blob: 82caebef69d2befeb1344cedc34d8dc067f4138e [file] [log] [blame]
margarethaa0486272018-04-12 19:59:31 +02001package de.ids_mannheim.korap.web.controller;
2
margaretha05122312018-04-16 15:01:34 +02003import static org.junit.Assert.assertEquals;
margarethaf839dde2018-04-16 17:52:57 +02004import static org.junit.Assert.assertNotNull;
margaretha6f0b7382018-11-21 17:42:02 +01005import static org.junit.Assert.assertTrue;
margarethafb027f92018-04-23 20:00:13 +02006
7import java.net.URI;
margaretha977fabe2022-04-28 09:23:47 +02008import java.time.ZonedDateTime;
margaretha93e602e2019-08-07 15:19:56 +02009import java.util.Set;
margaretha05122312018-04-16 15:01:34 +020010
margarethaa0486272018-04-12 19:59:31 +020011import javax.ws.rs.core.MultivaluedMap;
margaretha05122312018-04-16 15:01:34 +020012import javax.ws.rs.core.Response.Status;
margarethaa0486272018-04-12 19:59:31 +020013
14import org.apache.http.entity.ContentType;
margaretha05122312018-04-16 15:01:34 +020015import org.apache.oltu.oauth2.common.error.OAuthError;
margaretha03b82862018-07-12 20:09:26 +020016import org.apache.oltu.oauth2.common.message.types.GrantType;
margarethaf839dde2018-04-16 17:52:57 +020017import org.apache.oltu.oauth2.common.message.types.TokenType;
margarethaa0486272018-04-12 19:59:31 +020018import org.junit.Test;
margarethaa0486272018-04-12 19:59:31 +020019
margaretha05122312018-04-16 15:01:34 +020020import com.fasterxml.jackson.databind.JsonNode;
margarethaa0486272018-04-12 19:59:31 +020021import com.google.common.net.HttpHeaders;
margarethaa0486272018-04-12 19:59:31 +020022import com.sun.jersey.api.client.ClientResponse;
margarethaa0486272018-04-12 19:59:31 +020023import com.sun.jersey.core.util.MultivaluedMapImpl;
24
25import de.ids_mannheim.korap.authentication.http.HttpAuthorizationHandler;
margaretha43aceb52019-11-21 12:58:53 +010026import de.ids_mannheim.korap.config.Attributes;
margarethaa0486272018-04-12 19:59:31 +020027import de.ids_mannheim.korap.exceptions.KustvaktException;
margarethabe4c5c92018-05-03 18:55:49 +020028import de.ids_mannheim.korap.oauth2.constant.OAuth2Error;
margaretha93e602e2019-08-07 15:19:56 +020029import de.ids_mannheim.korap.oauth2.entity.AccessScope;
30import de.ids_mannheim.korap.oauth2.entity.RefreshToken;
margaretha05122312018-04-16 15:01:34 +020031import de.ids_mannheim.korap.utils.JsonUtils;
margarethaa0486272018-04-12 19:59:31 +020032
33/**
34 * @author margaretha
35 *
36 */
margarethaf0085122018-08-16 16:19:53 +020037public class OAuth2ControllerTest extends OAuth2TestBase {
margarethaa0486272018-04-12 19:59:31 +020038
margarethaf0085122018-08-16 16:19:53 +020039 public String userAuthHeader;
margaretha35074692021-03-26 18:11:59 +010040
margarethaf0085122018-08-16 16:19:53 +020041 public OAuth2ControllerTest () throws KustvaktException {
42 userAuthHeader = HttpAuthorizationHandler
43 .createBasicAuthorizationHeaderValue("dory", "password");
margarethaf839dde2018-04-16 17:52:57 +020044 }
45
margarethafb027f92018-04-23 20:00:13 +020046 @Test
47 public void testAuthorizeConfidentialClient () throws KustvaktException {
margarethaffb89502022-04-20 12:03:16 +020048 // with registered redirect URI
49 ClientResponse response =
50 requestAuthorizationCode("code", confidentialClientId, "",
51 "match_info search client_info", state, userAuthHeader);
margarethadc515072018-08-03 17:01:19 +020052
53 assertEquals(Status.TEMPORARY_REDIRECT.getStatusCode(),
54 response.getStatus());
55 URI redirectUri = response.getLocation();
margarethaffb89502022-04-20 12:03:16 +020056 MultivaluedMap<String, String> params =
57 getQueryParamsFromURI(redirectUri);
margarethadc515072018-08-03 17:01:19 +020058 assertNotNull(params.getFirst("code"));
margaretha9436ebe2022-04-22 11:48:37 +020059 assertEquals(state, params.getFirst("state"));
margarethaffb89502022-04-20 12:03:16 +020060 assertEquals("match_info search client_info", params.getFirst("scope"));
margarethadc515072018-08-03 17:01:19 +020061 }
62
63 @Test
64 public void testAuthorizePublicClient () throws KustvaktException {
margarethaffb89502022-04-20 12:03:16 +020065 // with registered redirect URI
margarethad67b4272022-04-11 17:34:19 +020066 String code = requestAuthorizationCode(publicClientId, userAuthHeader);
margarethaf0085122018-08-16 16:19:53 +020067 assertNotNull(code);
margarethafb027f92018-04-23 20:00:13 +020068 }
69
70 @Test
margaretha9436ebe2022-04-22 11:48:37 +020071 public void testAuthorizeWithRedirectUri () throws KustvaktException {
margarethaffb89502022-04-20 12:03:16 +020072 ClientResponse response =
73 requestAuthorizationCode("code", publicClientId2,
74 "https://public.com/redirect", "", "", userAuthHeader);
75 assertEquals(Status.TEMPORARY_REDIRECT.getStatusCode(),
76 response.getStatus());
margaretha9436ebe2022-04-22 11:48:37 +020077
margarethaffb89502022-04-20 12:03:16 +020078 URI redirectUri = response.getLocation();
margaretha9436ebe2022-04-22 11:48:37 +020079 assertEquals("https", redirectUri.getScheme());
80 assertEquals("public.com", redirectUri.getHost());
81 assertEquals("/redirect", redirectUri.getPath());
margarethaffb89502022-04-20 12:03:16 +020082
83 String[] queryParts = redirectUri.getQuery().split("&");
84 assertTrue(queryParts[0].startsWith("code="));
margaretha9436ebe2022-04-22 11:48:37 +020085 assertEquals("scope=match_info+search", queryParts[1]);
margarethaffb89502022-04-20 12:03:16 +020086 }
margaretha9436ebe2022-04-22 11:48:37 +020087
margarethaffb89502022-04-20 12:03:16 +020088 @Test
89 public void testAuthorizeWithoutScope () throws KustvaktException {
90 ClientResponse response = requestAuthorizationCode("code",
91 confidentialClientId, "", "", "", userAuthHeader);
92 assertEquals(Status.TEMPORARY_REDIRECT.getStatusCode(),
93 response.getStatus());
94
95 URI redirectUri = response.getLocation();
96 assertEquals(redirectUri.getScheme(), "https");
97 assertEquals(redirectUri.getHost(), "third.party.com");
98 assertEquals(redirectUri.getPath(), "/confidential/redirect");
99
100 String[] queryParts = redirectUri.getQuery().split("&");
101 assertTrue(queryParts[0].startsWith("code="));
102 assertEquals(queryParts[1], "scope=match_info+search");
103 }
104
105 @Test
106 public void testAuthorizeMissingClientId () throws KustvaktException {
107 ClientResponse response = requestAuthorizationCode("code", "", "", "",
108 "", userAuthHeader);
109 assertEquals(Status.BAD_REQUEST.getStatusCode(), response.getStatus());
110 String entity = response.getEntity(String.class);
111 JsonNode node = JsonUtils.readTree(entity);
112 assertEquals("Missing parameters: client_id",
113 node.at("/error_description").asText());
114 }
115
116 @Test
117 public void testAuthorizeMissingRedirectUri () throws KustvaktException {
118 ClientResponse response = requestAuthorizationCode("code",
119 publicClientId2, "", "", state, userAuthHeader);
120 assertEquals(Status.BAD_REQUEST.getStatusCode(), response.getStatus());
121
122 String entity = response.getEntity(String.class);
123 JsonNode node = JsonUtils.readTree(entity);
124 assertEquals(OAuthError.CodeResponse.INVALID_REQUEST,
125 node.at("/error").asText());
margaretha590acf62022-05-06 10:44:56 +0200126 assertEquals("Missing parameter: redirect URI",
margarethaffb89502022-04-20 12:03:16 +0200127 node.at("/error_description").asText());
margaretha9436ebe2022-04-22 11:48:37 +0200128 assertEquals(state, node.at("/state").asText());
margarethaffb89502022-04-20 12:03:16 +0200129 }
130
131 @Test
margaretha0034a0c2022-05-17 10:37:41 +0200132 public void testAuthorizeMissingResponseType() throws KustvaktException {
margarethaffb89502022-04-20 12:03:16 +0200133 ClientResponse response = requestAuthorizationCode("",
134 confidentialClientId, "", "", "", userAuthHeader);
135 assertEquals(Status.TEMPORARY_REDIRECT.getStatusCode(),
136 response.getStatus());
137
138 assertEquals("https://third.party.com/confidential/redirect?"
139 + "error_description=Missing+parameters%3A+response_type&"
140 + "error=invalid_request", response.getLocation().toString());
141 }
margaretha0034a0c2022-05-17 10:37:41 +0200142
143 @Test
144 public void testAuthorizeMissingResponseTypeWithoutClientId () throws KustvaktException {
145 ClientResponse response = requestAuthorizationCode("",
146 "", "", "", "", userAuthHeader);
147
148 assertEquals(Status.BAD_REQUEST.getStatusCode(),
149 response.getStatus());
150 String entity = response.getEntity(String.class);
151 JsonNode node = JsonUtils.readTree(entity);
152
153 assertEquals(OAuthError.CodeResponse.INVALID_REQUEST,
154 node.at("/error").asText());
155 assertEquals("Missing parameters: response_type client_id",
156 node.at("/error_description").asText());
157 }
margarethaffb89502022-04-20 12:03:16 +0200158
159 @Test
160 public void testAuthorizeInvalidClientId () throws KustvaktException {
161 ClientResponse response = requestAuthorizationCode("code",
162 "unknown-client-id", "", "", "", userAuthHeader);
margaretha9436ebe2022-04-22 11:48:37 +0200163 assertEquals(Status.UNAUTHORIZED.getStatusCode(), response.getStatus());
margarethaffb89502022-04-20 12:03:16 +0200164 String entity = response.getEntity(String.class);
margarethaffb89502022-04-20 12:03:16 +0200165 JsonNode node = JsonUtils.readTree(entity);
margaretha9436ebe2022-04-22 11:48:37 +0200166 assertEquals(OAuth2Error.INVALID_CLIENT, node.at("/error").asText());
margaretha7da23902022-05-02 08:38:45 +0200167 assertEquals("Unknown client: unknown-client-id",
margarethaffb89502022-04-20 12:03:16 +0200168 node.at("/error_description").asText());
169 }
170
171 @Test
margaretha9436ebe2022-04-22 11:48:37 +0200172 public void testAuthorizeDifferentRedirectUri () throws KustvaktException {
margarethafb027f92018-04-23 20:00:13 +0200173 String redirectUri = "https://different.uri/redirect";
margarethad67b4272022-04-11 17:34:19 +0200174 ClientResponse response = requestAuthorizationCode("code",
175 confidentialClientId, redirectUri, "", state, userAuthHeader);
margaretha9436ebe2022-04-22 11:48:37 +0200176 testInvalidRedirectUri(response.getEntity(String.class), true,
177 response.getStatus());
178 }
margarethafb027f92018-04-23 20:00:13 +0200179
margaretha9436ebe2022-04-22 11:48:37 +0200180 @Test
181 public void testAuthorizeWithRedirectUriLocalhost ()
182 throws KustvaktException {
183 ClientResponse response =
184 requestAuthorizationCode("code", publicClientId2,
185 "http://localhost:1410", "", state, userAuthHeader);
186 testInvalidRedirectUri(response.getEntity(String.class), true,
187 response.getStatus()); }
margarethafb027f92018-04-23 20:00:13 +0200188
margaretha9436ebe2022-04-22 11:48:37 +0200189 @Test
190 public void testAuthorizeWithRedirectUriFragment ()
191 throws KustvaktException {
192 ClientResponse response = requestAuthorizationCode("code",
193 publicClientId2, "http://public.com/index.html#redirect", "",
194 state, userAuthHeader);
195 testInvalidRedirectUri(response.getEntity(String.class), true,
196 response.getStatus());
197 }
198
199 @Test
200 public void testAuthorizeInvalidRedirectUri () throws KustvaktException {
201 // host not allowed by Apache URI Validator
202 String redirectUri = "https://public.uri/redirect";
203 ClientResponse response = requestAuthorizationCode("code",
204 publicClientId2, redirectUri, "", state, userAuthHeader);
205 testInvalidRedirectUri(response.getEntity(String.class), true,
206 response.getStatus());
margarethafb027f92018-04-23 20:00:13 +0200207 }
margarethafb027f92018-04-23 20:00:13 +0200208
209 @Test
210 public void testAuthorizeInvalidResponseType () throws KustvaktException {
margarethaffb89502022-04-20 12:03:16 +0200211 // without redirect URI in the request
margarethad67b4272022-04-11 17:34:19 +0200212 ClientResponse response = requestAuthorizationCode("string",
213 confidentialClientId, "", "", state, userAuthHeader);
margarethaffb89502022-04-20 12:03:16 +0200214 assertEquals(Status.TEMPORARY_REDIRECT.getStatusCode(),
215 response.getStatus());
216
217 assertEquals("https://third.party.com/confidential/redirect?"
218 + "error_description=Invalid+response_type+parameter+"
219 + "value&state=thisIsMyState&" + "error=invalid_request",
220 response.getLocation().toString());
221
222 // with redirect URI, and no registered redirect URI
223 response = requestAuthorizationCode("string", publicClientId2,
224 "https://public.client.com/redirect", "", state,
225 userAuthHeader);
226 assertEquals(Status.TEMPORARY_REDIRECT.getStatusCode(),
227 response.getStatus());
228
229 assertEquals("https://public.client.com/redirect?error_description="
230 + "Invalid+response_type+parameter+value&state=thisIsMyState&"
231 + "error=invalid_request", response.getLocation().toString());
232
233 // with different redirect URI
234 String redirectUri = "https://different.uri/redirect";
235 response = requestAuthorizationCode("string", confidentialClientId,
236 redirectUri, "", state, userAuthHeader);
margarethafb027f92018-04-23 20:00:13 +0200237 assertEquals(Status.BAD_REQUEST.getStatusCode(), response.getStatus());
238
margarethaffb89502022-04-20 12:03:16 +0200239 JsonNode node = JsonUtils.readTree(response.getEntity(String.class));
margarethafb027f92018-04-23 20:00:13 +0200240 assertEquals(OAuthError.CodeResponse.INVALID_REQUEST,
241 node.at("/error").asText());
margarethaffb89502022-04-20 12:03:16 +0200242 assertEquals("Invalid redirect URI",
243 node.at("/error_description").asText());
margaretha9436ebe2022-04-22 11:48:37 +0200244 assertEquals(state, node.at("/state").asText());
margarethaffb89502022-04-20 12:03:16 +0200245
246 // without redirect URI in the request and no registered
247 // redirect URI
248 response = requestAuthorizationCode("string", publicClientId2, "", "",
249 state, userAuthHeader);
250 assertEquals(Status.BAD_REQUEST.getStatusCode(), response.getStatus());
251
252 node = JsonUtils.readTree(response.getEntity(String.class));
253 assertEquals(OAuthError.CodeResponse.INVALID_REQUEST,
254 node.at("/error").asText());
margaretha590acf62022-05-06 10:44:56 +0200255 assertEquals("Missing parameter: redirect URI",
margarethafb027f92018-04-23 20:00:13 +0200256 node.at("/error_description").asText());
margaretha9436ebe2022-04-22 11:48:37 +0200257 assertEquals(state, node.at("/state").asText());
margarethafb027f92018-04-23 20:00:13 +0200258 }
259
margarethabe4c5c92018-05-03 18:55:49 +0200260 @Test
261 public void testAuthorizeInvalidScope () throws KustvaktException {
margarethad67b4272022-04-11 17:34:19 +0200262 String scope = "read_address";
margarethad67b4272022-04-11 17:34:19 +0200263 ClientResponse response = requestAuthorizationCode("code",
264 confidentialClientId, "", scope, state, userAuthHeader);
margarethaffb89502022-04-20 12:03:16 +0200265 assertEquals(Status.TEMPORARY_REDIRECT.getStatusCode(),
266 response.getStatus());
margarethabe4c5c92018-05-03 18:55:49 +0200267
margarethaffb89502022-04-20 12:03:16 +0200268 assertEquals(
269 "https://third.party.com/confidential/redirect?"
margaretha9436ebe2022-04-22 11:48:37 +0200270 + "error_description=read_address+is+an+invalid+scope&"
271 + "state=thisIsMyState&error=invalid_scope",
margarethaffb89502022-04-20 12:03:16 +0200272 response.getLocation().toString());
273 }
274
275 @Test
276 public void testAuthorizeUnsupportedTokenResponseType ()
277 throws KustvaktException {
278 ClientResponse response = requestAuthorizationCode("token",
279 confidentialClientId, "", "", state, userAuthHeader);
280 assertEquals(Status.TEMPORARY_REDIRECT.getStatusCode(),
281 response.getStatus());
282
283 assertEquals("https://third.party.com/confidential/redirect?"
284 + "error_description=response_type+token+is+not+"
285 + "supported&state=thisIsMyState&error=unsupported_"
286 + "response_type", response.getLocation().toString());
margarethabe4c5c92018-05-03 18:55:49 +0200287 }
288
margaretha6374f722018-04-17 18:45:57 +0200289 @Test
margarethaf0085122018-08-16 16:19:53 +0200290 public void testRequestTokenAuthorizationPublic ()
291 throws KustvaktException {
margaretha9436ebe2022-04-22 11:48:37 +0200292 String code = requestAuthorizationCode(publicClientId, userAuthHeader);
margaretha835178d2018-08-15 19:04:03 +0200293
margarethaf0085122018-08-16 16:19:53 +0200294 ClientResponse response = requestTokenWithAuthorizationCodeAndForm(
295 publicClientId, clientSecret, code);
margaretha835178d2018-08-15 19:04:03 +0200296 String entity = response.getEntity(String.class);
297 JsonNode node = JsonUtils.readTree(entity);
margarethaf0085122018-08-16 16:19:53 +0200298
margaretha835178d2018-08-15 19:04:03 +0200299 String accessToken = node.at("/access_token").asText();
margarethaf0085122018-08-16 16:19:53 +0200300
margaretha835178d2018-08-15 19:04:03 +0200301 assertEquals(TokenType.BEARER.toString(),
302 node.at("/token_type").asText());
margaretha0afd44a2020-02-05 10:49:21 +0100303 assertEquals(31536000, node.at("/expires_in").asInt());
margarethaf0085122018-08-16 16:19:53 +0200304
margaretha35074692021-03-26 18:11:59 +0100305 testRevokeToken(accessToken, publicClientId, null, ACCESS_TOKEN_TYPE);
margarethaf0085122018-08-16 16:19:53 +0200306
margaretha0afd44a2020-02-05 10:49:21 +0100307 assertTrue(node.at("/refresh_token").isMissingNode());
margaretha835178d2018-08-15 19:04:03 +0200308 }
margarethaf0085122018-08-16 16:19:53 +0200309
margaretha835178d2018-08-15 19:04:03 +0200310 @Test
margarethaa452c5e2018-04-25 22:48:09 +0200311 public void testRequestTokenAuthorizationConfidential ()
312 throws KustvaktException {
margarethabe4c5c92018-05-03 18:55:49 +0200313
margarethad67b4272022-04-11 17:34:19 +0200314 String scope = "search";
315 ClientResponse response = requestAuthorizationCode("code",
316 confidentialClientId, "", scope, state, userAuthHeader);
margarethabe4c5c92018-05-03 18:55:49 +0200317 MultivaluedMap<String, String> params =
margarethaffb89502022-04-20 12:03:16 +0200318 getQueryParamsFromURI(response.getLocation());
margarethabe4c5c92018-05-03 18:55:49 +0200319 String code = params.get("code").get(0);
320 String scopes = params.get("scope").get(0);
321
margaretha20f31232018-07-09 17:49:39 +0200322 assertEquals(scopes, "search");
margarethabe4c5c92018-05-03 18:55:49 +0200323
margarethaf0085122018-08-16 16:19:53 +0200324 response = requestTokenWithAuthorizationCodeAndForm(
325 confidentialClientId, clientSecret, code);
margarethaa452c5e2018-04-25 22:48:09 +0200326 String entity = response.getEntity(String.class);
327 JsonNode node = JsonUtils.readTree(entity);
328 assertNotNull(node.at("/access_token").asText());
329 assertNotNull(node.at("/refresh_token").asText());
330 assertEquals(TokenType.BEARER.toString(),
331 node.at("/token_type").asText());
332 assertNotNull(node.at("/expires_in").asText());
margarethabe4c5c92018-05-03 18:55:49 +0200333
margarethaf0085122018-08-16 16:19:53 +0200334 testRequestTokenWithUsedAuthorization(code);
margaretha35074692021-03-26 18:11:59 +0100335
margaretha6f0b7382018-11-21 17:42:02 +0100336 String refreshToken = node.at("/refresh_token").asText();
margaretha977fabe2022-04-28 09:23:47 +0200337
338 testRefreshTokenExpiry(refreshToken);
margaretha0afd44a2020-02-05 10:49:21 +0100339 testRequestRefreshTokenInvalidScope(confidentialClientId, refreshToken);
340 testRequestRefreshTokenInvalidClient(refreshToken);
341 testRequestRefreshTokenInvalidRefreshToken(confidentialClientId);
margaretha35074692021-03-26 18:11:59 +0100342
margaretha9436ebe2022-04-22 11:48:37 +0200343 testRequestRefreshToken(confidentialClientId, clientSecret,
344 refreshToken);
margarethaa452c5e2018-04-25 22:48:09 +0200345 }
margarethabe4c5c92018-05-03 18:55:49 +0200346
margarethaf0085122018-08-16 16:19:53 +0200347 private void testRequestTokenWithUsedAuthorization (String code)
348 throws KustvaktException {
349 ClientResponse response = requestTokenWithAuthorizationCodeAndForm(
350 confidentialClientId, clientSecret, code);
margarethabe4c5c92018-05-03 18:55:49 +0200351 String entity = response.getEntity(String.class);
352
353 assertEquals(Status.BAD_REQUEST.getStatusCode(), response.getStatus());
354
355 JsonNode node = JsonUtils.readTree(entity);
356 assertEquals(OAuthError.TokenResponse.INVALID_GRANT,
357 node.at("/error").asText());
358 assertEquals("Invalid authorization",
359 node.at("/error_description").asText());
360 }
361
362 @Test
363 public void testRequestTokenInvalidAuthorizationCode ()
364 throws KustvaktException {
margarethaf0085122018-08-16 16:19:53 +0200365 ClientResponse response = requestTokenWithAuthorizationCodeAndForm(
366 confidentialClientId, clientSecret, "blahblah");
margarethabe4c5c92018-05-03 18:55:49 +0200367 String entity = response.getEntity(String.class);
368
369 assertEquals(Status.BAD_REQUEST.getStatusCode(), response.getStatus());
370
371 JsonNode node = JsonUtils.readTree(entity);
372 assertEquals(OAuthError.TokenResponse.INVALID_REQUEST,
373 node.at("/error").asText());
374 }
375
376 @Test
377 public void testRequestTokenAuthorizationReplyAttack ()
378 throws KustvaktException {
margarethad67b4272022-04-11 17:34:19 +0200379 String redirect_uri = "https://third.party.com/confidential/redirect";
380 String scope = "search";
margarethabe4c5c92018-05-03 18:55:49 +0200381
margarethaf0085122018-08-16 16:19:53 +0200382 ClientResponse response =
margarethad67b4272022-04-11 17:34:19 +0200383 requestAuthorizationCode("code", confidentialClientId,
384 redirect_uri, scope, state, userAuthHeader);
margarethabe4c5c92018-05-03 18:55:49 +0200385 MultivaluedMap<String, String> params =
margarethaffb89502022-04-20 12:03:16 +0200386 getQueryParamsFromURI(response.getLocation());
margarethabe4c5c92018-05-03 18:55:49 +0200387 String code = params.get("code").get(0);
388
389 testRequestTokenAuthorizationInvalidClient(code);
390 testRequestTokenAuthorizationInvalidRedirectUri(code);
margarethad67b4272022-04-11 17:34:19 +0200391 testRequestTokenAuthorizationRevoked(code, redirect_uri);
margarethabe4c5c92018-05-03 18:55:49 +0200392 }
393
394 private void testRequestTokenAuthorizationInvalidClient (String code)
395 throws KustvaktException {
margarethaf0085122018-08-16 16:19:53 +0200396 ClientResponse response = requestTokenWithAuthorizationCodeAndForm(
397 confidentialClientId, "wrong_secret", code);
margarethabe4c5c92018-05-03 18:55:49 +0200398 String entity = response.getEntity(String.class);
399 JsonNode node = JsonUtils.readTree(entity);
400 assertEquals(OAuth2Error.INVALID_CLIENT, node.at("/error").asText());
401 }
402
403 private void testRequestTokenAuthorizationInvalidRedirectUri (String code)
404 throws KustvaktException {
405 MultivaluedMap<String, String> tokenForm = new MultivaluedMapImpl();
406 tokenForm.add("grant_type", "authorization_code");
margarethaf0085122018-08-16 16:19:53 +0200407 tokenForm.add("client_id", confidentialClientId);
margarethabe4c5c92018-05-03 18:55:49 +0200408 tokenForm.add("client_secret", "secret");
409 tokenForm.add("code", code);
410 tokenForm.add("redirect_uri", "https://blahblah.com");
411
412 ClientResponse response = requestToken(tokenForm);
413 String entity = response.getEntity(String.class);
414 JsonNode node = JsonUtils.readTree(entity);
415 assertEquals(OAuth2Error.INVALID_GRANT, node.at("/error").asText());
416 }
417
418 private void testRequestTokenAuthorizationRevoked (String code, String uri)
419 throws KustvaktException {
420 MultivaluedMap<String, String> tokenForm = new MultivaluedMapImpl();
421 tokenForm.add("grant_type", "authorization_code");
margarethaf0085122018-08-16 16:19:53 +0200422 tokenForm.add("client_id", confidentialClientId);
margarethabe4c5c92018-05-03 18:55:49 +0200423 tokenForm.add("client_secret", "secret");
424 tokenForm.add("code", code);
425 tokenForm.add("redirect_uri", uri);
426
427 ClientResponse response = requestToken(tokenForm);
428 String entity = response.getEntity(String.class);
429 JsonNode node = JsonUtils.readTree(entity);
430 assertEquals(OAuthError.TokenResponse.INVALID_GRANT,
431 node.at("/error").asText());
432 assertEquals("Invalid authorization",
433 node.at("/error_description").asText());
434 }
435
margarethaa452c5e2018-04-25 22:48:09 +0200436 @Test
margarethaf0085122018-08-16 16:19:53 +0200437 public void testRequestTokenPasswordGrantConfidentialSuper ()
margarethafb027f92018-04-23 20:00:13 +0200438 throws KustvaktException {
margarethaf0085122018-08-16 16:19:53 +0200439 ClientResponse response =
margaretha230effb2018-11-29 17:28:18 +0100440 requestTokenWithDoryPassword(superClientId, clientSecret);
margaretha6374f722018-04-17 18:45:57 +0200441
margarethaf0085122018-08-16 16:19:53 +0200442 assertEquals(Status.OK.getStatusCode(), response.getStatus());
443
margaretha6374f722018-04-17 18:45:57 +0200444 String entity = response.getEntity(String.class);
margaretha6374f722018-04-17 18:45:57 +0200445 JsonNode node = JsonUtils.readTree(entity);
446 assertNotNull(node.at("/access_token").asText());
margaretha6374f722018-04-17 18:45:57 +0200447 assertEquals(TokenType.BEARER.toString(),
448 node.at("/token_type").asText());
449 assertNotNull(node.at("/expires_in").asText());
margaretha35074692021-03-26 18:11:59 +0100450
margaretha977fabe2022-04-28 09:23:47 +0200451 String refresh = node.at("/refresh_token").asText();
452 RefreshToken refreshToken =
453 refreshTokenDao.retrieveRefreshToken(refresh);
margaretha93e602e2019-08-07 15:19:56 +0200454 Set<AccessScope> scopes = refreshToken.getScopes();
455 assertEquals(1, scopes.size());
456 assertEquals("[all]", scopes.toString());
margaretha977fabe2022-04-28 09:23:47 +0200457
458 testRefreshTokenExpiry(refresh);
margaretha6374f722018-04-17 18:45:57 +0200459 }
460
461 @Test
margarethaf0085122018-08-16 16:19:53 +0200462 public void testRequestTokenPasswordGrantConfidentialNonSuper ()
463 throws KustvaktException {
margaretha35074692021-03-26 18:11:59 +0100464 ClientResponse response = requestTokenWithDoryPassword(
465 confidentialClientId, clientSecret);
margarethaf0085122018-08-16 16:19:53 +0200466 String entity = response.getEntity(String.class);
467 assertEquals(Status.UNAUTHORIZED.getStatusCode(), response.getStatus());
468
469 JsonNode node = JsonUtils.readTree(entity);
470 assertEquals(OAuthError.TokenResponse.UNAUTHORIZED_CLIENT,
471 node.at("/error").asText());
472 assertEquals("Password grant is not allowed for third party clients",
473 node.at("/error_description").asText());
474 }
475
476 @Test
477 public void testRequestTokenPasswordGrantPublic ()
478 throws KustvaktException {
margaretha35074692021-03-26 18:11:59 +0100479 ClientResponse response =
480 requestTokenWithDoryPassword(publicClientId, "");
margarethaf0085122018-08-16 16:19:53 +0200481 String entity = response.getEntity(String.class);
482
483 assertEquals(Status.UNAUTHORIZED.getStatusCode(), response.getStatus());
484
485 JsonNode node = JsonUtils.readTree(entity);
486 assertEquals(OAuth2Error.UNAUTHORIZED_CLIENT,
487 node.at("/error").asText());
488 assertEquals("Password grant is not allowed for third party clients",
489 node.at("/error_description").asText());
490 }
491
492 @Test
margaretha00c28c02018-07-05 18:09:09 +0200493 public void testRequestTokenPasswordGrantAuthorizationHeader ()
494 throws KustvaktException {
495 MultivaluedMap<String, String> form = new MultivaluedMapImpl();
496 form.add("grant_type", "password");
margarethaf0085122018-08-16 16:19:53 +0200497 form.add("client_id", superClientId);
margaretha00c28c02018-07-05 18:09:09 +0200498 form.add("username", "dory");
499 form.add("password", "password");
500
margaretha35074692021-03-26 18:11:59 +0100501 ClientResponse response =
502 resource().path(API_VERSION).path("oauth2").path("token")
503 .header(HttpHeaders.AUTHORIZATION,
504 "Basic ZkNCYlFrQXlZekk0TnpVeE1nOnNlY3JldA==")
505 .header(HttpHeaders.CONTENT_TYPE,
506 ContentType.APPLICATION_FORM_URLENCODED)
507 .entity(form).post(ClientResponse.class);
margaretha00c28c02018-07-05 18:09:09 +0200508 String entity = response.getEntity(String.class);
margaretha00c28c02018-07-05 18:09:09 +0200509 JsonNode node = JsonUtils.readTree(entity);
510 assertNotNull(node.at("/access_token").asText());
511 assertNotNull(node.at("/refresh_token").asText());
512 assertEquals(TokenType.BEARER.toString(),
513 node.at("/token_type").asText());
514 assertNotNull(node.at("/expires_in").asText());
515 }
516
margaretha0a45be12018-07-12 15:06:30 +0200517 /**
518 * In case, client_id is specified both in Authorization header
519 * and request body, client_id in the request body is ignored.
520 *
521 * @throws KustvaktException
522 */
523 @Test
524 public void testRequestTokenPasswordGrantDifferentClientIds ()
525 throws KustvaktException {
526 MultivaluedMap<String, String> form = new MultivaluedMapImpl();
527 form.add("grant_type", "password");
528 form.add("client_id", "9aHsGW6QflV13ixNpez");
529 form.add("username", "dory");
530 form.add("password", "password");
531
margaretha35074692021-03-26 18:11:59 +0100532 ClientResponse response =
533 resource().path(API_VERSION).path("oauth2").path("token")
534 .header(HttpHeaders.AUTHORIZATION,
535 "Basic ZkNCYlFrQXlZekk0TnpVeE1nOnNlY3JldA==")
536 .header(HttpHeaders.CONTENT_TYPE,
537 ContentType.APPLICATION_FORM_URLENCODED)
538 .entity(form).post(ClientResponse.class);
margaretha0a45be12018-07-12 15:06:30 +0200539 String entity = response.getEntity(String.class);
540 JsonNode node = JsonUtils.readTree(entity);
541 assertNotNull(node.at("/access_token").asText());
542 assertNotNull(node.at("/refresh_token").asText());
543 assertEquals(TokenType.BEARER.toString(),
544 node.at("/token_type").asText());
545 assertNotNull(node.at("/expires_in").asText());
546 }
547
margaretha00c28c02018-07-05 18:09:09 +0200548 @Test
margarethafb027f92018-04-23 20:00:13 +0200549 public void testRequestTokenPasswordGrantMissingClientSecret ()
550 throws KustvaktException {
margarethaf0085122018-08-16 16:19:53 +0200551 ClientResponse response =
margaretha230effb2018-11-29 17:28:18 +0100552 requestTokenWithDoryPassword(confidentialClientId, "");
margarethafb027f92018-04-23 20:00:13 +0200553 assertEquals(Status.BAD_REQUEST.getStatusCode(), response.getStatus());
margaretha6374f722018-04-17 18:45:57 +0200554
555 String entity = response.getEntity(String.class);
556 JsonNode node = JsonUtils.readTree(entity);
margarethafb027f92018-04-23 20:00:13 +0200557 assertEquals(OAuthError.TokenResponse.INVALID_REQUEST,
margaretha6374f722018-04-17 18:45:57 +0200558 node.at("/error").asText());
margaretha7da23902022-05-02 08:38:45 +0200559 assertEquals("Missing parameter: client_secret",
margarethafb027f92018-04-23 20:00:13 +0200560 node.at("/error_description").asText());
margaretha6374f722018-04-17 18:45:57 +0200561 }
562
563 @Test
564 public void testRequestTokenPasswordGrantMissingClientId ()
margarethafb027f92018-04-23 20:00:13 +0200565 throws KustvaktException {
margaretha35074692021-03-26 18:11:59 +0100566 ClientResponse response =
567 requestTokenWithDoryPassword(null, clientSecret);
margaretha6374f722018-04-17 18:45:57 +0200568 String entity = response.getEntity(String.class);
569 assertEquals(Status.BAD_REQUEST.getStatusCode(), response.getStatus());
570
571 JsonNode node = JsonUtils.readTree(entity);
572 assertEquals(OAuthError.TokenResponse.INVALID_REQUEST,
573 node.at("/error").asText());
margarethafb027f92018-04-23 20:00:13 +0200574 assertEquals("Missing parameters: client_id",
margaretha6374f722018-04-17 18:45:57 +0200575 node.at("/error_description").asText());
576 }
margarethabe4c5c92018-05-03 18:55:49 +0200577
margarethafb027f92018-04-23 20:00:13 +0200578 @Test
margarethaf839dde2018-04-16 17:52:57 +0200579 public void testRequestTokenClientCredentialsGrant ()
margarethafb027f92018-04-23 20:00:13 +0200580 throws KustvaktException {
margarethaf839dde2018-04-16 17:52:57 +0200581
582 MultivaluedMap<String, String> form = new MultivaluedMapImpl();
583 form.add("grant_type", "client_credentials");
margarethaf0085122018-08-16 16:19:53 +0200584 form.add("client_id", confidentialClientId);
margarethafb027f92018-04-23 20:00:13 +0200585 form.add("client_secret", "secret");
586 ClientResponse response = requestToken(form);
margarethaf839dde2018-04-16 17:52:57 +0200587 String entity = response.getEntity(String.class);
588 assertEquals(Status.OK.getStatusCode(), response.getStatus());
589
590 JsonNode node = JsonUtils.readTree(entity);
591 // length?
592 assertNotNull(node.at("/access_token").asText());
593 assertNotNull(node.at("/refresh_token").asText());
594 assertEquals(TokenType.BEARER.toString(),
595 node.at("/token_type").asText());
596 assertNotNull(node.at("/expires_in").asText());
597 }
598
margarethadc515072018-08-03 17:01:19 +0200599 /**
600 * Client credentials grant is only allowed for confidential
601 * clients.
602 */
603 @Test
604 public void testRequestTokenClientCredentialsGrantPublic ()
605 throws KustvaktException {
606
607 MultivaluedMap<String, String> form = new MultivaluedMapImpl();
608 form.add("grant_type", "client_credentials");
margarethaf0085122018-08-16 16:19:53 +0200609 form.add("client_id", publicClientId);
margarethadc515072018-08-03 17:01:19 +0200610 form.add("client_secret", "");
611 ClientResponse response = requestToken(form);
612
613 String entity = response.getEntity(String.class);
614 assertEquals(Status.BAD_REQUEST.getStatusCode(), response.getStatus());
615 JsonNode node = JsonUtils.readTree(entity);
616 assertEquals(OAuthError.TokenResponse.INVALID_REQUEST,
617 node.at("/error").asText());
618 assertEquals("Missing parameters: client_secret",
619 node.at("/error_description").asText());
620 }
621
margarethaf839dde2018-04-16 17:52:57 +0200622 @Test
margarethabe4c5c92018-05-03 18:55:49 +0200623 public void testRequestTokenClientCredentialsGrantReducedScope ()
624 throws KustvaktException {
625
626 MultivaluedMap<String, String> form = new MultivaluedMapImpl();
627 form.add("grant_type", "client_credentials");
margarethaf0085122018-08-16 16:19:53 +0200628 form.add("client_id", confidentialClientId);
margarethabe4c5c92018-05-03 18:55:49 +0200629 form.add("client_secret", "secret");
margaretha9c78e1a2018-06-27 14:12:35 +0200630 form.add("scope", "preferred_username client_info");
margarethabe4c5c92018-05-03 18:55:49 +0200631
632 ClientResponse response = requestToken(form);
633 String entity = response.getEntity(String.class);
634 assertEquals(Status.OK.getStatusCode(), response.getStatus());
635
636 JsonNode node = JsonUtils.readTree(entity);
637 // length?
638 assertNotNull(node.at("/access_token").asText());
639 assertNotNull(node.at("/refresh_token").asText());
640 assertEquals(TokenType.BEARER.toString(),
641 node.at("/token_type").asText());
642 assertNotNull(node.at("/expires_in").asText());
margaretha9c78e1a2018-06-27 14:12:35 +0200643 assertEquals("client_info", node.at("/scope").asText());
margarethabe4c5c92018-05-03 18:55:49 +0200644 }
645
646 @Test
margarethafb027f92018-04-23 20:00:13 +0200647 public void testRequestTokenMissingGrantType () throws KustvaktException {
margarethaf839dde2018-04-16 17:52:57 +0200648 MultivaluedMap<String, String> form = new MultivaluedMapImpl();
margarethafb027f92018-04-23 20:00:13 +0200649 ClientResponse response = requestToken(form);
margarethaf839dde2018-04-16 17:52:57 +0200650 assertEquals(Status.BAD_REQUEST.getStatusCode(), response.getStatus());
651
652 String entity = response.getEntity(String.class);
653 JsonNode node = JsonUtils.readTree(entity);
654 assertEquals(OAuthError.TokenResponse.INVALID_REQUEST,
655 node.at("/error").asText());
656 }
margarethaa0486272018-04-12 19:59:31 +0200657
658 @Test
margarethafb027f92018-04-23 20:00:13 +0200659 public void testRequestTokenUnsupportedGrant () throws KustvaktException {
margarethaa0486272018-04-12 19:59:31 +0200660
661 MultivaluedMap<String, String> form = new MultivaluedMapImpl();
margaretha05122312018-04-16 15:01:34 +0200662 form.add("grant_type", "blahblah");
663
margaretha35074692021-03-26 18:11:59 +0100664 ClientResponse response =
665 resource().path(API_VERSION).path("oauth2").path("token")
666 .header(HttpHeaders.X_FORWARDED_FOR, "149.27.0.32")
667 .header(HttpHeaders.CONTENT_TYPE,
668 ContentType.APPLICATION_FORM_URLENCODED)
669 .entity(form).post(ClientResponse.class);
margarethaa0486272018-04-12 19:59:31 +0200670
margaretha05122312018-04-16 15:01:34 +0200671 String entity = response.getEntity(String.class);
margaretha05122312018-04-16 15:01:34 +0200672 assertEquals(Status.BAD_REQUEST.getStatusCode(), response.getStatus());
673
674 JsonNode node = JsonUtils.readTree(entity);
margarethaf839dde2018-04-16 17:52:57 +0200675 assertEquals("Invalid grant_type parameter value",
margaretha05122312018-04-16 15:01:34 +0200676 node.get("error_description").asText());
margarethaf839dde2018-04-16 17:52:57 +0200677 assertEquals(OAuthError.TokenResponse.INVALID_REQUEST,
678 node.get("error").asText());
margarethaa0486272018-04-12 19:59:31 +0200679 }
680
margaretha03b82862018-07-12 20:09:26 +0200681 private void testRequestRefreshTokenInvalidScope (String clientId,
682 String refreshToken) throws KustvaktException {
683 MultivaluedMap<String, String> form = new MultivaluedMapImpl();
684 form.add("grant_type", GrantType.REFRESH_TOKEN.toString());
685 form.add("client_id", clientId);
margaretha0afd44a2020-02-05 10:49:21 +0100686 form.add("client_secret", clientSecret);
margaretha03b82862018-07-12 20:09:26 +0200687 form.add("refresh_token", refreshToken);
688 form.add("scope", "search serialize_query");
689
margaretha35074692021-03-26 18:11:59 +0100690 ClientResponse response =
691 resource().path(API_VERSION).path("oauth2").path("token")
692 .header(HttpHeaders.X_FORWARDED_FOR, "149.27.0.32")
693 .header(HttpHeaders.CONTENT_TYPE,
694 ContentType.APPLICATION_FORM_URLENCODED)
695 .entity(form).post(ClientResponse.class);
margaretha03b82862018-07-12 20:09:26 +0200696
697 String entity = response.getEntity(String.class);
698 JsonNode node = JsonUtils.readTree(entity);
699 assertEquals(OAuth2Error.INVALID_SCOPE, node.at("/error").asText());
700 }
701
margaretha35074692021-03-26 18:11:59 +0100702 private void testRequestRefreshToken (String clientId, String clientSecret,
margaretha03b82862018-07-12 20:09:26 +0200703 String refreshToken) throws KustvaktException {
704 MultivaluedMap<String, String> form = new MultivaluedMapImpl();
705 form.add("grant_type", GrantType.REFRESH_TOKEN.toString());
706 form.add("client_id", clientId);
margaretha35074692021-03-26 18:11:59 +0100707 form.add("client_secret", clientSecret);
margaretha03b82862018-07-12 20:09:26 +0200708 form.add("refresh_token", refreshToken);
709
margaretha35074692021-03-26 18:11:59 +0100710 ClientResponse response =
711 resource().path(API_VERSION).path("oauth2").path("token")
712 .header(HttpHeaders.X_FORWARDED_FOR, "149.27.0.32")
713 .header(HttpHeaders.CONTENT_TYPE,
714 ContentType.APPLICATION_FORM_URLENCODED)
715 .entity(form).post(ClientResponse.class);
margaretha03b82862018-07-12 20:09:26 +0200716
717 String entity = response.getEntity(String.class);
718 assertEquals(Status.OK.getStatusCode(), response.getStatus());
719
720 JsonNode node = JsonUtils.readTree(entity);
721 assertNotNull(node.at("/access_token").asText());
margaretha9436ebe2022-04-22 11:48:37 +0200722
margaretha35074692021-03-26 18:11:59 +0100723 String newRefreshToken = node.at("/refresh_token").asText();
724 assertNotNull(newRefreshToken);
margaretha03b82862018-07-12 20:09:26 +0200725 assertEquals(TokenType.BEARER.toString(),
726 node.at("/token_type").asText());
727 assertNotNull(node.at("/expires_in").asText());
margaretha6f0b7382018-11-21 17:42:02 +0100728
margaretha35074692021-03-26 18:11:59 +0100729 assertTrue(!newRefreshToken.equals(refreshToken));
margaretha9436ebe2022-04-22 11:48:37 +0200730
margaretha35074692021-03-26 18:11:59 +0100731 testRequestTokenWithRevokedRefreshToken(clientId, clientSecret,
732 refreshToken);
margaretha9436ebe2022-04-22 11:48:37 +0200733
margaretha35074692021-03-26 18:11:59 +0100734 testRevokeToken(newRefreshToken, clientId, clientSecret,
735 REFRESH_TOKEN_TYPE);
736 testRequestTokenWithRevokedRefreshToken(clientId, clientSecret,
737 newRefreshToken);
margaretha03b82862018-07-12 20:09:26 +0200738 }
739
740 private void testRequestRefreshTokenInvalidClient (String refreshToken)
741 throws KustvaktException {
742 MultivaluedMap<String, String> form = new MultivaluedMapImpl();
743 form.add("grant_type", GrantType.REFRESH_TOKEN.toString());
margaretha835178d2018-08-15 19:04:03 +0200744 form.add("client_id", "iBr3LsTCxOj7D2o0A5m");
margaretha03b82862018-07-12 20:09:26 +0200745 form.add("refresh_token", refreshToken);
746
margaretha35074692021-03-26 18:11:59 +0100747 ClientResponse response =
748 resource().path(API_VERSION).path("oauth2").path("token")
749 .header(HttpHeaders.X_FORWARDED_FOR, "149.27.0.32")
750 .header(HttpHeaders.CONTENT_TYPE,
751 ContentType.APPLICATION_FORM_URLENCODED)
752 .entity(form).post(ClientResponse.class);
margaretha03b82862018-07-12 20:09:26 +0200753
754 String entity = response.getEntity(String.class);
755 JsonNode node = JsonUtils.readTree(entity);
756 assertEquals(OAuth2Error.INVALID_CLIENT, node.at("/error").asText());
757 }
758
759 private void testRequestRefreshTokenInvalidRefreshToken (String clientId)
760 throws KustvaktException {
761 MultivaluedMap<String, String> form = new MultivaluedMapImpl();
762 form.add("grant_type", GrantType.REFRESH_TOKEN.toString());
763 form.add("client_id", clientId);
margaretha0afd44a2020-02-05 10:49:21 +0100764 form.add("client_secret", clientSecret);
margaretha03b82862018-07-12 20:09:26 +0200765 form.add("refresh_token", "Lia8s8w8tJeZSBlaQDrYV8ion3l");
766
margaretha35074692021-03-26 18:11:59 +0100767 ClientResponse response =
768 resource().path(API_VERSION).path("oauth2").path("token")
769 .header(HttpHeaders.X_FORWARDED_FOR, "149.27.0.32")
770 .header(HttpHeaders.CONTENT_TYPE,
771 ContentType.APPLICATION_FORM_URLENCODED)
772 .entity(form).post(ClientResponse.class);
margaretha03b82862018-07-12 20:09:26 +0200773
774 String entity = response.getEntity(String.class);
775 JsonNode node = JsonUtils.readTree(entity);
776 assertEquals(OAuth2Error.INVALID_GRANT, node.at("/error").asText());
777 }
778
margaretha35074692021-03-26 18:11:59 +0100779 private JsonNode requestTokenList (String userAuthHeader, String tokenType,
780 String clientId) throws KustvaktException {
781 MultivaluedMap<String, String> form = new MultivaluedMapImpl();
782 form.add("super_client_id", superClientId);
783 form.add("super_client_secret", clientSecret);
784 form.add("token_type", tokenType);
785
margaretha9436ebe2022-04-22 11:48:37 +0200786 if (clientId != null && !clientId.isEmpty()) {
margaretha35074692021-03-26 18:11:59 +0100787 form.add("client_id", clientId);
788 }
margaretha9436ebe2022-04-22 11:48:37 +0200789
margaretha35074692021-03-26 18:11:59 +0100790 ClientResponse response = resource().path(API_VERSION).path("oauth2")
791 .path("token").path("list")
792 .header(Attributes.AUTHORIZATION, userAuthHeader)
margarethadc515072018-08-03 17:01:19 +0200793 .header(HttpHeaders.CONTENT_TYPE,
794 ContentType.APPLICATION_FORM_URLENCODED)
795 .entity(form).post(ClientResponse.class);
margarethaf0085122018-08-16 16:19:53 +0200796
margarethadc515072018-08-03 17:01:19 +0200797 assertEquals(Status.OK.getStatusCode(), response.getStatus());
margaretha35074692021-03-26 18:11:59 +0100798
799 String entity = response.getEntity(String.class);
800 return JsonUtils.readTree(entity);
801 }
margaretha9436ebe2022-04-22 11:48:37 +0200802
margaretha35074692021-03-26 18:11:59 +0100803 private JsonNode requestTokenList (String userAuthHeader, String tokenType)
804 throws KustvaktException {
805 return requestTokenList(userAuthHeader, tokenType, null);
margaretha7497adf2019-11-26 13:13:57 +0100806 }
margaretha9436ebe2022-04-22 11:48:37 +0200807
margaretha43aceb52019-11-21 12:58:53 +0100808 @Test
margaretha9436ebe2022-04-22 11:48:37 +0200809 public void testListRefreshTokenConfidentialClient ()
810 throws KustvaktException {
margaretha43aceb52019-11-21 12:58:53 +0100811 String username = "gurgle";
812 String password = "pwd";
813 userAuthHeader = HttpAuthorizationHandler
814 .createBasicAuthorizationHeaderValue(username, password);
815
816 // super client
817 ClientResponse response = requestTokenWithPassword(superClientId,
818 clientSecret, username, password);
819 assertEquals(Status.OK.getStatusCode(), response.getStatus());
820 JsonNode node = JsonUtils.readTree(response.getEntity(String.class));
821 String refreshToken1 = node.at("/refresh_token").asText();
822
823 // client 1
margarethad67b4272022-04-11 17:34:19 +0200824 String code =
825 requestAuthorizationCode(confidentialClientId, userAuthHeader);
margaretha0afd44a2020-02-05 10:49:21 +0100826 response = requestTokenWithAuthorizationCodeAndForm(
827 confidentialClientId, clientSecret, code);
margaretha43aceb52019-11-21 12:58:53 +0100828 assertEquals(Status.OK.getStatusCode(), response.getStatus());
829
830 // client 2
margarethad67b4272022-04-11 17:34:19 +0200831 code = requestAuthorizationCode(confidentialClientId2,
832 clientRedirectUri, userAuthHeader);
margaretha0afd44a2020-02-05 10:49:21 +0100833 response = requestTokenWithAuthorizationCodeAndForm(
margarethad67b4272022-04-11 17:34:19 +0200834 confidentialClientId2, clientSecret, code, clientRedirectUri);
margaretha0afd44a2020-02-05 10:49:21 +0100835 assertEquals(Status.OK.getStatusCode(), response.getStatus());
836
837 // list
margaretha35074692021-03-26 18:11:59 +0100838 node = requestTokenList(userAuthHeader, REFRESH_TOKEN_TYPE);
margaretha0afd44a2020-02-05 10:49:21 +0100839 assertEquals(2, node.size());
margaretha4f4b9ab2021-04-30 17:33:21 +0200840 assertEquals(confidentialClientId, node.at("/0/client_id").asText());
841 assertEquals(confidentialClientId2, node.at("/1/client_id").asText());
margaretha35074692021-03-26 18:11:59 +0100842
margaretha0afd44a2020-02-05 10:49:21 +0100843 // client 1
margarethad67b4272022-04-11 17:34:19 +0200844 code = requestAuthorizationCode(confidentialClientId, userAuthHeader);
margaretha43aceb52019-11-21 12:58:53 +0100845 response = requestTokenWithAuthorizationCodeAndForm(
846 confidentialClientId, clientSecret, code);
847 assertEquals(Status.OK.getStatusCode(), response.getStatus());
848
margaretha7497adf2019-11-26 13:13:57 +0100849 // another user
850 String darlaAuthHeader = HttpAuthorizationHandler
851 .createBasicAuthorizationHeaderValue("darla", "pwd");
margaretha35074692021-03-26 18:11:59 +0100852
853 // test listing clients
854 node = requestTokenList(darlaAuthHeader, REFRESH_TOKEN_TYPE);
855 assertEquals(0, node.size());
856
margaretha43aceb52019-11-21 12:58:53 +0100857 // client 1
margarethad67b4272022-04-11 17:34:19 +0200858 code = requestAuthorizationCode(confidentialClientId, darlaAuthHeader);
margaretha43aceb52019-11-21 12:58:53 +0100859 assertEquals(Status.OK.getStatusCode(), response.getStatus());
860 response = requestTokenWithAuthorizationCodeAndForm(
margaretha0afd44a2020-02-05 10:49:21 +0100861 confidentialClientId, clientSecret, code);
margaretha35074692021-03-26 18:11:59 +0100862
margaretha43aceb52019-11-21 12:58:53 +0100863 node = JsonUtils.readTree(response.getEntity(String.class));
864 String refreshToken5 = node.at("/refresh_token").asText();
margaretha35074692021-03-26 18:11:59 +0100865
866 // list all refresh tokens
867 node = requestTokenList(userAuthHeader, REFRESH_TOKEN_TYPE);
margaretha43aceb52019-11-21 12:58:53 +0100868 assertEquals(3, node.size());
margaretha35074692021-03-26 18:11:59 +0100869
870 // list refresh tokens from client 1
margaretha9436ebe2022-04-22 11:48:37 +0200871 node = requestTokenList(userAuthHeader, REFRESH_TOKEN_TYPE,
872 confidentialClientId);
margaretha35074692021-03-26 18:11:59 +0100873 assertEquals(2, node.size());
margaretha9436ebe2022-04-22 11:48:37 +0200874
margaretha43aceb52019-11-21 12:58:53 +0100875 testRevokeToken(refreshToken1, superClientId, clientSecret,
876 REFRESH_TOKEN_TYPE);
margaretha35074692021-03-26 18:11:59 +0100877 testRevokeToken(node.at("/0/token").asText(), confidentialClientId,
margaretha0afd44a2020-02-05 10:49:21 +0100878 clientSecret, REFRESH_TOKEN_TYPE);
879 testRevokeToken(node.at("/1/token").asText(), confidentialClientId2,
margaretha43aceb52019-11-21 12:58:53 +0100880 clientSecret, REFRESH_TOKEN_TYPE);
margaretha35074692021-03-26 18:11:59 +0100881
882 node = requestTokenList(userAuthHeader, REFRESH_TOKEN_TYPE);
margaretha43aceb52019-11-21 12:58:53 +0100883 assertEquals(1, node.size());
margaretha35074692021-03-26 18:11:59 +0100884
885 testRevokeTokenViaSuperClient(node.at("/0/token").asText(),
886 userAuthHeader);
887 node = requestTokenList(userAuthHeader, REFRESH_TOKEN_TYPE);
margaretha7497adf2019-11-26 13:13:57 +0100888 assertEquals(0, node.size());
margaretha35074692021-03-26 18:11:59 +0100889
margaretha7497adf2019-11-26 13:13:57 +0100890 // try revoking a token belonging to another user
891 // should not return any errors
892 testRevokeTokenViaSuperClient(refreshToken5, userAuthHeader);
margaretha35074692021-03-26 18:11:59 +0100893 node = requestTokenList(darlaAuthHeader, REFRESH_TOKEN_TYPE);
margaretha7497adf2019-11-26 13:13:57 +0100894 assertEquals(1, node.size());
margaretha35074692021-03-26 18:11:59 +0100895
margaretha7497adf2019-11-26 13:13:57 +0100896 testRevokeTokenViaSuperClient(refreshToken5, darlaAuthHeader);
margaretha35074692021-03-26 18:11:59 +0100897 node = requestTokenList(darlaAuthHeader, REFRESH_TOKEN_TYPE);
margaretha7497adf2019-11-26 13:13:57 +0100898 assertEquals(0, node.size());
margaretha43aceb52019-11-21 12:58:53 +0100899 }
margaretha43aceb52019-11-21 12:58:53 +0100900
margaretha35074692021-03-26 18:11:59 +0100901 @Test
902 public void testListTokenPublicClient () throws KustvaktException {
903 String username = "nemo";
904 String password = "pwd";
905 userAuthHeader = HttpAuthorizationHandler
906 .createBasicAuthorizationHeaderValue(username, password);
907
908 // access token 1
margarethad67b4272022-04-11 17:34:19 +0200909 String code = requestAuthorizationCode(publicClientId, userAuthHeader);
margaretha9436ebe2022-04-22 11:48:37 +0200910 ClientResponse response = requestTokenWithAuthorizationCodeAndForm(
911 publicClientId, "", code);
margaretha43aceb52019-11-21 12:58:53 +0100912 assertEquals(Status.OK.getStatusCode(), response.getStatus());
margaretha35074692021-03-26 18:11:59 +0100913 JsonNode node = JsonUtils.readTree(response.getEntity(String.class));
914 String accessToken1 = node.at("/access_token").asText();
margaretha43aceb52019-11-21 12:58:53 +0100915
margaretha35074692021-03-26 18:11:59 +0100916 // access token 2
margarethad67b4272022-04-11 17:34:19 +0200917 code = requestAuthorizationCode(publicClientId, userAuthHeader);
margaretha35074692021-03-26 18:11:59 +0100918 response = requestTokenWithAuthorizationCodeAndForm(publicClientId, "",
919 code);
920 assertEquals(Status.OK.getStatusCode(), response.getStatus());
921 node = JsonUtils.readTree(response.getEntity(String.class));
922 String accessToken2 = node.at("/access_token").asText();
margaretha9436ebe2022-04-22 11:48:37 +0200923
margaretha35074692021-03-26 18:11:59 +0100924 // list access tokens
925 node = requestTokenList(userAuthHeader, ACCESS_TOKEN_TYPE);
926 assertEquals(2, node.size());
margaretha9436ebe2022-04-22 11:48:37 +0200927
margaretha35074692021-03-26 18:11:59 +0100928 // list refresh tokens
929 node = requestTokenList(userAuthHeader, REFRESH_TOKEN_TYPE);
930 assertEquals(0, node.size());
margaretha9436ebe2022-04-22 11:48:37 +0200931
margaretha35074692021-03-26 18:11:59 +0100932 testRevokeTokenViaSuperClient(accessToken1, userAuthHeader);
933 node = requestTokenList(userAuthHeader, ACCESS_TOKEN_TYPE);
margaretha9436ebe2022-04-22 11:48:37 +0200934 // System.out.println(node);
margaretha35074692021-03-26 18:11:59 +0100935 assertEquals(1, node.size());
margaretha4f4b9ab2021-04-30 17:33:21 +0200936 assertEquals(accessToken2, node.at("/0/token").asText());
margaretha9436ebe2022-04-22 11:48:37 +0200937 assertTrue(node.at("/0/scope").size() > 0);
margaretha4f4b9ab2021-04-30 17:33:21 +0200938 assertNotNull(node.at("/0/created_date").asText());
939 assertNotNull(node.at("/0/expires_in").asLong());
940 assertNotNull(node.at("/0/user_authentication_time").asText());
margaretha9436ebe2022-04-22 11:48:37 +0200941
margaretha4f4b9ab2021-04-30 17:33:21 +0200942 assertEquals(publicClientId, node.at("/0/client_id").asText());
943 assertNotNull(node.at("/0/client_name").asText());
944 assertNotNull(node.at("/0/client_description").asText());
945 assertNotNull(node.at("/0/client_url").asText());
margaretha9436ebe2022-04-22 11:48:37 +0200946
margaretha35074692021-03-26 18:11:59 +0100947 testRevokeTokenViaSuperClient(accessToken2, userAuthHeader);
948 node = requestTokenList(userAuthHeader, ACCESS_TOKEN_TYPE);
949 assertEquals(0, node.size());
margaretha43aceb52019-11-21 12:58:53 +0100950 }
margaretha977fabe2022-04-28 09:23:47 +0200951
952 private void testRefreshTokenExpiry (String refreshToken)
953 throws KustvaktException {
954 RefreshToken token = refreshTokenDao.retrieveRefreshToken(refreshToken);
955 ZonedDateTime expiry = token.getCreatedDate().plusYears(1);
956 assertTrue(expiry.equals(token.getExpiryDate()));
957 }
margarethaa0486272018-04-12 19:59:31 +0200958}