| package de.ids_mannheim.korap.web.controller.oauth2; |
| |
| import static org.junit.jupiter.api.Assertions.assertEquals; |
| import static org.junit.jupiter.api.Assertions.assertNotNull; |
| import static org.junit.jupiter.api.Assertions.assertTrue; |
| |
| import java.io.IOException; |
| |
| import org.junit.jupiter.api.Test; |
| |
| import com.fasterxml.jackson.databind.JsonNode; |
| |
| import de.ids_mannheim.korap.authentication.http.HttpAuthorizationHandler; |
| import de.ids_mannheim.korap.config.Attributes; |
| import de.ids_mannheim.korap.constant.OAuth2Scope; |
| import de.ids_mannheim.korap.constant.TokenType; |
| import de.ids_mannheim.korap.exceptions.KustvaktException; |
| import de.ids_mannheim.korap.exceptions.StatusCodes; |
| import de.ids_mannheim.korap.utils.JsonUtils; |
| import de.ids_mannheim.korap.web.controller.vc.VirtualCorpusTestBase; |
| import jakarta.ws.rs.core.Response; |
| import jakarta.ws.rs.core.Response.Status; |
| |
| public class OAuth2AccessTokenTest extends VirtualCorpusTestBase { |
| |
| private String userAuthHeader; |
| |
| private String clientAuthHeader; |
| |
| public OAuth2AccessTokenTest () throws KustvaktException { |
| userAuthHeader = HttpAuthorizationHandler |
| .createBasicAuthorizationHeaderValue("dory", "password"); |
| clientAuthHeader = HttpAuthorizationHandler |
| .createBasicAuthorizationHeaderValue(confidentialClientId, |
| clientSecret); |
| } |
| |
| @Test |
| public void testScopeWithSuperClient () throws KustvaktException { |
| Response response = requestTokenWithDoryPassword(superClientId, |
| clientSecret); |
| JsonNode node = JsonUtils.readTree(response.readEntity(String.class)); |
| assertEquals(node.at("/scope").asText(), "all"); |
| String accessToken = node.at("/access_token").asText(); |
| |
| createDoryGroup(); |
| createMarlinGroup(); |
| addMember(marlinGroupName, "dory", "marlin"); |
| |
| // test list user group |
| response = target().path(API_VERSION).path("group").request() |
| .header(Attributes.AUTHORIZATION, "Bearer " + accessToken) |
| .get(); |
| assertEquals(Status.OK.getStatusCode(), response.getStatus()); |
| node = JsonUtils.readTree(response.readEntity(String.class)); |
| assertEquals(2, node.size()); |
| |
| deleteGroupByName(doryGroupName, "dory"); |
| deleteGroupByName(marlinGroupName, "marlin"); |
| } |
| |
| @Test |
| public void testCustomScope () throws KustvaktException { |
| createDoryVC(); |
| |
| Response response = requestAuthorizationCode("code", |
| confidentialClientId, "", OAuth2Scope.VC_INFO.toString(), "", |
| userAuthHeader); |
| String code = parseAuthorizationCode(response); |
| response = requestTokenWithAuthorizationCodeAndForm( |
| confidentialClientId, clientSecret, code); |
| JsonNode node = JsonUtils.readTree(response.readEntity(String.class)); |
| String token = node.at("/access_token").asText(); |
| String refreshToken = node.at("/refresh_token").asText(); |
| |
| assertTrue(node.at("/scope").asText() |
| .contains(OAuth2Scope.VC_INFO.toString())); |
| // test list vc using the token |
| response = target().path(API_VERSION).path("vc").request() |
| .header(Attributes.AUTHORIZATION, "Bearer " + token).get(); |
| assertEquals(Status.OK.getStatusCode(), response.getStatus()); |
| node = JsonUtils.readTree(response.readEntity(String.class)); |
| assertEquals(2, node.size()); |
| |
| revokeToken(token, confidentialClientId, clientSecret, |
| ACCESS_TOKEN_TYPE); |
| revokeToken(refreshToken, confidentialClientId, clientSecret, |
| REFRESH_TOKEN_TYPE); |
| |
| deleteVC("dory-vc", "dory", "dory"); |
| } |
| |
| @Test |
| public void testDefaultScope () throws KustvaktException, IOException { |
| String code = requestAuthorizationCode(confidentialClientId, |
| userAuthHeader); |
| Response response = requestTokenWithAuthorizationCodeAndForm( |
| confidentialClientId, clientSecret, code); |
| assertEquals(Status.OK.getStatusCode(), response.getStatus()); |
| JsonNode node = JsonUtils.readTree(response.readEntity(String.class)); |
| String accessToken = node.at("/access_token").asText(); |
| String refreshToken = node.at("/refresh_token").asText(); |
| testScopeNotAuthorized(accessToken); |
| testScopeNotAuthorize2(accessToken); |
| testSearchWithOAuth2Token(accessToken); |
| |
| revokeToken(accessToken, confidentialClientId, clientSecret, |
| ACCESS_TOKEN_TYPE); |
| revokeToken(refreshToken, confidentialClientId, clientSecret, |
| REFRESH_TOKEN_TYPE); |
| } |
| |
| private void testScopeNotAuthorized (String accessToken) |
| throws KustvaktException { |
| Response response = target().path(API_VERSION).path("vc").request() |
| .header(Attributes.AUTHORIZATION, "Bearer " + accessToken) |
| .get(); |
| assertEquals(Status.UNAUTHORIZED.getStatusCode(), response.getStatus()); |
| String entity = response.readEntity(String.class); |
| JsonNode node = JsonUtils.readTree(entity); |
| assertEquals(StatusCodes.AUTHORIZATION_FAILED, |
| node.at("/errors/0/0").asInt()); |
| assertEquals(node.at("/errors/0/1").asText(), |
| "Scope vc_info is not authorized"); |
| } |
| |
| private void testScopeNotAuthorize2 (String accessToken) |
| throws KustvaktException { |
| Response response = target().path(API_VERSION).path("vc").path("access") |
| .request() |
| .header(Attributes.AUTHORIZATION, "Bearer " + accessToken) |
| .get(); |
| String entity = response.readEntity(String.class); |
| assertEquals(Status.UNAUTHORIZED.getStatusCode(), response.getStatus()); |
| JsonNode node = JsonUtils.readTree(entity); |
| assertEquals(StatusCodes.AUTHORIZATION_FAILED, |
| node.at("/errors/0/0").asInt()); |
| assertEquals(node.at("/errors/0/1").asText(), |
| "Scope vc_access_info is not authorized"); |
| } |
| |
| @Test |
| public void testSearchWithUnknownToken () |
| throws KustvaktException, IOException { |
| Response response = searchWithAccessToken( |
| "ljsa8tKNRSczJhk20öhq92zG8z350"); |
| assertEquals(Status.UNAUTHORIZED.getStatusCode(), response.getStatus()); |
| String ent = response.readEntity(String.class); |
| JsonNode node = JsonUtils.readTree(ent); |
| assertEquals(StatusCodes.INVALID_ACCESS_TOKEN, |
| node.at("/errors/0/0").asInt()); |
| assertEquals(node.at("/errors/0/1").asText(), |
| "Access token is invalid"); |
| } |
| |
| @Test |
| public void testRevokeAccessTokenConfidentialClient () |
| throws KustvaktException { |
| String code = requestAuthorizationCode(confidentialClientId, |
| userAuthHeader); |
| JsonNode node = requestTokenWithAuthorizationCodeAndHeader( |
| confidentialClientId, code, clientAuthHeader); |
| String accessToken = node.at("/access_token").asText(); |
| String refreshToken = node.at("/refresh_token").asText(); |
| |
| revokeToken(accessToken, confidentialClientId, clientSecret, |
| ACCESS_TOKEN_TYPE); |
| testSearchWithRevokedAccessToken(accessToken); |
| |
| revokeToken(refreshToken, confidentialClientId, clientSecret, |
| REFRESH_TOKEN_TYPE); |
| } |
| |
| @Test |
| public void testRevokeAccessTokenPublicClientViaSuperClient () |
| throws KustvaktException { |
| String code = requestAuthorizationCode(publicClientId, userAuthHeader); |
| Response response = requestTokenWithAuthorizationCodeAndForm( |
| publicClientId, "", code); |
| JsonNode node = JsonUtils.readTree(response.readEntity(String.class)); |
| String accessToken = node.at("/access_token").asText(); |
| revokeTokenViaSuperClient(accessToken, userAuthHeader); |
| testSearchWithRevokedAccessToken(accessToken); |
| } |
| |
| @Test |
| public void testAccessTokenAfterRequestRefreshToken () |
| throws KustvaktException, IOException { |
| String code = requestAuthorizationCode(confidentialClientId, |
| userAuthHeader); |
| JsonNode node = requestTokenWithAuthorizationCodeAndHeader( |
| confidentialClientId, code, clientAuthHeader); |
| String accessToken = node.at("/access_token").asText(); |
| String refreshToken = node.at("/refresh_token").asText(); |
| |
| node = requestTokenWithRefreshToken(confidentialClientId, clientSecret, |
| refreshToken); |
| String newAccessToken = node.at("/access_token").asText(); |
| String newRefreshToken = node.at("/refresh_token").asText(); |
| assertTrue(!refreshToken.equals(newRefreshToken)); |
| |
| testSearchWithRevokedAccessToken(accessToken); |
| revokeToken(newAccessToken, confidentialClientId, clientSecret, |
| ACCESS_TOKEN_TYPE); |
| revokeToken(newRefreshToken, confidentialClientId, clientSecret, |
| REFRESH_TOKEN_TYPE); |
| } |
| |
| @Test |
| public void testRequestAuthorizationWithBearerTokenUnauthorized () |
| throws KustvaktException { |
| String code = requestAuthorizationCode(confidentialClientId, |
| userAuthHeader); |
| JsonNode node = requestTokenWithAuthorizationCodeAndHeader( |
| confidentialClientId, code, clientAuthHeader); |
| String userAuthToken = node.at("/access_token").asText(); |
| String refreshToken = node.at("/refresh_token").asText(); |
| Response response = requestAuthorizationCode("code", |
| confidentialClientId, "", "search", "", |
| "Bearer " + userAuthToken); |
| assertEquals(Status.UNAUTHORIZED.getStatusCode(), response.getStatus()); |
| node = JsonUtils.readTree(response.readEntity(String.class)); |
| assertEquals(StatusCodes.AUTHORIZATION_FAILED, |
| node.at("/errors/0/0").asInt()); |
| assertEquals(node.at("/errors/0/1").asText(), |
| "Scope authorize is not authorized"); |
| |
| revokeToken(userAuthToken, confidentialClientId, clientSecret, |
| ACCESS_TOKEN_TYPE); |
| revokeToken(refreshToken, confidentialClientId, clientSecret, |
| REFRESH_TOKEN_TYPE); |
| } |
| |
| @Test |
| public void testRequestAuthorizationWithBearerToken () |
| throws KustvaktException { |
| Response response = requestTokenWithDoryPassword(superClientId, |
| clientSecret); |
| String entity = response.readEntity(String.class); |
| JsonNode node = JsonUtils.readTree(entity); |
| String userAuthToken = node.at("/access_token").asText(); |
| assertNotNull(userAuthToken); |
| assertEquals(TokenType.BEARER.displayName(), |
| node.at("/token_type").asText()); |
| assertNotNull(node.at("/expires_in").asText()); |
| String code = requestAuthorizationCode(superClientId, |
| "Bearer " + userAuthToken); |
| assertNotNull(code); |
| |
| revokeTokenViaSuperClient(userAuthToken, userAuthHeader); |
| } |
| |
| @Test |
| public void testRequestAuthorizationWithPassword () |
| throws KustvaktException { |
| Response response = requestTokenWithPassword(superClientId, |
| clientSecret, "username", "pass}"); |
| String entity = response.readEntity(String.class); |
| JsonNode node = JsonUtils.readTree(entity); |
| String accessToken = node.at("/access_token").asText(); |
| assertNotNull(accessToken); |
| String refreshToken = node.at("/refresh_token").asText(); |
| assertNotNull(refreshToken); |
| assertEquals(OAuth2Scope.ALL.name().toLowerCase(), |
| node.at("/scope").asText()); |
| assertEquals(TokenType.BEARER.displayName(), |
| node.at("/token_type").asText()); |
| assertNotNull(node.at("/expires_in").asText()); |
| } |
| } |