blob: 4f0f2cce341641e2077e442c9c52145a72c9b6ae [file] [log] [blame]
margarethacf306d32018-05-30 19:45:35 +02001package de.ids_mannheim.korap.web.controller;
2
Marc Kupietzd43a98d2023-09-22 17:11:46 +02003import static org.junit.jupiter.api.Assertions.assertEquals;
4import static org.junit.jupiter.api.Assertions.assertNotNull;
5import static org.junit.jupiter.api.Assertions.assertTrue;
margarethacf306d32018-05-30 19:45:35 +02006
margarethacf306d32018-05-30 19:45:35 +02007import java.io.IOException;
margarethacf306d32018-05-30 19:45:35 +02008
margaretha96c309d2023-08-16 12:24:12 +02009import jakarta.ws.rs.client.Entity;
10import jakarta.ws.rs.core.Form;
11import jakarta.ws.rs.core.Response;
12import jakarta.ws.rs.core.Response.Status;
margarethab1081b12018-07-03 23:35:01 +020013
14import org.apache.http.entity.ContentType;
Marc Kupietzd43a98d2023-09-22 17:11:46 +020015import org.junit.jupiter.api.Test;
margarethacf306d32018-05-30 19:45:35 +020016import com.fasterxml.jackson.databind.JsonNode;
17import com.google.common.net.HttpHeaders;
margaretha53c1ff82023-10-26 12:33:26 +020018import com.nimbusds.oauth2.sdk.GrantType;
19
margaretha835178d2018-08-15 19:04:03 +020020import de.ids_mannheim.korap.authentication.http.HttpAuthorizationHandler;
margarethacf306d32018-05-30 19:45:35 +020021import de.ids_mannheim.korap.config.Attributes;
margaretha2df06602018-11-14 19:10:30 +010022import de.ids_mannheim.korap.constant.OAuth2Scope;
margarethaf0085122018-08-16 16:19:53 +020023import de.ids_mannheim.korap.constant.TokenType;
margarethacf306d32018-05-30 19:45:35 +020024import de.ids_mannheim.korap.exceptions.KustvaktException;
25import de.ids_mannheim.korap.exceptions.StatusCodes;
26import de.ids_mannheim.korap.utils.JsonUtils;
margarethad0017702024-07-29 13:13:43 +020027import de.ids_mannheim.korap.web.controller.usergroup.UserGroupTestBase;
margarethacf306d32018-05-30 19:45:35 +020028
margarethad0017702024-07-29 13:13:43 +020029public class OAuth2AccessTokenTest extends UserGroupTestBase {
margarethacf306d32018-05-30 19:45:35 +020030
margarethaf0085122018-08-16 16:19:53 +020031 private String userAuthHeader;
Marc Kupietzd43a98d2023-09-22 17:11:46 +020032
margarethaf0085122018-08-16 16:19:53 +020033 private String clientAuthHeader;
margaretha1ef36bd2018-08-14 18:17:05 +020034
margaretha35e1ca22023-11-16 22:00:01 +010035 public OAuth2AccessTokenTest () throws KustvaktException {
36 userAuthHeader = HttpAuthorizationHandler
37 .createBasicAuthorizationHeaderValue("dory", "password");
38 clientAuthHeader = HttpAuthorizationHandler
39 .createBasicAuthorizationHeaderValue(confidentialClientId,
40 clientSecret);
margaretha835178d2018-08-15 19:04:03 +020041 }
margaretha064eb6f2018-07-10 18:33:01 +020042
margaretha835178d2018-08-15 19:04:03 +020043 @Test
margaretha35e1ca22023-11-16 22:00:01 +010044 public void testScopeWithSuperClient () throws KustvaktException {
45 Response response = requestTokenWithDoryPassword(superClientId,
46 clientSecret);
abcpro173fe8f22022-11-08 19:56:52 +000047 JsonNode node = JsonUtils.readTree(response.readEntity(String.class));
Marc Kupietzd43a98d2023-09-22 17:11:46 +020048 assertEquals(node.at("/scope").asText(), "all");
margaretha835178d2018-08-15 19:04:03 +020049 String accessToken = node.at("/access_token").asText();
margarethad0017702024-07-29 13:13:43 +020050
51 createDoryGroup();
52 createMarlinGroup();
margaretha04836712024-08-16 13:03:56 +020053 addMember(marlinGroupName, "dory", "marlin");
margarethad0017702024-07-29 13:13:43 +020054
margaretha835178d2018-08-15 19:04:03 +020055 // test list user group
margaretha35e1ca22023-11-16 22:00:01 +010056 response = target().path(API_VERSION).path("group").request()
57 .header(Attributes.AUTHORIZATION, "Bearer " + accessToken)
58 .get();
margaretha835178d2018-08-15 19:04:03 +020059 assertEquals(Status.OK.getStatusCode(), response.getStatus());
abcpro173fe8f22022-11-08 19:56:52 +000060 node = JsonUtils.readTree(response.readEntity(String.class));
margaretha835178d2018-08-15 19:04:03 +020061 assertEquals(2, node.size());
margarethad0017702024-07-29 13:13:43 +020062
63 deleteGroupByName(doryGroupName, "dory");
64 deleteGroupByName(marlinGroupName, "marlin");
margaretha835178d2018-08-15 19:04:03 +020065 }
66
67 @Test
margaretha35e1ca22023-11-16 22:00:01 +010068 public void testCustomScope () throws KustvaktException {
69 Response response = requestAuthorizationCode("code",
70 confidentialClientId, "", OAuth2Scope.VC_INFO.toString(), "",
71 userAuthHeader);
margaretha6345b812023-05-02 15:03:06 +020072 String code = parseAuthorizationCode(response);
margaretha35e1ca22023-11-16 22:00:01 +010073 response = requestTokenWithAuthorizationCodeAndForm(
74 confidentialClientId, clientSecret, code);
abcpro173fe8f22022-11-08 19:56:52 +000075 JsonNode node = JsonUtils.readTree(response.readEntity(String.class));
margaretha835178d2018-08-15 19:04:03 +020076 String token = node.at("/access_token").asText();
margaretha35e1ca22023-11-16 22:00:01 +010077 assertTrue(node.at("/scope").asText()
78 .contains(OAuth2Scope.VC_INFO.toString()));
margarethaf0085122018-08-16 16:19:53 +020079 // test list vc using the token
margaretha35e1ca22023-11-16 22:00:01 +010080 response = target().path(API_VERSION).path("vc").request()
81 .header(Attributes.AUTHORIZATION, "Bearer " + token).get();
margaretha20f31232018-07-09 17:49:39 +020082 assertEquals(Status.OK.getStatusCode(), response.getStatus());
abcpro173fe8f22022-11-08 19:56:52 +000083 node = JsonUtils.readTree(response.readEntity(String.class));
margarethad0017702024-07-29 13:13:43 +020084 assertEquals(3, node.size());
margaretha20f31232018-07-09 17:49:39 +020085 }
margarethacf306d32018-05-30 19:45:35 +020086
87 @Test
margaretha35e1ca22023-11-16 22:00:01 +010088 public void testDefaultScope () throws KustvaktException, IOException {
89 String code = requestAuthorizationCode(confidentialClientId,
90 userAuthHeader);
91 Response response = requestTokenWithAuthorizationCodeAndForm(
92 confidentialClientId, clientSecret, code);
margarethaf0085122018-08-16 16:19:53 +020093 assertEquals(Status.OK.getStatusCode(), response.getStatus());
abcpro173fe8f22022-11-08 19:56:52 +000094 JsonNode node = JsonUtils.readTree(response.readEntity(String.class));
margarethaf0085122018-08-16 16:19:53 +020095 String accessToken = node.at("/access_token").asText();
96 testScopeNotAuthorized(accessToken);
97 testScopeNotAuthorize2(accessToken);
margarethadc515072018-08-03 17:01:19 +020098 testSearchWithOAuth2Token(accessToken);
margarethadc515072018-08-03 17:01:19 +020099 }
100
margaretha35e1ca22023-11-16 22:00:01 +0100101 private void testScopeNotAuthorized (String accessToken)
102 throws KustvaktException {
103 Response response = target().path(API_VERSION).path("vc").request()
104 .header(Attributes.AUTHORIZATION, "Bearer " + accessToken)
105 .get();
Marc Kupietzd43a98d2023-09-22 17:11:46 +0200106 assertEquals(Status.UNAUTHORIZED.getStatusCode(), response.getStatus());
abcpro173fe8f22022-11-08 19:56:52 +0000107 String entity = response.readEntity(String.class);
margarethacf306d32018-05-30 19:45:35 +0200108 JsonNode node = JsonUtils.readTree(entity);
margaretha35e1ca22023-11-16 22:00:01 +0100109 assertEquals(StatusCodes.AUTHORIZATION_FAILED,
110 node.at("/errors/0/0").asInt());
111 assertEquals(node.at("/errors/0/1").asText(),
112 "Scope vc_info is not authorized");
margarethacf306d32018-05-30 19:45:35 +0200113 }
114
margaretha35e1ca22023-11-16 22:00:01 +0100115 private void testScopeNotAuthorize2 (String accessToken)
116 throws KustvaktException {
117 Response response = target().path(API_VERSION).path("vc").path("access")
118 .request()
119 .header(Attributes.AUTHORIZATION, "Bearer " + accessToken)
120 .get();
abcpro173fe8f22022-11-08 19:56:52 +0000121 String entity = response.readEntity(String.class);
Marc Kupietzd43a98d2023-09-22 17:11:46 +0200122 assertEquals(Status.UNAUTHORIZED.getStatusCode(), response.getStatus());
margaretha0a45be12018-07-12 15:06:30 +0200123 JsonNode node = JsonUtils.readTree(entity);
margaretha35e1ca22023-11-16 22:00:01 +0100124 assertEquals(StatusCodes.AUTHORIZATION_FAILED,
125 node.at("/errors/0/0").asInt());
126 assertEquals(node.at("/errors/0/1").asText(),
127 "Scope vc_access_info is not authorized");
margaretha0a45be12018-07-12 15:06:30 +0200128 }
129
margarethacf306d32018-05-30 19:45:35 +0200130 @Test
margaretha35e1ca22023-11-16 22:00:01 +0100131 public void testSearchWithUnknownToken ()
132 throws KustvaktException, IOException {
133 Response response = searchWithAccessToken(
134 "ljsa8tKNRSczJhk20öhq92zG8z350");
Marc Kupietzd43a98d2023-09-22 17:11:46 +0200135 assertEquals(Status.UNAUTHORIZED.getStatusCode(), response.getStatus());
abcpro173fe8f22022-11-08 19:56:52 +0000136 String ent = response.readEntity(String.class);
margarethacf306d32018-05-30 19:45:35 +0200137 JsonNode node = JsonUtils.readTree(ent);
margaretha35e1ca22023-11-16 22:00:01 +0100138 assertEquals(StatusCodes.INVALID_ACCESS_TOKEN,
139 node.at("/errors/0/0").asInt());
140 assertEquals(node.at("/errors/0/1").asText(),
141 "Access token is invalid");
margarethacf306d32018-05-30 19:45:35 +0200142 }
margarethadc515072018-08-03 17:01:19 +0200143
144 @Test
margaretha35e1ca22023-11-16 22:00:01 +0100145 public void testRevokeAccessTokenConfidentialClient ()
146 throws KustvaktException {
147 String code = requestAuthorizationCode(confidentialClientId,
148 userAuthHeader);
149 JsonNode node = requestTokenWithAuthorizationCodeAndHeader(
150 confidentialClientId, code, clientAuthHeader);
margarethaf0085122018-08-16 16:19:53 +0200151 String accessToken = node.at("/access_token").asText();
abcpro173fe8f22022-11-08 19:56:52 +0000152 Form form = new Form();
153 form.param("token", accessToken);
154 form.param("client_id", confidentialClientId);
155 form.param("client_secret", "secret");
margaretha35e1ca22023-11-16 22:00:01 +0100156 Response response = target().path(API_VERSION).path("oauth2")
157 .path("revoke").request()
158 .header(HttpHeaders.CONTENT_TYPE,
159 ContentType.APPLICATION_FORM_URLENCODED)
160 .post(Entity.form(form));
margarethadc515072018-08-03 17:01:19 +0200161 assertEquals(Status.OK.getStatusCode(), response.getStatus());
margarethaf0085122018-08-16 16:19:53 +0200162 testSearchWithRevokedAccessToken(accessToken);
margarethadc515072018-08-03 17:01:19 +0200163 }
Marc Kupietzd43a98d2023-09-22 17:11:46 +0200164
margaretha0afd44a2020-02-05 10:49:21 +0100165 @Test
margaretha35e1ca22023-11-16 22:00:01 +0100166 public void testRevokeAccessTokenPublicClientViaSuperClient ()
167 throws KustvaktException {
Marc Kupietzd43a98d2023-09-22 17:11:46 +0200168 String code = requestAuthorizationCode(publicClientId, userAuthHeader);
margaretha35e1ca22023-11-16 22:00:01 +0100169 Response response = requestTokenWithAuthorizationCodeAndForm(
170 publicClientId, "", code);
abcpro173fe8f22022-11-08 19:56:52 +0000171 JsonNode node = JsonUtils.readTree(response.readEntity(String.class));
margaretha0afd44a2020-02-05 10:49:21 +0100172 String accessToken = node.at("/access_token").asText();
173 testRevokeTokenViaSuperClient(accessToken, userAuthHeader);
174 testSearchWithRevokedAccessToken(accessToken);
175 }
margarethadc515072018-08-03 17:01:19 +0200176
margaretha1ef36bd2018-08-14 18:17:05 +0200177 @Test
margaretha35e1ca22023-11-16 22:00:01 +0100178 public void testAccessTokenAfterRequestRefreshToken ()
179 throws KustvaktException, IOException {
180 String code = requestAuthorizationCode(confidentialClientId,
181 userAuthHeader);
182 JsonNode node = requestTokenWithAuthorizationCodeAndHeader(
183 confidentialClientId, code, clientAuthHeader);
margaretha1ef36bd2018-08-14 18:17:05 +0200184 String accessToken = node.at("/access_token").asText();
185 String refreshToken = node.at("/refresh_token").asText();
abcpro173fe8f22022-11-08 19:56:52 +0000186 Form form = new Form();
187 form.param("grant_type", GrantType.REFRESH_TOKEN.toString());
188 form.param("client_id", confidentialClientId);
189 form.param("client_secret", "secret");
190 form.param("refresh_token", refreshToken);
margaretha35e1ca22023-11-16 22:00:01 +0100191 Response response = target().path(API_VERSION).path("oauth2")
192 .path("token").request()
193 .header(HttpHeaders.X_FORWARDED_FOR, "149.27.0.32")
194 .header(HttpHeaders.CONTENT_TYPE,
195 ContentType.APPLICATION_FORM_URLENCODED)
196 .post(Entity.form(form));
abcpro173fe8f22022-11-08 19:56:52 +0000197 String entity = response.readEntity(String.class);
margaretha1ef36bd2018-08-14 18:17:05 +0200198 assertEquals(Status.OK.getStatusCode(), response.getStatus());
margaretha1ef36bd2018-08-14 18:17:05 +0200199 node = JsonUtils.readTree(entity);
200 assertNotNull(node.at("/access_token").asText());
margaretha6f0b7382018-11-21 17:42:02 +0100201 assertTrue(!refreshToken.equals(node.at("/refresh_token").asText()));
margaretha6f0b7382018-11-21 17:42:02 +0100202 testSearchWithRevokedAccessToken(accessToken);
margarethadc515072018-08-03 17:01:19 +0200203 }
margaretha835178d2018-08-15 19:04:03 +0200204
205 @Test
margaretha35e1ca22023-11-16 22:00:01 +0100206 public void testRequestAuthorizationWithBearerTokenUnauthorized ()
207 throws KustvaktException {
208 String code = requestAuthorizationCode(confidentialClientId,
209 userAuthHeader);
210 JsonNode node = requestTokenWithAuthorizationCodeAndHeader(
211 confidentialClientId, code, clientAuthHeader);
margarethaf0085122018-08-16 16:19:53 +0200212 String userAuthToken = node.at("/access_token").asText();
margaretha35e1ca22023-11-16 22:00:01 +0100213 Response response = requestAuthorizationCode("code",
214 confidentialClientId, "", "search", "",
215 "Bearer " + userAuthToken);
margaretha835178d2018-08-15 19:04:03 +0200216 assertEquals(Status.UNAUTHORIZED.getStatusCode(), response.getStatus());
abcpro173fe8f22022-11-08 19:56:52 +0000217 node = JsonUtils.readTree(response.readEntity(String.class));
margaretha35e1ca22023-11-16 22:00:01 +0100218 assertEquals(StatusCodes.AUTHORIZATION_FAILED,
219 node.at("/errors/0/0").asInt());
220 assertEquals(node.at("/errors/0/1").asText(),
221 "Scope authorize is not authorized");
margaretha835178d2018-08-15 19:04:03 +0200222 }
223
224 @Test
margaretha35e1ca22023-11-16 22:00:01 +0100225 public void testRequestAuthorizationWithBearerToken ()
226 throws KustvaktException {
227 Response response = requestTokenWithDoryPassword(superClientId,
228 clientSecret);
abcpro173fe8f22022-11-08 19:56:52 +0000229 String entity = response.readEntity(String.class);
margarethaf0085122018-08-16 16:19:53 +0200230 JsonNode node = JsonUtils.readTree(entity);
231 String userAuthToken = node.at("/access_token").asText();
232 assertNotNull(userAuthToken);
margaretha35e1ca22023-11-16 22:00:01 +0100233 assertEquals(TokenType.BEARER.displayName(),
234 node.at("/token_type").asText());
margarethaf0085122018-08-16 16:19:53 +0200235 assertNotNull(node.at("/expires_in").asText());
margaretha35e1ca22023-11-16 22:00:01 +0100236 String code = requestAuthorizationCode(superClientId,
237 "Bearer " + userAuthToken);
margaretha835178d2018-08-15 19:04:03 +0200238 assertNotNull(code);
239 }
margarethacf306d32018-05-30 19:45:35 +0200240}