aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAurelien Poscia <aurelien.poscia@sonarsource.com>2024-04-16 13:56:10 +0200
committersonartech <sonartech@sonarsource.com>2024-04-22 20:02:38 +0000
commitd42e73cd8ae1c41f60c828375561e9767d941570 (patch)
treef5070a556b0de45b19f0c35cc8f32ffcbb78687b
parent3a0102ec7c2bcfaf9fa9859e66cd2ef8a94dfd08 (diff)
downloadsonarqube-d42e73cd8ae1c41f60c828375561e9767d941570.tar.gz
sonarqube-d42e73cd8ae1c41f60c828375561e9767d941570.zip
SONAR-22088 Fix GitLab auth when group sync is disabledcopy_of_master
-rw-r--r--server/sonar-auth-gitlab/build.gradle1
-rw-r--r--server/sonar-auth-gitlab/src/main/java/org/sonar/auth/gitlab/GitLabIdentityProvider.java70
-rw-r--r--server/sonar-auth-gitlab/src/test/java/org/sonar/auth/gitlab/GitLabIdentityProviderTest.java246
-rw-r--r--server/sonar-auth-gitlab/src/test/java/org/sonar/auth/gitlab/IntegrationTest.java20
-rw-r--r--sonar-core/src/main/resources/org/sonar/l10n/core.properties2
5 files changed, 267 insertions, 72 deletions
diff --git a/server/sonar-auth-gitlab/build.gradle b/server/sonar-auth-gitlab/build.gradle
index 26b522bafa8..9a0574fd46e 100644
--- a/server/sonar-auth-gitlab/build.gradle
+++ b/server/sonar-auth-gitlab/build.gradle
@@ -21,6 +21,7 @@ dependencies {
testImplementation 'com.squareup.okhttp3:mockwebserver'
testImplementation 'com.squareup.okhttp3:okhttp'
testImplementation 'junit:junit'
+ testImplementation 'com.tngtech.java:junit-dataprovider'
testImplementation 'org.assertj:assertj-core'
testImplementation 'org.mockito:mockito-core'
}
diff --git a/server/sonar-auth-gitlab/src/main/java/org/sonar/auth/gitlab/GitLabIdentityProvider.java b/server/sonar-auth-gitlab/src/main/java/org/sonar/auth/gitlab/GitLabIdentityProvider.java
index 1ed3db4beca..4478d48b30f 100644
--- a/server/sonar-auth-gitlab/src/main/java/org/sonar/auth/gitlab/GitLabIdentityProvider.java
+++ b/server/sonar-auth-gitlab/src/main/java/org/sonar/auth/gitlab/GitLabIdentityProvider.java
@@ -20,16 +20,17 @@
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;
+import com.google.common.annotations.VisibleForTesting;
import java.io.IOException;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ExecutionException;
import java.util.stream.Stream;
+import javax.inject.Inject;
import org.sonar.api.server.authentication.Display;
import org.sonar.api.server.authentication.OAuth2IdentityProvider;
import org.sonar.api.server.authentication.UnauthorizedException;
@@ -41,17 +42,24 @@ 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";
public static final String KEY = "gitlab";
private final GitLabSettings gitLabSettings;
private final ScribeGitLabOauth2Api scribeApi;
private final GitLabRestClient gitLabRestClient;
+ private final ScribeFactory scribeFactory;
+ @Inject
public GitLabIdentityProvider(GitLabSettings gitLabSettings, GitLabRestClient gitLabRestClient, ScribeGitLabOauth2Api scribeApi) {
+ this(gitLabSettings, gitLabRestClient, scribeApi, new ScribeFactory());
+ }
+
+ @VisibleForTesting
+ GitLabIdentityProvider(GitLabSettings gitLabSettings, GitLabRestClient gitLabRestClient, ScribeGitLabOauth2Api scribeApi,
+ ScribeFactory scribeFactory) {
this.gitLabSettings = gitLabSettings;
this.scribeApi = scribeApi;
this.gitLabRestClient = gitLabRestClient;
+ this.scribeFactory = scribeFactory;
}
@Override
@@ -85,23 +93,18 @@ public class GitLabIdentityProvider implements OAuth2IdentityProvider {
@Override
public void init(InitContext context) {
String state = context.generateCsrfState();
- OAuth20Service scribe = newScribeBuilder(context).build(scribeApi);
- String url = scribe.getAuthorizationUrl(state);
- context.redirectTo(url);
- }
-
- private ServiceBuilderOAuth20 newScribeBuilder(OAuth2Context context) {
- checkState(isEnabled(), "GitLab authentication is disabled");
- return new ServiceBuilder(gitLabSettings.applicationId())
- .apiSecret(gitLabSettings.secret())
- .defaultScope(gitLabSettings.syncUserGroups() ? API_SCOPE : READ_USER_SCOPE)
- .callback(context.getCallbackUrl());
+ try (OAuth20Service scribe = scribeFactory.newScribe(gitLabSettings, context.getCallbackUrl(), scribeApi)) {
+ String url = scribe.getAuthorizationUrl(state);
+ context.redirectTo(url);
+ } catch (IOException e) {
+ throw new IllegalStateException(e);
+ }
}
@Override
public void callback(CallbackContext context) {
- try {
- onCallback(context);
+ try (OAuth20Service scribe = scribeFactory.newScribe(gitLabSettings, context.getCallbackUrl(), scribeApi)) {
+ onCallback(context, scribe);
} catch (IOException | ExecutionException e) {
throw new IllegalStateException(e);
} catch (InterruptedException e) {
@@ -110,12 +113,10 @@ public class GitLabIdentityProvider implements OAuth2IdentityProvider {
}
}
- private void onCallback(CallbackContext context) throws InterruptedException, ExecutionException, IOException {
+ private void onCallback(CallbackContext context, OAuth20Service scribe) throws InterruptedException, ExecutionException, IOException {
HttpRequest request = context.getHttpRequest();
- OAuth20Service scribe = newScribeBuilder(context).build(scribeApi);
String code = request.getParameter(OAuthConstants.CODE);
OAuth2AccessToken accessToken = scribe.getAccessToken(code);
-
GsonUser user = gitLabRestClient.getUser(scribe, accessToken);
UserIdentity.Builder builder = UserIdentity.builder()
@@ -124,22 +125,20 @@ public class GitLabIdentityProvider implements OAuth2IdentityProvider {
.setName(user.getName())
.setEmail(user.getEmail());
-
- Set<String> userGroups = getGroups(scribe, accessToken);
-
- if (!gitLabSettings.allowedGroups().isEmpty()) {
- validateUserInAllowedGroups(userGroups, gitLabSettings.allowedGroups());
- }
-
if (gitLabSettings.syncUserGroups()) {
+ Set<String> userGroups = getGroups(scribe, accessToken);
+ validateUserInAllowedGroups(userGroups, gitLabSettings.allowedGroups());
builder.setGroups(userGroups);
}
-
context.authenticate(builder.build());
context.redirectToRequestedPage();
}
- private static void validateUserInAllowedGroups(Set<String> userGroups, Set<String> allowedGroups) {
+ private void validateUserInAllowedGroups(Set<String> userGroups, Set<String> allowedGroups) {
+ if (gitLabSettings.allowedGroups().isEmpty()) {
+ return;
+ }
+
boolean allowedUser = userGroups.stream()
.anyMatch(userGroup -> isAllowedGroup(userGroup, allowedGroups));
@@ -160,4 +159,19 @@ public class GitLabIdentityProvider implements OAuth2IdentityProvider {
.collect(toSet());
}
+ static class ScribeFactory {
+
+ private static final String API_SCOPE = "api";
+ private static final String READ_USER_SCOPE = "read_user";
+
+ OAuth20Service newScribe(GitLabSettings gitLabSettings, String callbackUrl, ScribeGitLabOauth2Api scribeApi) {
+ checkState(gitLabSettings.isEnabled(), "GitLab authentication is disabled");
+ return new ServiceBuilder(gitLabSettings.applicationId())
+ .apiSecret(gitLabSettings.secret())
+ .defaultScope(gitLabSettings.syncUserGroups() ? API_SCOPE : READ_USER_SCOPE)
+ .callback(callbackUrl)
+ .build(scribeApi);
+ }
+ }
+
}
diff --git a/server/sonar-auth-gitlab/src/test/java/org/sonar/auth/gitlab/GitLabIdentityProviderTest.java b/server/sonar-auth-gitlab/src/test/java/org/sonar/auth/gitlab/GitLabIdentityProviderTest.java
index 49399eb64e7..e8316171d97 100644
--- a/server/sonar-auth-gitlab/src/test/java/org/sonar/auth/gitlab/GitLabIdentityProviderTest.java
+++ b/server/sonar-auth-gitlab/src/test/java/org/sonar/auth/gitlab/GitLabIdentityProviderTest.java
@@ -19,25 +19,85 @@
*/
package org.sonar.auth.gitlab;
-import org.assertj.core.api.Assertions;
+import com.github.scribejava.core.model.OAuth2AccessToken;
+import com.github.scribejava.core.model.OAuthConstants;
+import com.github.scribejava.core.oauth.OAuth20Service;
+import com.tngtech.java.junit.dataprovider.DataProvider;
+import com.tngtech.java.junit.dataprovider.DataProviderRunner;
+import com.tngtech.java.junit.dataprovider.UseDataProvider;
+import java.io.IOException;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.ExecutionException;
+import org.junit.Before;
import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Answers;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
import org.sonar.api.server.authentication.Display;
import org.sonar.api.server.authentication.OAuth2IdentityProvider;
+import org.sonar.api.server.authentication.UnauthorizedException;
+import org.sonar.api.server.authentication.UserIdentity;
+import static java.util.stream.Collectors.toSet;
import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
+import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
+import static org.mockito.Mockito.any;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import static org.mockito.MockitoAnnotations.openMocks;
+@RunWith(DataProviderRunner.class)
public class GitLabIdentityProviderTest {
+ private static final String OAUTH_CODE = "code fdsojfsjodfg";
+ private static final String AUTHORIZATION_URL = "AUTHORIZATION_URL";
+ private static final String CALLBACK_URL = "CALLBACK_URL";
+ private static final String STATE = "State request";
+
+ @Mock
+ private GitLabRestClient gitLabRestClient;
+ @Mock
+ private GitLabSettings gitLabSettings;
+ @Mock(answer = Answers.RETURNS_DEEP_STUBS)
+ private GitLabIdentityProvider.ScribeFactory scribeFactory;
+ @Mock
+ private OAuth2IdentityProvider.InitContext initContext;
+ @Mock(answer = Answers.RETURNS_DEEP_STUBS)
+ private OAuth2IdentityProvider.CallbackContext callbackContext;
+ @Mock
+ private OAuth20Service scribe;
+ @Mock
+ private ScribeGitLabOauth2Api scribeApi;
+ @Mock
+ private OAuth2AccessToken accessToken;
+
+ private GitLabIdentityProvider gitLabIdentityProvider;
+
+ @Before
+ public void setup() throws IOException, ExecutionException, InterruptedException {
+ openMocks(this);
+ gitLabIdentityProvider = new GitLabIdentityProvider(gitLabSettings, gitLabRestClient, scribeApi, scribeFactory);
+
+ when(initContext.generateCsrfState()).thenReturn(STATE);
+ when(initContext.getCallbackUrl()).thenReturn(CALLBACK_URL);
+
+ when(callbackContext.getCallbackUrl()).thenReturn(CALLBACK_URL);
+ when(callbackContext.getHttpRequest().getParameter(OAuthConstants.CODE)).thenReturn(OAUTH_CODE);
+
+ when(scribeFactory.newScribe(gitLabSettings, CALLBACK_URL, scribeApi)).thenReturn(scribe);
+ when(scribe.getAccessToken(OAUTH_CODE)).thenReturn(accessToken);
+ when(scribe.getAuthorizationUrl(STATE)).thenReturn(AUTHORIZATION_URL);
+ }
+
@Test
public void test_identity_provider() {
- GitLabSettings gitLabSettings = mock(GitLabSettings.class);
when(gitLabSettings.isEnabled()).thenReturn(true);
when(gitLabSettings.allowUsersToSignUp()).thenReturn(true);
- GitLabIdentityProvider gitLabIdentityProvider = new GitLabIdentityProvider(gitLabSettings, new GitLabRestClient(gitLabSettings),
- new ScribeGitLabOauth2Api(gitLabSettings));
assertThat(gitLabIdentityProvider.getKey()).isEqualTo("gitlab");
assertThat(gitLabIdentityProvider.getName()).isEqualTo("GitLab");
@@ -49,61 +109,165 @@ public class GitLabIdentityProviderTest {
}
@Test
- public void test_init() {
- 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(true);
- GitLabIdentityProvider gitLabIdentityProvider = new GitLabIdentityProvider(gitLabSettings, new GitLabRestClient(gitLabSettings),
- new ScribeGitLabOauth2Api(gitLabSettings));
+ public void init_whenSuccessful_redirectsToUrl() {
+ gitLabIdentityProvider.init(initContext);
+
+ verify(initContext).generateCsrfState();
+ verify(initContext).redirectTo(AUTHORIZATION_URL);
+ }
+
+ @Test
+ public void init_whenErrorWhileBuildingScribe_shouldReThrow() {
+ IllegalStateException exception = new IllegalStateException("GitLab authentication is disabled");
+ when(scribeFactory.newScribe(any(), any(), any())).thenThrow(exception);
OAuth2IdentityProvider.InitContext initContext = mock(OAuth2IdentityProvider.InitContext.class);
when(initContext.getCallbackUrl()).thenReturn("http://server/callback");
- gitLabIdentityProvider.init(initContext);
+ assertThatIllegalStateException()
+ .isThrownBy(() -> gitLabIdentityProvider.init(initContext))
+ .isEqualTo(exception);
+ }
+
+ @Test
+ public void onCallback_withGroupSyncDisabledAndNoAllowedGroups_redirectsToRequestedPage() {
+ GsonUser gsonUser = mockGsonUser();
+
+ gitLabIdentityProvider.callback(callbackContext);
- verify(initContext).redirectTo("http://server/oauth/authorize?response_type=code&client_id=123&redirect_uri=http%3A%2F%2Fserver%2Fcallback&scope=api");
+ verifyAuthenticateIsCalledWithExpectedIdentity(callbackContext, gsonUser, Set.of());
+ verify(callbackContext).redirectToRequestedPage();
+ verify(gitLabRestClient, never()).getGroups(any(), any());
}
@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");
+ public void onCallback_withGroupSyncDisabledAndAllowedGroups_redirectsToRequestedPage() {
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");
+ GsonUser gsonUser = mockGsonUser();
- gitLabIdentityProvider.init(initContext);
+ gitLabIdentityProvider.callback(callbackContext);
- verify(initContext).redirectTo("http://server/oauth/authorize?response_type=code&client_id=123&redirect_uri=http%3A%2F%2Fserver%2Fcallback&scope=read_user");
+ verifyAuthenticateIsCalledWithExpectedIdentity(callbackContext, gsonUser, Set.of());
+ verify(callbackContext).redirectToRequestedPage();
+ verify(gitLabRestClient, never()).getGroups(any(), any());
}
@Test
- public void fail_to_init() {
- GitLabSettings gitLabSettings = mock(GitLabSettings.class);
+ @UseDataProvider("allowedGroups")
+ public void onCallback_withGroupSyncAndAllowedGroupsMatching_redirectsToRequestedPage(Set<String> allowedGroups) {
+ when(gitLabSettings.syncUserGroups()).thenReturn(true);
+ when(gitLabSettings.allowedGroups()).thenReturn(allowedGroups);
+
+ GsonUser gsonUser = mockGsonUser();
+ Set<GsonGroup> gsonGroups = mockGitlabGroups();
+
+ gitLabIdentityProvider.callback(callbackContext);
+
+ verifyAuthenticateIsCalledWithExpectedIdentity(callbackContext, gsonUser, gsonGroups);
+ verify(callbackContext).redirectToRequestedPage();
+ }
+
+ @DataProvider
+ public static Object[][] allowedGroups() {
+ return new Object[][]{
+ {Set.of()},
+ {Set.of("path")}
+ };
+ }
+
+ @Test
+ public void onCallback_withGroupSyncAndAllowedGroupsNotMatching_shouldThrow() {
+ when(gitLabSettings.syncUserGroups()).thenReturn(true);
+ when(gitLabSettings.allowedGroups()).thenReturn(Set.of("path2"));
+
+ mockGsonUser();
+ mockGitlabGroups();
+
+ assertThatExceptionOfType(UnauthorizedException.class)
+ .isThrownBy(() -> gitLabIdentityProvider.callback(callbackContext))
+ .withMessage("You are not allowed to authenticate");
+ }
+
+ @Test
+ public void onCallback_ifScribeFactoryFails_shouldThrow() {
+ IllegalStateException exception = new IllegalStateException("message");
+ when(scribeFactory.newScribe(any(), any(), any())).thenThrow(exception);
+
+ assertThatIllegalStateException()
+ .isThrownBy(() -> gitLabIdentityProvider.callback(callbackContext))
+ .isEqualTo(exception);
+ }
+
+ private Set<GsonGroup> mockGitlabGroups() {
+ GsonGroup gsonGroup = mock(GsonGroup.class);
+ when(gsonGroup.getFullPath()).thenReturn("path/to/group");
+ GsonGroup gsonGroup2 = mock(GsonGroup.class);
+ when(gsonGroup2.getFullPath()).thenReturn("path/to/group2");
+ when(gitLabRestClient.getGroups(scribe, accessToken)).thenReturn(List.of(gsonGroup, gsonGroup2));
+ return Set.of(gsonGroup, gsonGroup2);
+ }
+
+ private static void verifyAuthenticateIsCalledWithExpectedIdentity(OAuth2IdentityProvider.CallbackContext callbackContext,
+ GsonUser gsonUser, Set<GsonGroup> gsonGroups) {
+ ArgumentCaptor<UserIdentity> userIdentityCaptor = ArgumentCaptor.forClass(UserIdentity.class);
+ verify(callbackContext).authenticate(userIdentityCaptor.capture());
+
+ UserIdentity actualIdentity = userIdentityCaptor.getValue();
+
+ assertThat(actualIdentity.getProviderId()).asLong().isEqualTo(gsonUser.getId());
+ assertThat(actualIdentity.getProviderLogin()).isEqualTo(gsonUser.getUsername());
+ assertThat(actualIdentity.getName()).isEqualTo(gsonUser.getName());
+ assertThat(actualIdentity.getEmail()).isEqualTo(gsonUser.getEmail());
+ assertThat(actualIdentity.getGroups()).isEqualTo(gsonGroups.stream().map(GsonGroup::getFullPath).collect(toSet()));
+ }
+
+ private GsonUser mockGsonUser() {
+ GsonUser gsonUser = mock();
+ when(gsonUser.getId()).thenReturn(432423L);
+ when(gsonUser.getUsername()).thenReturn("userName");
+ when(gsonUser.getName()).thenReturn("name");
+ when(gsonUser.getEmail()).thenReturn("toto@gitlab.com");
+ when(gitLabRestClient.getUser(scribe, accessToken)).thenReturn(gsonUser);
+ return gsonUser;
+ }
+
+ @Test
+ public void newScribe_whenGitLabAuthIsDisabled_throws() {
when(gitLabSettings.isEnabled()).thenReturn(false);
- when(gitLabSettings.allowUsersToSignUp()).thenReturn(true);
- when(gitLabSettings.applicationId()).thenReturn("123");
- when(gitLabSettings.secret()).thenReturn("456");
- when(gitLabSettings.url()).thenReturn("http://server");
- GitLabIdentityProvider gitLabIdentityProvider = new GitLabIdentityProvider(gitLabSettings, new GitLabRestClient(gitLabSettings),
+
+ assertThatIllegalStateException()
+ .isThrownBy(() -> new GitLabIdentityProvider.ScribeFactory().newScribe(gitLabSettings, CALLBACK_URL, new ScribeGitLabOauth2Api(gitLabSettings)))
+ .withMessage("GitLab authentication is disabled");
+ }
+
+ @Test
+ @UseDataProvider("groupsSyncToScope")
+ public void newScribe_whenGitLabSettingsValid_shouldUseCorrectScopeDependingOnGroupSync(boolean groupSyncEnabled, String expectedScope) {
+ setupGitlabSettingsWithGroupSync(groupSyncEnabled);
+
+
+ OAuth20Service realScribe = new GitLabIdentityProvider.ScribeFactory().newScribe(gitLabSettings, CALLBACK_URL,
new ScribeGitLabOauth2Api(gitLabSettings));
- OAuth2IdentityProvider.InitContext initContext = mock(OAuth2IdentityProvider.InitContext.class);
- when(initContext.getCallbackUrl()).thenReturn("http://server/callback");
+ assertThat(realScribe).isNotNull();
+ assertThat(realScribe.getCallback()).isEqualTo(CALLBACK_URL);
+ assertThat(realScribe.getApiSecret()).isEqualTo(gitLabSettings.secret());
+ assertThat(realScribe.getDefaultScope()).isEqualTo(expectedScope);
+ }
- Assertions.assertThatThrownBy(() -> gitLabIdentityProvider.init(initContext))
- .hasMessage("GitLab authentication is disabled")
- .isInstanceOf(IllegalStateException.class);
+ @DataProvider
+ public static Object[][] groupsSyncToScope() {
+ return new Object[][]{
+ {false, "read_user"},
+ {true, "api"}
+ };
+ }
+
+ private void setupGitlabSettingsWithGroupSync(boolean enableGroupSync) {
+ when(gitLabSettings.isEnabled()).thenReturn(true);
+ when(gitLabSettings.applicationId()).thenReturn("123");
+ when(gitLabSettings.secret()).thenReturn("456");
+ when(gitLabSettings.syncUserGroups()).thenReturn(enableGroupSync);
}
}
diff --git a/server/sonar-auth-gitlab/src/test/java/org/sonar/auth/gitlab/IntegrationTest.java b/server/sonar-auth-gitlab/src/test/java/org/sonar/auth/gitlab/IntegrationTest.java
index 8f933d881ef..7446ea83523 100644
--- a/server/sonar-auth-gitlab/src/test/java/org/sonar/auth/gitlab/IntegrationTest.java
+++ b/server/sonar-auth-gitlab/src/test/java/org/sonar/auth/gitlab/IntegrationTest.java
@@ -72,7 +72,8 @@ public class IntegrationTest {
.setProperty(GITLAB_AUTH_URL, gitLabUrl)
.setProperty(GITLAB_AUTH_APPLICATION_ID, "123")
.setProperty(GITLAB_AUTH_SECRET, "456")
- .setProperty(GITLAB_AUTH_ALLOWED_GROUPS, "group1,group2");
+ .setProperty(GITLAB_AUTH_ALLOWED_GROUPS, "group1,group2")
+ .setProperty(GITLAB_AUTH_SYNC_USER_GROUPS, "true");
}
@Test
@@ -96,7 +97,7 @@ public class IntegrationTest {
}
@Test
- public void callback_whenNotAllowedUser_shouldThrow() {
+ public void callback_whenGroupNotAllowedAndGroupSyncEnabled_shouldThrow() {
OAuth2IdentityProvider.CallbackContext callbackContext = mockCallbackContext();
mockAccessTokenResponse();
@@ -109,6 +110,21 @@ public class IntegrationTest {
}
@Test
+ public void callback_whenGroupNotAllowedAndGroupSyncDisabled_shouldThrow() {
+ mapSettings.setProperty(GITLAB_AUTH_SYNC_USER_GROUPS, "false");
+ OAuth2IdentityProvider.CallbackContext callbackContext = mockCallbackContext();
+
+ mockAccessTokenResponse();
+ mockUserResponse();
+ mockSingleGroupReponse("wrong-group");
+
+ gitLabIdentityProvider.callback(callbackContext);
+
+ verify(callbackContext).authenticate(any());
+ verify(callbackContext).redirectToRequestedPage();
+ }
+
+ @Test
public void callback_whenAllowedUserBySubgroupMembership_shouldAuthenticate() {
OAuth2IdentityProvider.CallbackContext callbackContext = mockCallbackContext();
diff --git a/sonar-core/src/main/resources/org/sonar/l10n/core.properties b/sonar-core/src/main/resources/org/sonar/l10n/core.properties
index 0cedde212a9..a09e67795bc 100644
--- a/sonar-core/src/main/resources/org/sonar/l10n/core.properties
+++ b/sonar-core/src/main/resources/org/sonar/l10n/core.properties
@@ -1598,7 +1598,7 @@ settings.authentication.gitlab.form.secret.description=Secret provided by GitLab
settings.authentication.gitlab.form.synchronizeGroups.name=Synchronize user groups
settings.authentication.gitlab.form.synchronizeGroups.description=For each GitLab group they belong to, the user will be associated to a group with the same name (if it exists) in SonarQube. If enabled, the GitLab OAuth 2 application will need to provide the api scope.
settings.authentication.gitlab.form.allowedGroups.name=Allowed groups
-settings.authentication.gitlab.form.allowedGroups.description.JIT=Only members of these groups (and sub-groups) will be allowed to authenticate. Please enter the group slug as it appears in the GitLab URL, for instance `my-gitlab-group`. ⚠︎ if not set and `Allow users to sign up` is enabled, any user from GitLab will be able to login to this SonarQube instance.
+settings.authentication.gitlab.form.allowedGroups.description.JIT=Only members of these groups (and sub-groups) will be allowed to authenticate. Enter the group slug as it appears in the GitLab URL, for instance `my-gitlab-group`. ⚠︎ When you turn on `Allow users to sign up`, make sure to also turn on group synchronization and provide a list of allowed groups. Otherwise, any GitLab user will be able to log in to this SonarQube instance.
settings.authentication.gitlab.form.allowedGroups.description.AUTO_PROVISIONING=Only members of these groups (and sub-groups) will be provisioned. Please enter the group slug as it appears in the GitLab URL, for instance `my-gitlab-group`.
settings.authentication.gitlab.form.allowUsersToSignUp.name=Allow users to sign up
settings.authentication.gitlab.form.allowUsersToSignUp.description=Allow new users to authenticate. When set to disabled, only existing users will be able to authenticate to the server.