@@ -20,6 +20,7 @@ | |||
package org.sonar.auth.gitlab; | |||
import com.github.scribejava.core.builder.ServiceBuilder; | |||
import com.github.scribejava.core.builder.ServiceBuilderOAuth20; | |||
import com.github.scribejava.core.model.OAuth2AccessToken; | |||
import com.github.scribejava.core.model.OAuthConstants; | |||
import com.github.scribejava.core.oauth.OAuth20Service; | |||
@@ -39,6 +40,8 @@ import static java.util.stream.Collectors.toSet; | |||
public class GitLabIdentityProvider implements OAuth2IdentityProvider { | |||
public static final String API_SCOPE = "api"; | |||
public static final String READ_USER_SCOPE = "read_user"; | |||
private final GitLabSettings gitLabSettings; | |||
private final ScribeGitLabOauth2Api scribeApi; | |||
private final GitLabRestClient gitLabRestClient; | |||
@@ -80,15 +83,16 @@ public class GitLabIdentityProvider implements OAuth2IdentityProvider { | |||
@Override | |||
public void init(InitContext context) { | |||
String state = context.generateCsrfState(); | |||
OAuth20Service scribe = newScribeBuilder(context).build(scribeApi); | |||
OAuth20Service scribe = newScribeBuilder(context, gitLabSettings.syncUserGroups()).build(scribeApi); | |||
String url = scribe.getAuthorizationUrl(state); | |||
context.redirectTo(url); | |||
} | |||
private ServiceBuilder newScribeBuilder(OAuth2Context context) { | |||
private ServiceBuilderOAuth20 newScribeBuilder(OAuth2Context context, boolean syncUserGroups) { | |||
checkState(isEnabled(), "GitLab authentication is disabled"); | |||
return new ServiceBuilder(gitLabSettings.applicationId()) | |||
.apiSecret(gitLabSettings.secret()) | |||
.defaultScope(syncUserGroups ? API_SCOPE : READ_USER_SCOPE) | |||
.callback(context.getCallbackUrl()); | |||
} | |||
@@ -106,7 +110,7 @@ public class GitLabIdentityProvider implements OAuth2IdentityProvider { | |||
private void onCallback(CallbackContext context) throws InterruptedException, ExecutionException, IOException { | |||
HttpServletRequest request = context.getRequest(); | |||
OAuth20Service scribe = newScribeBuilder(context).build(scribeApi); | |||
OAuth20Service scribe = newScribeBuilder(context, gitLabSettings.syncUserGroups()).build(scribeApi); | |||
String code = request.getParameter(OAuthConstants.CODE); | |||
OAuth2AccessToken accessToken = scribe.getAccessToken(code); | |||
@@ -120,7 +120,7 @@ public class GitLabSettings { | |||
PropertyDefinition.builder(GITLAB_AUTH_SYNC_USER_GROUPS) | |||
.deprecatedKey("sonar.auth.gitlab.sync_user_groups") | |||
.name("Synchronize user groups") | |||
.description("For each GitLab group he belongs to, the user will be associated to a group with the same name (if it exists) in SonarQube.") | |||
.description("For each GitLab group he belongs to, the user will be associated to a group with the same name (if it exists) in SonarQube. If enabled, the GitLab Oauth2 application will need to provide the api scope") | |||
.category(CATEGORY) | |||
.subCategory(SUBCATEGORY) | |||
.type(PropertyType.BOOLEAN) |
@@ -60,6 +60,7 @@ public class GitLabIdentityProviderTest { | |||
when(gitLabSettings.applicationId()).thenReturn("123"); | |||
when(gitLabSettings.secret()).thenReturn("456"); | |||
when(gitLabSettings.url()).thenReturn("http://server"); | |||
when(gitLabSettings.syncUserGroups()).thenReturn(true); | |||
GitLabIdentityProvider gitLabIdentityProvider = new GitLabIdentityProvider(gitLabSettings, new GitLabRestClient(gitLabSettings), | |||
new ScribeGitLabOauth2Api(gitLabSettings)); | |||
@@ -68,7 +69,27 @@ public class GitLabIdentityProviderTest { | |||
gitLabIdentityProvider.init(initContext); | |||
verify(initContext).redirectTo("http://server/oauth/authorize?response_type=code&client_id=123&redirect_uri=http%3A%2F%2Fserver%2Fcallback"); | |||
verify(initContext).redirectTo("http://server/oauth/authorize?response_type=code&client_id=123&redirect_uri=http%3A%2F%2Fserver%2Fcallback&scope=api"); | |||
} | |||
@Test | |||
public void test_init_without_sync() { | |||
GitLabSettings gitLabSettings = mock(GitLabSettings.class); | |||
when(gitLabSettings.isEnabled()).thenReturn(true); | |||
when(gitLabSettings.allowUsersToSignUp()).thenReturn(true); | |||
when(gitLabSettings.applicationId()).thenReturn("123"); | |||
when(gitLabSettings.secret()).thenReturn("456"); | |||
when(gitLabSettings.url()).thenReturn("http://server"); | |||
when(gitLabSettings.syncUserGroups()).thenReturn(false); | |||
GitLabIdentityProvider gitLabIdentityProvider = new GitLabIdentityProvider(gitLabSettings, new GitLabRestClient(gitLabSettings), | |||
new ScribeGitLabOauth2Api(gitLabSettings)); | |||
OAuth2IdentityProvider.InitContext initContext = mock(OAuth2IdentityProvider.InitContext.class); | |||
when(initContext.getCallbackUrl()).thenReturn("http://server/callback"); | |||
gitLabIdentityProvider.init(initContext); | |||
verify(initContext).redirectTo("http://server/oauth/authorize?response_type=code&client_id=123&redirect_uri=http%3A%2F%2Fserver%2Fcallback&scope=read_user"); | |||
} | |||
@Test |
@@ -60,7 +60,7 @@ Create a GitLab OAuth application from your GitLab account. Click [here](https:/ | |||
1. In the **Name** text box, name your app SonarQube. | |||
1. In the **Redirect URI** text box, enter your SonarQube URL with the path `/oauth2/callback/gitlab`. For example, `https://sonarqube.mycompany.com/oauth2/callback/gitlab`. | |||
1. Under **Scopes**, select **api**. | |||
1. Under **Scopes**, select **api**. If you want to authenticate without group synchronization, you need to select **read_user**. | |||
After saving your application, GitLab gives you your **Application ID** and **Secret**. Keep these at hand, open your SonarQube instance, and navigate to **[Administration > Configuration > General Settings > Security](/#sonarqube-admin#/admin/settings?category=security/)** to finish setting up GitLab authentication: | |||