diff options
author | Antoine Vigneau <antoine.vigneau@sonarsource.com> | 2024-01-18 16:58:34 +0100 |
---|---|---|
committer | sonartech <sonartech@sonarsource.com> | 2024-01-23 20:04:15 +0000 |
commit | c6027f911e0fc04d4b4164a3134766ae0b8f1e5c (patch) | |
tree | 87cefa6be96861a00da0cca8b39919f99e829617 /server/sonar-auth-gitlab/src/test/java/org | |
parent | 14f52af28bf687f58db699873470ea892bdfecc4 (diff) | |
download | sonarqube-c6027f911e0fc04d4b4164a3134766ae0b8f1e5c.tar.gz sonarqube-c6027f911e0fc04d4b4164a3134766ae0b8f1e5c.zip |
SONAR-21413 Use GitLab allowed groups to filter users authenticating
Diffstat (limited to 'server/sonar-auth-gitlab/src/test/java/org')
-rw-r--r-- | server/sonar-auth-gitlab/src/test/java/org/sonar/auth/gitlab/GitLabIdentityProviderTest.java | 2 | ||||
-rw-r--r-- | server/sonar-auth-gitlab/src/test/java/org/sonar/auth/gitlab/IntegrationTest.java | 201 |
2 files changed, 148 insertions, 55 deletions
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..3371b3188a1 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 @@ -85,7 +85,7 @@ 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&scope=read_user"); + verify(initContext).redirectTo("http://server/oauth/authorize?response_type=code&client_id=123&redirect_uri=http%3A%2F%2Fserver%2Fcallback&scope=api"); } @Test 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 65da50c2d0f..8f933d881ef 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 @@ -21,7 +21,6 @@ package org.sonar.auth.gitlab; import okhttp3.mockwebserver.MockResponse; import okhttp3.mockwebserver.MockWebServer; -import org.assertj.core.api.Assertions; import org.junit.Before; import org.junit.Rule; import org.junit.Test; @@ -29,13 +28,17 @@ import org.mockito.ArgumentCaptor; import org.mockito.Mockito; import org.sonar.api.config.internal.MapSettings; import org.sonar.api.server.authentication.OAuth2IdentityProvider; +import org.sonar.api.server.authentication.UnauthorizedException; import org.sonar.api.server.authentication.UserIdentity; import org.sonar.api.server.http.HttpRequest; import static java.lang.String.format; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import static org.sonar.auth.gitlab.GitLabSettings.GITLAB_AUTH_ALLOWED_GROUPS; import static org.sonar.auth.gitlab.GitLabSettings.GITLAB_AUTH_ALLOW_USERS_TO_SIGNUP; import static org.sonar.auth.gitlab.GitLabSettings.GITLAB_AUTH_APPLICATION_ID; import static org.sonar.auth.gitlab.GitLabSettings.GITLAB_AUTH_ENABLED; @@ -68,23 +71,17 @@ public class IntegrationTest { .setProperty(GITLAB_AUTH_ALLOW_USERS_TO_SIGNUP, "true") .setProperty(GITLAB_AUTH_URL, gitLabUrl) .setProperty(GITLAB_AUTH_APPLICATION_ID, "123") - .setProperty(GITLAB_AUTH_SECRET, "456"); + .setProperty(GITLAB_AUTH_SECRET, "456") + .setProperty(GITLAB_AUTH_ALLOWED_GROUPS, "group1,group2"); } @Test - public void authenticate_user() { - OAuth2IdentityProvider.CallbackContext callbackContext = Mockito.mock(OAuth2IdentityProvider.CallbackContext.class); - when(callbackContext.getCallbackUrl()).thenReturn("http://server/callback"); - - HttpRequest httpRequest = Mockito.mock(HttpRequest.class); - when(httpRequest.getParameter("code")).thenReturn(ANY_CODE_VALUE); - when(callbackContext.getHttpRequest()).thenReturn(httpRequest); + public void callback_whenAllowedUser_shouldAuthenticate() { + OAuth2IdentityProvider.CallbackContext callbackContext = mockCallbackContext(); - gitlab.enqueue(new MockResponse().setBody( - "{\n" + " \"access_token\": \"de6780bc506a0446309bd9362820ba8aed28aa506c71eedbe1c5c4f9dd350e54\",\n" + " \"token_type\": \"bearer\",\n" + " \"expires_in\": 7200,\n" - + " \"refresh_token\": \"8257e65c97202ed1726cf9571600918f3bffb2544b26e00a61df9897668c33a1\"\n" + "}")); - // response of /user - gitlab.enqueue(new MockResponse().setBody("{\"id\": 123, \"username\":\"toto\", \"name\":\"Toto Toto\",\"email\":\"toto@toto.com\"}")); + mockAccessTokenResponse(); + mockUserResponse(); + mockSingleGroupReponse("group1"); gitLabIdentityProvider.callback(callbackContext); @@ -99,22 +96,53 @@ public class IntegrationTest { } @Test - public void synchronize_groups() throws InterruptedException { - mapSettings.setProperty(GITLAB_AUTH_SYNC_USER_GROUPS, "true"); - OAuth2IdentityProvider.CallbackContext callbackContext = Mockito.mock(OAuth2IdentityProvider.CallbackContext.class); - when(callbackContext.getCallbackUrl()).thenReturn("http://server/callback"); + public void callback_whenNotAllowedUser_shouldThrow() { + OAuth2IdentityProvider.CallbackContext callbackContext = mockCallbackContext(); + + mockAccessTokenResponse(); + mockUserResponse(); + mockSingleGroupReponse("wrong-group"); + + assertThatThrownBy(() -> gitLabIdentityProvider.callback(callbackContext)) + .isInstanceOf((UnauthorizedException.class)) + .hasMessage("You are not allowed to authenticate"); + } + + @Test + public void callback_whenAllowedUserBySubgroupMembership_shouldAuthenticate() { + OAuth2IdentityProvider.CallbackContext callbackContext = mockCallbackContext(); + + mockAccessTokenResponse(); + mockUserResponse(); + mockSingleGroupReponse("group1/subgroup"); + + gitLabIdentityProvider.callback(callbackContext); + + verify(callbackContext).authenticate(any()); + verify(callbackContext).redirectToRequestedPage(); + } - HttpRequest httpRequest = Mockito.mock(HttpRequest.class); - when(httpRequest.getParameter("code")).thenReturn(ANY_CODE_VALUE); - when(callbackContext.getHttpRequest()).thenReturn(httpRequest); - gitlab.enqueue(new MockResponse().setBody( - "{\n" + " \"access_token\": \"de6780bc506a0446309bd9362820ba8aed28aa506c71eedbe1c5c4f9dd350e54\",\n" + " \"token_type\": \"bearer\",\n" + " \"expires_in\": 7200,\n" - + " \"refresh_token\": \"8257e65c97202ed1726cf9571600918f3bffb2544b26e00a61df9897668c33a1\"\n" + "}")); - // response of /user - gitlab.enqueue(new MockResponse().setBody("{\"id\": 123, \"username\": \"username\", \"name\": \"name\"}")); - // response of /groups - gitlab.enqueue(new MockResponse().setBody("[{\"full_path\": \"group1\"}, {\"full_path\": \"group2\"}]")); + @Test + public void callback_shouldSynchronizeGroups() throws InterruptedException { + mapSettings.setProperty(GITLAB_AUTH_SYNC_USER_GROUPS, "true"); + OAuth2IdentityProvider.CallbackContext callbackContext = mockCallbackContext(); + + mockAccessTokenResponse(); + mockUserResponse(); + // Response for /groups + gitlab.enqueue(new MockResponse().setBody(""" + [ + { + "id": 1, + "full_path": "group1" + }, + { + "id": 2, + "full_path": "group2" + } + ] + """)); gitLabIdentityProvider.callback(callbackContext); @@ -128,35 +156,60 @@ public class IntegrationTest { } @Test - public void synchronize_groups_on_many_pages() { + public void callback_whenMultiplePagesOfGroups_shouldSynchronizeAllGroups() { mapSettings.setProperty(GITLAB_AUTH_SYNC_USER_GROUPS, "true"); - OAuth2IdentityProvider.CallbackContext callbackContext = Mockito.mock(OAuth2IdentityProvider.CallbackContext.class); - when(callbackContext.getCallbackUrl()).thenReturn("http://server/callback"); - - HttpRequest httpRequest = Mockito.mock(HttpRequest.class); - when(httpRequest.getParameter("code")).thenReturn(ANY_CODE_VALUE); - when(callbackContext.getHttpRequest()).thenReturn(httpRequest); + OAuth2IdentityProvider.CallbackContext callbackContext = mockCallbackContext(); - gitlab.enqueue(new MockResponse().setBody( - "{\n" + " \"access_token\": \"de6780bc506a0446309bd9362820ba8aed28aa506c71eedbe1c5c4f9dd350e54\",\n" + " \"token_type\": \"bearer\",\n" + " \"expires_in\": 7200,\n" - + " \"refresh_token\": \"8257e65c97202ed1726cf9571600918f3bffb2544b26e00a61df9897668c33a1\"\n" + "}")); - // response of /user - gitlab.enqueue(new MockResponse().setBody("{\"id\": 123, \"username\": \"username\", \"name\": \"name\"}")); - // response of /groups, first page + mockAccessTokenResponse(); + mockUserResponse(); + // Response for /groups, first page gitlab.enqueue(new MockResponse() - .setBody("[{\"full_path\": \"group1\"}, {\"full_path\": \"group2\"}]") + .setBody(""" + [ + { + "id": 1, + "full_path": "group1" + }, + { + "id": 2, + "full_path": "group2" + } + ] + """) .setHeader("Link", format(" <%s/groups?per_page=100&page=2>; rel=\"next\"," + " <%s/groups?per_page=100&&page=3>; rel=\"last\"," + " <%s/groups?per_page=100&&page=1>; rel=\"first\"", gitLabUrl, gitLabUrl, gitLabUrl))); - // response of /groups, page 2 + // Response for /groups, page 2 gitlab.enqueue(new MockResponse() - .setBody("[{\"full_path\": \"group3\"}, {\"full_path\": \"group4\"}]") + .setBody(""" + [ + { + "id": 3, + "full_path": "group3" + }, + { + "id": 4, + "full_path": "group4" + } + ] + """) .setHeader("Link", format("<%s/groups?per_page=100&page=3>; rel=\"next\"," + " <%s/groups?per_page=100&&page=3>; rel=\"last\"," + " <%s/groups?per_page=100&&page=1>; rel=\"first\"", gitLabUrl, gitLabUrl, gitLabUrl))); - // response of /groups, page 3 + // Response for /groups, page 3 gitlab.enqueue(new MockResponse() - .setBody("[{\"full_path\": \"group5\"}, {\"full_path\": \"group6\"}]") + .setBody(""" + [ + { + "id": 5, + "full_path": "group5" + }, + { + "id": 6, + "full_path": "group6" + } + ] + """) .setHeader("Link", format("<%s/groups?per_page=100&&page=3>; rel=\"last\"," + " <%s/groups?per_page=100&&page=1>; rel=\"first\"", gitLabUrl, gitLabUrl))); @@ -169,22 +222,62 @@ public class IntegrationTest { } @Test - public void fail_to_authenticate() { + public void callback_whenNoUser_shouldThrow() { + OAuth2IdentityProvider.CallbackContext callbackContext = mockCallbackContext(); + + mockAccessTokenResponse(); + // Response for /user + gitlab.enqueue(new MockResponse().setResponseCode(404).setBody("empty")); + + assertThatThrownBy(() -> gitLabIdentityProvider.callback(callbackContext)) + .hasMessage("Fail to execute request '" + gitLabSettings.url() + "/api/v4/user'. HTTP code: 404, response: empty") + .isInstanceOf((IllegalStateException.class)); + } + + private static OAuth2IdentityProvider.CallbackContext mockCallbackContext() { OAuth2IdentityProvider.CallbackContext callbackContext = Mockito.mock(OAuth2IdentityProvider.CallbackContext.class); when(callbackContext.getCallbackUrl()).thenReturn("http://server/callback"); HttpRequest httpRequest = Mockito.mock(HttpRequest.class); when(httpRequest.getParameter("code")).thenReturn(ANY_CODE_VALUE); when(callbackContext.getHttpRequest()).thenReturn(httpRequest); + return callbackContext; + } - gitlab.enqueue(new MockResponse().setBody( - "{\n" + " \"access_token\": \"de6780bc506a0446309bd9362820ba8aed28aa506c71eedbe1c5c4f9dd350e54\",\n" + " \"token_type\": \"bearer\",\n" + " \"expires_in\": 7200,\n" - + " \"refresh_token\": \"8257e65c97202ed1726cf9571600918f3bffb2544b26e00a61df9897668c33a1\"\n" + "}")); - gitlab.enqueue(new MockResponse().setResponseCode(404).setBody("empty")); + private void mockAccessTokenResponse() { + // Response for OAuth access token + gitlab.enqueue(new MockResponse().setBody(""" + { + "access_token": "de6780bc506a0446309bd9362820ba8aed28aa506c71eedbe1c5c4f9dd350e54", + "token_type": "bearer", + "expires_in": 7200, + "refresh_token": "8257e65c97202ed1726cf9571600918f3bffb2544b26e00a61df9897668c33a1" + } + """)); + } - Assertions.assertThatThrownBy(() -> gitLabIdentityProvider.callback(callbackContext)) - .hasMessage("Fail to execute request '" + gitLabSettings.url() + "/api/v4/user'. HTTP code: 404, response: empty") - .isInstanceOf((IllegalStateException.class)); + private void mockUserResponse() { + // Response for /user + gitlab.enqueue(new MockResponse().setBody(""" + { + "id": 123, + "username": "toto", + "name": "Toto Toto", + "email": "toto@toto.com" + } + """)); + } + + private void mockSingleGroupReponse(String group) { + // Response for /groups + gitlab.enqueue(new MockResponse().setBody(""" + [ + { + "id": 1, + "full_path": "%s" + } + ] + """.formatted(group))); } } |