blob: 2ee4bc294392d8a4defb1e3da86db86e816dbf01 [file] [log] [blame]
margaretha31a9f522018-04-03 20:40:45 +02001package de.ids_mannheim.korap.web.controller;
2
3import static org.junit.Assert.assertEquals;
margaretha0e8f4e72018-04-05 14:11:52 +02004import static org.junit.Assert.assertNotNull;
margaretha8d804f62018-04-10 12:39:56 +02005import static org.junit.Assert.assertTrue;
6
margaretha05122312018-04-16 15:01:34 +02007import java.util.List;
margaretha05122312018-04-16 15:01:34 +02008import java.util.Map.Entry;
margarethaf839dde2018-04-16 17:52:57 +02009import java.util.Set;
margaretha05122312018-04-16 15:01:34 +020010
margaretha8d804f62018-04-10 12:39:56 +020011import javax.ws.rs.core.MultivaluedMap;
margaretha31a9f522018-04-03 20:40:45 +020012
13import org.apache.http.entity.ContentType;
14import org.junit.Test;
15
margaretha0e8f4e72018-04-05 14:11:52 +020016import com.fasterxml.jackson.databind.JsonNode;
margaretha31a9f522018-04-03 20:40:45 +020017import com.google.common.net.HttpHeaders;
margaretha8d804f62018-04-10 12:39:56 +020018import com.sun.jersey.api.client.ClientHandlerException;
margaretha31a9f522018-04-03 20:40:45 +020019import com.sun.jersey.api.client.ClientResponse;
20import com.sun.jersey.api.client.ClientResponse.Status;
margaretha8d804f62018-04-10 12:39:56 +020021import com.sun.jersey.api.client.UniformInterfaceException;
22import com.sun.jersey.core.util.MultivaluedMapImpl;
margaretha05122312018-04-16 15:01:34 +020023import com.sun.jersey.spi.container.ContainerRequest;
margaretha31a9f522018-04-03 20:40:45 +020024
margaretha0e8f4e72018-04-05 14:11:52 +020025import de.ids_mannheim.korap.authentication.http.HttpAuthorizationHandler;
26import de.ids_mannheim.korap.config.Attributes;
margaretha31a9f522018-04-03 20:40:45 +020027import de.ids_mannheim.korap.exceptions.KustvaktException;
margaretha80ea0dd2018-07-03 14:22:59 +020028import de.ids_mannheim.korap.exceptions.StatusCodes;
margarethaa452c5e2018-04-25 22:48:09 +020029import de.ids_mannheim.korap.oauth2.constant.OAuth2ClientType;
30import de.ids_mannheim.korap.oauth2.constant.OAuth2Error;
margaretha0e8f4e72018-04-05 14:11:52 +020031import de.ids_mannheim.korap.utils.JsonUtils;
margaretha31a9f522018-04-03 20:40:45 +020032import de.ids_mannheim.korap.web.input.OAuth2ClientJson;
33
margarethaa0486272018-04-12 19:59:31 +020034/**
35 * @author margaretha
36 *
37 */
margarethaf0085122018-08-16 16:19:53 +020038public class OAuth2ClientControllerTest extends OAuth2TestBase {
margaretha31a9f522018-04-03 20:40:45 +020039
margaretha0e8f4e72018-04-05 14:11:52 +020040 private String username = "OAuth2ClientControllerTest";
margarethaf0085122018-08-16 16:19:53 +020041 private String userAuthHeader;
42
43 public OAuth2ClientControllerTest () throws KustvaktException {
44 userAuthHeader = HttpAuthorizationHandler
45 .createBasicAuthorizationHeaderValue("dory", "password");
46 }
margaretha8d804f62018-04-10 12:39:56 +020047
margaretha05122312018-04-16 15:01:34 +020048 private void checkWWWAuthenticateHeader (ClientResponse response) {
49 Set<Entry<String, List<String>>> headers =
50 response.getHeaders().entrySet();
51
52 for (Entry<String, List<String>> header : headers) {
53 if (header.getKey().equals(ContainerRequest.WWW_AUTHENTICATE)) {
54 assertEquals("Basic realm=\"Kustvakt\"",
55 header.getValue().get(0));
56 }
57 }
58 }
margaretha7a09e482019-11-14 14:34:07 +010059
60 private ClientResponse registerClient (String username,
61 OAuth2ClientJson json) throws UniformInterfaceException,
62 ClientHandlerException, KustvaktException {
63 return resource().path(API_VERSION).path("oauth2").path("client")
64 .path("register")
65 .header(Attributes.AUTHORIZATION, HttpAuthorizationHandler
66 .createBasicAuthorizationHeaderValue(username, "password"))
67 .header(HttpHeaders.X_FORWARDED_FOR, "149.27.0.32")
68 .header(HttpHeaders.CONTENT_TYPE, ContentType.APPLICATION_JSON)
69 .entity(json).post(ClientResponse.class);
70 }
margaretha6374f722018-04-17 18:45:57 +020071
margaretha7f5071f2018-08-14 15:58:51 +020072 private ClientResponse registerConfidentialClient ()
margaretha8d804f62018-04-10 12:39:56 +020073 throws KustvaktException {
margaretha31a9f522018-04-03 20:40:45 +020074
75 OAuth2ClientJson json = new OAuth2ClientJson();
margaretha0e8f4e72018-04-05 14:11:52 +020076 json.setName("OAuth2ClientTest");
77 json.setType(OAuth2ClientType.CONFIDENTIAL);
margaretha31a9f522018-04-03 20:40:45 +020078 json.setUrl("http://example.client.com");
margarethaa0486272018-04-12 19:59:31 +020079 json.setRedirectURI("https://example.client.com/redirect");
margarethafb027f92018-04-23 20:00:13 +020080 json.setDescription("This is a confidential test client.");
margaretha31a9f522018-04-03 20:40:45 +020081
margaretha7a09e482019-11-14 14:34:07 +010082 return registerClient(username, json);
margaretha8d804f62018-04-10 12:39:56 +020083 }
84
margarethaf0085122018-08-16 16:19:53 +020085 private JsonNode retrieveClientInfo (String clientId, String username)
86 throws UniformInterfaceException, ClientHandlerException,
87 KustvaktException {
margaretha230effb2018-11-29 17:28:18 +010088 ClientResponse response = resource().path(API_VERSION).path("oauth2")
margarethac20cd342019-11-14 10:59:39 +010089 .path("client").path(clientId)
margarethaf0085122018-08-16 16:19:53 +020090 .header(Attributes.AUTHORIZATION, HttpAuthorizationHandler
91 .createBasicAuthorizationHeaderValue(username, "pass"))
92 .get(ClientResponse.class);
93
94 assertEquals(Status.OK.getStatusCode(), response.getStatus());
95
96 String entity = response.getEntity(String.class);
97 return JsonUtils.readTree(entity);
98 }
99
margaretha8d804f62018-04-10 12:39:56 +0200100 @Test
margaretha2ea9a1e2019-01-11 16:37:21 +0100101 public void testRetrieveClientInfo () throws KustvaktException {
102 // public client
103 JsonNode clientInfo = retrieveClientInfo(publicClientId, "system");
104 assertEquals(publicClientId, clientInfo.at("/id").asText());
105 assertEquals("third party client", clientInfo.at("/name").asText());
106 assertNotNull(clientInfo.at("/description"));
margarethac20cd342019-11-14 10:59:39 +0100107 assertNotNull(clientInfo.at("/url"));
margaretha2ea9a1e2019-01-11 16:37:21 +0100108 assertEquals("PUBLIC", clientInfo.at("/type").asText());
109
110 // confidential client
111 clientInfo = retrieveClientInfo(confidentialClientId, "system");
112 assertEquals(confidentialClientId, clientInfo.at("/id").asText());
113 assertEquals("non super confidential client", clientInfo.at("/name").asText());
margarethac20cd342019-11-14 10:59:39 +0100114 assertNotNull(clientInfo.at("/url"));
margaretha2ea9a1e2019-01-11 16:37:21 +0100115 assertEquals(false,clientInfo.at("/isSuper").asBoolean());
116 assertEquals("CONFIDENTIAL", clientInfo.at("/type").asText());
117
118 // super client
119 clientInfo = retrieveClientInfo(superClientId, "system");
120 assertEquals(superClientId, clientInfo.at("/id").asText());
121 assertEquals("super confidential client", clientInfo.at("/name").asText());
margarethac20cd342019-11-14 10:59:39 +0100122 assertNotNull(clientInfo.at("/url"));
margaretha2ea9a1e2019-01-11 16:37:21 +0100123 assertEquals("CONFIDENTIAL", clientInfo.at("/type").asText());
124 assertTrue(clientInfo.at("/isSuper").asBoolean());
125 }
126
127 @Test
margaretha7f5071f2018-08-14 15:58:51 +0200128 public void testRegisterConfidentialClient () throws KustvaktException {
129 ClientResponse response = registerConfidentialClient();
margaretha8d804f62018-04-10 12:39:56 +0200130 String entity = response.getEntity(String.class);
131 assertEquals(Status.OK.getStatusCode(), response.getStatus());
132 JsonNode node = JsonUtils.readTree(entity);
margarethafb1e0992018-04-10 14:58:28 +0200133 String clientId = node.at("/client_id").asText();
134 String clientSecret = node.at("/client_secret").asText();
135 assertNotNull(clientId);
136 assertNotNull(clientSecret);
margaretha8d804f62018-04-10 12:39:56 +0200137
margaretha7f5071f2018-08-14 15:58:51 +0200138 testRegisterClientNonUniqueURL();
139
140 String newclientSecret =
141 testResetConfidentialClientSecret(clientId, clientSecret);
margarethafb1e0992018-04-10 14:58:28 +0200142
margaretha80ea0dd2018-07-03 14:22:59 +0200143 testDeregisterConfidentialClientMissingSecret(clientId);
margaretha7f5071f2018-08-14 15:58:51 +0200144 testDeregisterClientIncorrectCredentials(clientId, clientSecret);
145 testDeregisterConfidentialClient(clientId, newclientSecret);
146 }
147
margaretha7f5071f2018-08-14 15:58:51 +0200148 private void testRegisterClientNonUniqueURL () throws KustvaktException {
149 ClientResponse response = registerConfidentialClient();
150 assertEquals(Status.BAD_REQUEST.getStatusCode(), response.getStatus());
151 JsonNode node = JsonUtils.readTree(response.getEntity(String.class));
152 assertEquals(OAuth2Error.INVALID_REQUEST, node.at("/error").asText());
margaretha8d804f62018-04-10 12:39:56 +0200153 }
154
155 @Test
margaretha21d32962019-11-14 17:08:15 +0100156 public void testRegisterClientNameTooShort ()
157 throws UniformInterfaceException, ClientHandlerException,
158 KustvaktException {
159 OAuth2ClientJson json = new OAuth2ClientJson();
160 json.setName("R");
161 json.setType(OAuth2ClientType.PUBLIC);
162
163 ClientResponse response = registerClient(username, json);
164 String entity = response.getEntity(String.class);
165 JsonNode node = JsonUtils.readTree(entity);
166 assertEquals(StatusCodes.INVALID_ARGUMENT,
167 node.at("/errors/0/0").asInt());
168 assertEquals("clientName must contain at least 3 characters",
169 node.at("/errors/0/1").asText());
170 assertEquals(Status.BAD_REQUEST.getStatusCode(), response.getStatus());
171 }
172
173 @Test
margaretha8d804f62018-04-10 12:39:56 +0200174 public void testRegisterPublicClient () throws UniformInterfaceException,
175 ClientHandlerException, KustvaktException {
176 OAuth2ClientJson json = new OAuth2ClientJson();
177 json.setName("OAuth2PublicClient");
178 json.setType(OAuth2ClientType.PUBLIC);
margarethaf839dde2018-04-16 17:52:57 +0200179 json.setUrl("http://test.public.client.com");
180 json.setRedirectURI("https://test.public.client.com/redirect");
margarethafb027f92018-04-23 20:00:13 +0200181 json.setDescription("This is a public test client.");
margaretha8d804f62018-04-10 12:39:56 +0200182
margaretha7a09e482019-11-14 14:34:07 +0100183 ClientResponse response = registerClient(username, json);
margaretha31a9f522018-04-03 20:40:45 +0200184
margaretha0e8f4e72018-04-05 14:11:52 +0200185 String entity = response.getEntity(String.class);
margaretha31a9f522018-04-03 20:40:45 +0200186 assertEquals(Status.OK.getStatusCode(), response.getStatus());
margaretha0e8f4e72018-04-05 14:11:52 +0200187 JsonNode node = JsonUtils.readTree(entity);
margaretha8d804f62018-04-10 12:39:56 +0200188 String clientId = node.at("/client_id").asText();
189 assertNotNull(clientId);
190 assertTrue(node.at("/client_secret").isMissingNode());
191
margaretha835178d2018-08-15 19:04:03 +0200192 testResetPublicClientSecret(clientId);
margarethaf0085122018-08-16 16:19:53 +0200193 testAccessTokenAfterDeregistration(clientId, null);
margaretha8d804f62018-04-10 12:39:56 +0200194 }
195
margaretha6374f722018-04-17 18:45:57 +0200196 @Test
margarethad7cab212018-07-02 19:01:43 +0200197 public void testRegisterDesktopApp () throws UniformInterfaceException,
198 ClientHandlerException, KustvaktException {
199 OAuth2ClientJson json = new OAuth2ClientJson();
200 json.setName("OAuth2DesktopClient");
201 json.setType(OAuth2ClientType.PUBLIC);
202 json.setDescription("This is a desktop test client.");
203
margaretha7a09e482019-11-14 14:34:07 +0100204 ClientResponse response = registerClient(username, json);
margarethad7cab212018-07-02 19:01:43 +0200205
206 String entity = response.getEntity(String.class);
207 assertEquals(Status.OK.getStatusCode(), response.getStatus());
208 JsonNode node = JsonUtils.readTree(entity);
209 String clientId = node.at("/client_id").asText();
210 assertNotNull(clientId);
211 assertTrue(node.at("/client_secret").isMissingNode());
margaretha7f5071f2018-08-14 15:58:51 +0200212
margaretha835178d2018-08-15 19:04:03 +0200213 testDeregisterPublicClientMissingUserAuthentication(clientId);
214 testDeregisterPublicClientMissingId();
margaretha7a09e482019-11-14 14:34:07 +0100215 testDeregisterPublicClient(clientId,username);
margaretha7f5071f2018-08-14 15:58:51 +0200216 }
margaretha21d32962019-11-14 17:08:15 +0100217
margarethaf0085122018-08-16 16:19:53 +0200218 private void testAccessTokenAfterDeregistration (String clientId,
219 String clientSecret) throws KustvaktException {
220 String userAuthHeader = HttpAuthorizationHandler
221 .createBasicAuthorizationHeaderValue("dory", "password");
222
223 String code =
224 requestAuthorizationCode(clientId, "", null, userAuthHeader);
margaretha230effb2018-11-29 17:28:18 +0100225 ClientResponse response = requestTokenWithAuthorizationCodeAndForm(
226 clientId, clientSecret, code);
margaretha7f5071f2018-08-14 15:58:51 +0200227 JsonNode node = JsonUtils.readTree(response.getEntity(String.class));
228 String accessToken = node.at("/access_token").asText();
229
230 response = searchWithAccessToken(accessToken);
231 assertEquals(Status.OK.getStatusCode(), response.getStatus());
232
margarethaf0085122018-08-16 16:19:53 +0200233 code = requestAuthorizationCode(clientId, "", null, userAuthHeader);
margaretha7a09e482019-11-14 14:34:07 +0100234 testDeregisterPublicClient(clientId, username);
margaretha7f5071f2018-08-14 15:58:51 +0200235
margarethaf0085122018-08-16 16:19:53 +0200236 response = requestTokenWithAuthorizationCodeAndForm(clientId,
237 clientSecret, code);
margaretha7f5071f2018-08-14 15:58:51 +0200238 assertEquals(Status.UNAUTHORIZED.getStatusCode(), response.getStatus());
239 node = JsonUtils.readTree(response.getEntity(String.class));
240 assertEquals(OAuth2Error.INVALID_CLIENT.toString(),
241 node.at("/error").asText());
242
243 response = searchWithAccessToken(accessToken);
244 assertEquals(Status.UNAUTHORIZED.getStatusCode(), response.getStatus());
245 node = JsonUtils.readTree(response.getEntity(String.class));
246 assertEquals(StatusCodes.INVALID_ACCESS_TOKEN,
247 node.at("/errors/0/0").asInt());
margaretha85273f12019-02-04 18:13:17 +0100248 assertEquals("Access token is invalid",
margaretha7f5071f2018-08-14 15:58:51 +0200249 node.at("/errors/0/1").asText());
margaretha6374f722018-04-17 18:45:57 +0200250 }
251
margaretha80ea0dd2018-07-03 14:22:59 +0200252 private void testDeregisterPublicClientMissingUserAuthentication (
253 String clientId) throws UniformInterfaceException,
254 ClientHandlerException, KustvaktException {
255
margaretha230effb2018-11-29 17:28:18 +0100256 ClientResponse response = resource().path(API_VERSION).path("oauth2")
257 .path("client").path("deregister").path(clientId)
258 .delete(ClientResponse.class);
margaretha80ea0dd2018-07-03 14:22:59 +0200259
260 assertEquals(Status.UNAUTHORIZED.getStatusCode(), response.getStatus());
261
262 String entity = response.getEntity(String.class);
263 JsonNode node = JsonUtils.readTree(entity);
264 assertEquals(StatusCodes.AUTHORIZATION_FAILED,
265 node.at("/errors/0/0").asInt());
266 }
267
268 private void testDeregisterPublicClientMissingId ()
269 throws UniformInterfaceException, ClientHandlerException,
270 KustvaktException {
271
margaretha230effb2018-11-29 17:28:18 +0100272 ClientResponse response = resource().path(API_VERSION).path("oauth2")
273 .path("client").path("deregister")
margaretha064eb6f2018-07-10 18:33:01 +0200274 .header(Attributes.AUTHORIZATION, HttpAuthorizationHandler
margaretha80ea0dd2018-07-03 14:22:59 +0200275 .createBasicAuthorizationHeaderValue(username, "pass"))
276 .delete(ClientResponse.class);
277
margarethac20cd342019-11-14 10:59:39 +0100278 assertEquals(Status.METHOD_NOT_ALLOWED.getStatusCode(), response.getStatus());
margaretha80ea0dd2018-07-03 14:22:59 +0200279 }
280
margaretha7a09e482019-11-14 14:34:07 +0100281 private void testDeregisterPublicClient (String clientId, String username)
margaretha8d804f62018-04-10 12:39:56 +0200282 throws UniformInterfaceException, ClientHandlerException,
283 KustvaktException {
284
margaretha230effb2018-11-29 17:28:18 +0100285 ClientResponse response = resource().path(API_VERSION).path("oauth2")
286 .path("client").path("deregister").path(clientId)
margaretha064eb6f2018-07-10 18:33:01 +0200287 .header(Attributes.AUTHORIZATION, HttpAuthorizationHandler
margaretha80ea0dd2018-07-03 14:22:59 +0200288 .createBasicAuthorizationHeaderValue(username, "pass"))
289 .delete(ClientResponse.class);
margaretha8d804f62018-04-10 12:39:56 +0200290
291 assertEquals(Status.OK.getStatusCode(), response.getStatus());
margaretha31a9f522018-04-03 20:40:45 +0200292 }
margarethafb1e0992018-04-10 14:58:28 +0200293
294 private void testDeregisterConfidentialClient (String clientId,
295 String clientSecret) throws UniformInterfaceException,
296 ClientHandlerException, KustvaktException {
margarethafb1e0992018-04-10 14:58:28 +0200297
margaretha80ea0dd2018-07-03 14:22:59 +0200298 MultivaluedMap<String, String> form = new MultivaluedMapImpl();
299 form.add("client_secret", clientSecret);
300
margaretha230effb2018-11-29 17:28:18 +0100301 ClientResponse response = resource().path(API_VERSION).path("oauth2")
302 .path("client").path("deregister").path(clientId)
margaretha064eb6f2018-07-10 18:33:01 +0200303 .header(Attributes.AUTHORIZATION, HttpAuthorizationHandler
304 .createBasicAuthorizationHeaderValue(username, "pass"))
margarethafb1e0992018-04-10 14:58:28 +0200305 .header(HttpHeaders.CONTENT_TYPE,
306 ContentType.APPLICATION_FORM_URLENCODED)
margaretha80ea0dd2018-07-03 14:22:59 +0200307 .entity(form).delete(ClientResponse.class);
margarethafb1e0992018-04-10 14:58:28 +0200308
309 assertEquals(Status.OK.getStatusCode(), response.getStatus());
310 }
311
margaretha80ea0dd2018-07-03 14:22:59 +0200312 private void testDeregisterConfidentialClientMissingSecret (String clientId)
margarethafb027f92018-04-23 20:00:13 +0200313 throws KustvaktException {
314
margaretha230effb2018-11-29 17:28:18 +0100315 ClientResponse response = resource().path(API_VERSION).path("oauth2")
316 .path("client").path("deregister").path(clientId)
margaretha064eb6f2018-07-10 18:33:01 +0200317 .header(Attributes.AUTHORIZATION, HttpAuthorizationHandler
318 .createBasicAuthorizationHeaderValue(username, "pass"))
margarethafb027f92018-04-23 20:00:13 +0200319 .header(HttpHeaders.CONTENT_TYPE,
320 ContentType.APPLICATION_FORM_URLENCODED)
321 .delete(ClientResponse.class);
322
323 String entity = response.getEntity(String.class);
324 assertEquals(Status.BAD_REQUEST.getStatusCode(), response.getStatus());
325
326 JsonNode node = JsonUtils.readTree(entity);
margarethad7cab212018-07-02 19:01:43 +0200327 assertEquals(OAuth2Error.INVALID_REQUEST, node.at("/error").asText());
margaretha80ea0dd2018-07-03 14:22:59 +0200328 assertEquals("Missing parameters: client_secret",
margarethafb027f92018-04-23 20:00:13 +0200329 node.at("/error_description").asText());
330 }
331
margaretha7f5071f2018-08-14 15:58:51 +0200332 private void testDeregisterClientIncorrectCredentials (String clientId,
333 String clientSecret) throws UniformInterfaceException,
334 ClientHandlerException, KustvaktException {
margarethafb1e0992018-04-10 14:58:28 +0200335
margaretha80ea0dd2018-07-03 14:22:59 +0200336 MultivaluedMap<String, String> form = new MultivaluedMapImpl();
margaretha7f5071f2018-08-14 15:58:51 +0200337 form.add("client_secret", clientSecret);
margaretha80ea0dd2018-07-03 14:22:59 +0200338
margaretha230effb2018-11-29 17:28:18 +0100339 ClientResponse response = resource().path(API_VERSION).path("oauth2")
340 .path("client").path("deregister").path(clientId)
margaretha064eb6f2018-07-10 18:33:01 +0200341 .header(Attributes.AUTHORIZATION, HttpAuthorizationHandler
342 .createBasicAuthorizationHeaderValue(username, "pass"))
margarethafb1e0992018-04-10 14:58:28 +0200343 .header(HttpHeaders.CONTENT_TYPE,
344 ContentType.APPLICATION_FORM_URLENCODED)
margaretha80ea0dd2018-07-03 14:22:59 +0200345 .entity(form).delete(ClientResponse.class);
margarethafb1e0992018-04-10 14:58:28 +0200346
margarethafb1e0992018-04-10 14:58:28 +0200347 String entity = response.getEntity(String.class);
margarethaa0486272018-04-12 19:59:31 +0200348 assertEquals(Status.UNAUTHORIZED.getStatusCode(), response.getStatus());
margaretha6374f722018-04-17 18:45:57 +0200349
margarethafb1e0992018-04-10 14:58:28 +0200350 JsonNode node = JsonUtils.readTree(entity);
margarethad7cab212018-07-02 19:01:43 +0200351 assertEquals(OAuth2Error.INVALID_CLIENT, node.at("/error").asText());
margarethafb027f92018-04-23 20:00:13 +0200352 assertEquals("Invalid client credentials",
margarethaa0486272018-04-12 19:59:31 +0200353 node.at("/error_description").asText());
margaretha6374f722018-04-17 18:45:57 +0200354
margaretha05122312018-04-16 15:01:34 +0200355 checkWWWAuthenticateHeader(response);
margarethafb1e0992018-04-10 14:58:28 +0200356 }
margaretha7f5071f2018-08-14 15:58:51 +0200357
358 private void testResetPublicClientSecret (String clientId)
359 throws UniformInterfaceException, ClientHandlerException,
360 KustvaktException {
361 MultivaluedMap<String, String> form = new MultivaluedMapImpl();
362 form.add("client_id", clientId);
363
margaretha230effb2018-11-29 17:28:18 +0100364 ClientResponse response = resource().path(API_VERSION).path("oauth2")
365 .path("client").path("reset")
margaretha7f5071f2018-08-14 15:58:51 +0200366 .header(Attributes.AUTHORIZATION, HttpAuthorizationHandler
367 .createBasicAuthorizationHeaderValue(username, "pass"))
368 .header(HttpHeaders.CONTENT_TYPE,
369 ContentType.APPLICATION_FORM_URLENCODED)
370 .entity(form).post(ClientResponse.class);
371
372 String entity = response.getEntity(String.class);
373 assertEquals(Status.BAD_REQUEST.getStatusCode(), response.getStatus());
374 JsonNode node = JsonUtils.readTree(entity);
375 assertEquals(OAuth2Error.INVALID_REQUEST, node.at("/error").asText());
376 assertEquals("Operation is not allowed for public clients",
377 node.at("/error_description").asText());
378 }
379
380 private String testResetConfidentialClientSecret (String clientId,
381 String clientSecret) throws UniformInterfaceException,
382 ClientHandlerException, KustvaktException {
383 MultivaluedMap<String, String> form = new MultivaluedMapImpl();
384 form.add("client_id", clientId);
385 form.add("client_secret", clientSecret);
386
margaretha230effb2018-11-29 17:28:18 +0100387 ClientResponse response = resource().path(API_VERSION).path("oauth2")
388 .path("client").path("reset")
margaretha7f5071f2018-08-14 15:58:51 +0200389 .header(Attributes.AUTHORIZATION, HttpAuthorizationHandler
390 .createBasicAuthorizationHeaderValue(username, "pass"))
391 .header(HttpHeaders.CONTENT_TYPE,
392 ContentType.APPLICATION_FORM_URLENCODED)
393 .entity(form).post(ClientResponse.class);
394
395 String entity = response.getEntity(String.class);
396 assertEquals(Status.OK.getStatusCode(), response.getStatus());
397
398 JsonNode node = JsonUtils.readTree(entity);
399 assertEquals(clientId, node.at("/client_id").asText());
400
401 String newClientSecret = node.at("/client_secret").asText();
402 assertTrue(!clientSecret.equals(newClientSecret));
403
404 return newClientSecret;
405 }
margaretha835178d2018-08-15 19:04:03 +0200406
407 @Test
408 public void testUpdateClientPrivilege () throws KustvaktException {
margarethaf0085122018-08-16 16:19:53 +0200409 // register a client
margaretha835178d2018-08-15 19:04:03 +0200410 ClientResponse response = registerConfidentialClient();
411 JsonNode node = JsonUtils.readTree(response.getEntity(String.class));
412 String clientId = node.at("/client_id").asText();
margarethaf0085122018-08-16 16:19:53 +0200413 String clientSecret = node.at("/client_secret").asText();
margaretha835178d2018-08-15 19:04:03 +0200414
margarethaf0085122018-08-16 16:19:53 +0200415 // request an access token
416 String clientAuthHeader = HttpAuthorizationHandler
417 .createBasicAuthorizationHeaderValue(clientId, clientSecret);
418 String code = requestAuthorizationCode(clientId, clientSecret, null,
419 userAuthHeader);
420 node = requestTokenWithAuthorizationCodeAndHeader(clientId, code,
421 clientAuthHeader);
422 String accessToken = node.at("/access_token").asText();
423
424 testAccessTokenAfterUpgradingClient(clientId, accessToken);
425 testAccessTokenAfterDegradingSuperClient(clientId, accessToken);
margaretha230effb2018-11-29 17:28:18 +0100426
margaretha9e53bb22018-09-14 19:39:15 +0200427 testDeregisterConfidentialClient(clientId, clientSecret);
margarethaf0085122018-08-16 16:19:53 +0200428 }
429
430 // old access tokens retain their scopes
431 private void testAccessTokenAfterUpgradingClient (String clientId,
432 String accessToken) throws KustvaktException {
margaretha835178d2018-08-15 19:04:03 +0200433 MultivaluedMap<String, String> form = new MultivaluedMapImpl();
434 form.add("client_id", clientId);
435 form.add("super", "true");
436
437 updateClientPrivilege(form);
margarethaf0085122018-08-16 16:19:53 +0200438 JsonNode node = retrieveClientInfo(clientId, "admin");
margaretha835178d2018-08-15 19:04:03 +0200439 assertTrue(node.at("/isSuper").asBoolean());
440
margarethaf0085122018-08-16 16:19:53 +0200441 // list vc
margaretha03b195a2019-11-12 14:57:15 +0100442 ClientResponse response = resource().path(API_VERSION).path("vc")
443 .header(Attributes.AUTHORIZATION, "Bearer " + accessToken)
444 .get(ClientResponse.class);
margaretha835178d2018-08-15 19:04:03 +0200445
margarethaf0085122018-08-16 16:19:53 +0200446 assertEquals(ClientResponse.Status.UNAUTHORIZED.getStatusCode(),
447 response.getStatus());
margaretha835178d2018-08-15 19:04:03 +0200448 String entity = response.getEntity(String.class);
margarethaf0085122018-08-16 16:19:53 +0200449 node = JsonUtils.readTree(entity);
450 assertEquals(StatusCodes.AUTHORIZATION_FAILED,
451 node.at("/errors/0/0").asInt());
452 assertEquals("Scope vc_info is not authorized",
453 node.at("/errors/0/1").asText());
margaretha230effb2018-11-29 17:28:18 +0100454
margarethaf0085122018-08-16 16:19:53 +0200455 // search
456 response = searchWithAccessToken(accessToken);
457 assertEquals(Status.OK.getStatusCode(), response.getStatus());
458 }
459
460 private void testAccessTokenAfterDegradingSuperClient (String clientId,
461 String accessToken) throws KustvaktException {
462 MultivaluedMap<String, String> form = new MultivaluedMapImpl();
463 form.add("client_id", clientId);
464 form.add("super", "false");
margaretha230effb2018-11-29 17:28:18 +0100465
margarethaf0085122018-08-16 16:19:53 +0200466 updateClientPrivilege(form);
467 JsonNode node = retrieveClientInfo(clientId, username);
468 assertTrue(node.at("/isSuper").isMissingNode());
469
470 ClientResponse response = searchWithAccessToken(accessToken);
471 assertEquals(ClientResponse.Status.UNAUTHORIZED.getStatusCode(),
472 response.getStatus());
margaretha230effb2018-11-29 17:28:18 +0100473
margarethaf0085122018-08-16 16:19:53 +0200474 String entity = response.getEntity(String.class);
475 node = JsonUtils.readTree(entity);
476 assertEquals(StatusCodes.INVALID_ACCESS_TOKEN,
477 node.at("/errors/0/0").asInt());
margaretha85273f12019-02-04 18:13:17 +0100478 assertEquals("Access token is invalid",
margarethaf0085122018-08-16 16:19:53 +0200479 node.at("/errors/0/1").asText());
margaretha835178d2018-08-15 19:04:03 +0200480 }
margaretha230effb2018-11-29 17:28:18 +0100481
margaretha7a09e482019-11-14 14:34:07 +0100482 private void requestAuthorizedClientList (String userAuthHeader)
483 throws KustvaktException {
margaretha5a2c34e2018-11-29 19:35:13 +0100484 MultivaluedMap<String, String> form = new MultivaluedMapImpl();
485 form.add("client_id", superClientId);
486 form.add("client_secret", clientSecret);
margaretha77e74742019-11-15 12:15:20 +0100487 form.add("authorized-only", "true");
margaretha5a2c34e2018-11-29 19:35:13 +0100488
489 ClientResponse response = resource().path(API_VERSION).path("oauth2")
490 .path("client").path("list")
491 .header(Attributes.AUTHORIZATION, userAuthHeader)
492 .header(HttpHeaders.CONTENT_TYPE,
493 ContentType.APPLICATION_FORM_URLENCODED)
494 .entity(form).post(ClientResponse.class);
495
496 assertEquals(Status.OK.getStatusCode(), response.getStatus());
497
498 String entity = response.getEntity(String.class);
499 JsonNode node = JsonUtils.readTree(entity);
500 assertEquals(2, node.size());
501 assertEquals(confidentialClientId, node.at("/0/clientId").asText());
502 assertEquals(publicClientId, node.at("/1/clientId").asText());
503 }
504
margaretha230effb2018-11-29 17:28:18 +0100505 @Test
506 public void testListUserClients () throws KustvaktException {
507 String username = "pearl";
508 String password = "pwd";
509 userAuthHeader = HttpAuthorizationHandler
510 .createBasicAuthorizationHeaderValue(username, password);
511
512 // super client
513 ClientResponse response = requestTokenWithPassword(superClientId,
514 clientSecret, username, password);
515 assertEquals(Status.OK.getStatusCode(), response.getStatus());
516
517 // client 1
margaretha0afd44a2020-02-05 10:49:21 +0100518 String code = requestAuthorizationCode(publicClientId, "",
margaretha230effb2018-11-29 17:28:18 +0100519 null, userAuthHeader);
520 response = requestTokenWithAuthorizationCodeAndForm(publicClientId, "",
521 code);
522 assertEquals(Status.OK.getStatusCode(), response.getStatus());
523
margarethac750cbb2018-12-11 12:47:02 +0100524 JsonNode node = JsonUtils.readTree(response.getEntity(String.class));
margarethadb457bc2019-11-21 14:38:56 +0100525 String accessToken = node.at("/access_token").asText();
margarethac750cbb2018-12-11 12:47:02 +0100526
margaretha230effb2018-11-29 17:28:18 +0100527 // client 2
528 code = requestAuthorizationCode(confidentialClientId, clientSecret,
529 null, userAuthHeader);
530 response = requestTokenWithAuthorizationCodeAndForm(
531 confidentialClientId, clientSecret, code);
margaretha0afd44a2020-02-05 10:49:21 +0100532 String refreshToken = node.at("/refresh_token").asText();
margaretha230effb2018-11-29 17:28:18 +0100533 assertEquals(Status.OK.getStatusCode(), response.getStatus());
534
margaretha7a09e482019-11-14 14:34:07 +0100535 requestAuthorizedClientList(userAuthHeader);
536 testListAuthorizedClientWithMultipleRefreshTokens(userAuthHeader);
margaretha0afd44a2020-02-05 10:49:21 +0100537 testListAuthorizedClientWithMultipleAccessTokens(userAuthHeader);
538 testWithClientsFromAnotherUser(userAuthHeader);
margaretha7a09e482019-11-14 14:34:07 +0100539
margarethadb457bc2019-11-21 14:38:56 +0100540 // revoke client 1
margaretha7497adf2019-11-26 13:13:57 +0100541 testRevokeAllTokenViaSuperClient(publicClientId, userAuthHeader,
margaretha0afd44a2020-02-05 10:49:21 +0100542 accessToken);
margarethadb457bc2019-11-21 14:38:56 +0100543
544 // revoke client 2
margarethac750cbb2018-12-11 12:47:02 +0100545 node = JsonUtils.readTree(response.getEntity(String.class));
margarethadb457bc2019-11-21 14:38:56 +0100546 accessToken = node.at("/access_token").asText();
margarethac750cbb2018-12-11 12:47:02 +0100547 refreshToken = node.at("/refresh_token").asText();
margaretha7497adf2019-11-26 13:13:57 +0100548 testRevokeAllTokenViaSuperClient(confidentialClientId, userAuthHeader,
margaretha0afd44a2020-02-05 10:49:21 +0100549 accessToken);
550 testRequestTokenWithRevokedRefreshToken(confidentialClientId, clientSecret,
551 refreshToken);
margaretha5a2c34e2018-11-29 19:35:13 +0100552 }
margaretha230effb2018-11-29 17:28:18 +0100553
margaretha7a09e482019-11-14 14:34:07 +0100554 private void testListAuthorizedClientWithMultipleRefreshTokens (
555 String userAuthHeader) throws KustvaktException {
margaretha0afd44a2020-02-05 10:49:21 +0100556 // client 2
557 String code = requestAuthorizationCode(confidentialClientId, clientSecret,
558 null, userAuthHeader);
559 ClientResponse response = requestTokenWithAuthorizationCodeAndForm(
560 confidentialClientId, clientSecret, code);
561
562 assertEquals(Status.OK.getStatusCode(), response.getStatus());
563
564 requestAuthorizedClientList(userAuthHeader);
565 }
566
567 private void testListAuthorizedClientWithMultipleAccessTokens (
568 String userAuthHeader) throws KustvaktException {
margaretha5a2c34e2018-11-29 19:35:13 +0100569 // client 1
margaretha0afd44a2020-02-05 10:49:21 +0100570 String code = requestAuthorizationCode(publicClientId, "",
margaretha5a2c34e2018-11-29 19:35:13 +0100571 null, userAuthHeader);
572 ClientResponse response = requestTokenWithAuthorizationCodeAndForm(
573 publicClientId, "", code);
margaretha230effb2018-11-29 17:28:18 +0100574
575 assertEquals(Status.OK.getStatusCode(), response.getStatus());
margarethadb457bc2019-11-21 14:38:56 +0100576
577 requestAuthorizedClientList(userAuthHeader);
578 }
579
margaretha0afd44a2020-02-05 10:49:21 +0100580 private void testWithClientsFromAnotherUser (
margarethadb457bc2019-11-21 14:38:56 +0100581 String userAuthHeader) throws KustvaktException {
582
583 String aaaAuthHeader = HttpAuthorizationHandler
584 .createBasicAuthorizationHeaderValue("aaa", "pwd");
margaretha0afd44a2020-02-05 10:49:21 +0100585
margarethadb457bc2019-11-21 14:38:56 +0100586 // client 1
margaretha0afd44a2020-02-05 10:49:21 +0100587 String code = requestAuthorizationCode(publicClientId, "",
margarethadb457bc2019-11-21 14:38:56 +0100588 null, aaaAuthHeader);
589 ClientResponse response = requestTokenWithAuthorizationCodeAndForm(
590 publicClientId, "", code);
margaretha0afd44a2020-02-05 10:49:21 +0100591
margarethac750cbb2018-12-11 12:47:02 +0100592 JsonNode node = JsonUtils.readTree(response.getEntity(String.class));
margaretha0afd44a2020-02-05 10:49:21 +0100593 String accessToken1 = node.at("/access_token").asText();
594
595 // client 2
596 code = requestAuthorizationCode(confidentialClientId, clientSecret,
597 null, aaaAuthHeader);
598 response = requestTokenWithAuthorizationCodeAndForm(
599 confidentialClientId, clientSecret, code);
600
601 node = JsonUtils.readTree(response.getEntity(String.class));
602 String accessToken2 = node.at("/access_token").asText();
margarethac750cbb2018-12-11 12:47:02 +0100603 String refreshToken = node.at("/refresh_token").asText();
604
margaretha0afd44a2020-02-05 10:49:21 +0100605 requestAuthorizedClientList(aaaAuthHeader);
606 requestAuthorizedClientList(userAuthHeader);
607
margaretha7497adf2019-11-26 13:13:57 +0100608 testRevokeAllTokenViaSuperClient(publicClientId, aaaAuthHeader,
margaretha0afd44a2020-02-05 10:49:21 +0100609 accessToken1);
610 testRevokeAllTokenViaSuperClient(confidentialClientId, aaaAuthHeader,
611 accessToken2);
612 testRequestTokenWithRevokedRefreshToken(confidentialClientId, clientSecret,
613 refreshToken);
margaretha230effb2018-11-29 17:28:18 +0100614 }
615
margaretha7497adf2019-11-26 13:13:57 +0100616 private void testRevokeAllTokenViaSuperClient (String clientId,
margaretha0afd44a2020-02-05 10:49:21 +0100617 String userAuthHeader, String accessToken)
margarethac750cbb2018-12-11 12:47:02 +0100618 throws KustvaktException {
619 // check token before revoking
620 ClientResponse response = searchWithAccessToken(accessToken);
621 JsonNode node = JsonUtils.readTree(response.getEntity(String.class));
622 assertTrue(node.at("/matches").size() > 0);
623
624 MultivaluedMap<String, String> form = new MultivaluedMapImpl();
625 form.add("client_id", clientId);
626 form.add("super_client_id", superClientId);
627 form.add("super_client_secret", clientSecret);
628
629 response = resource().path(API_VERSION).path("oauth2").path("revoke")
margaretha7497adf2019-11-26 13:13:57 +0100630 .path("super").path("all")
631 .header(Attributes.AUTHORIZATION, userAuthHeader)
margarethac750cbb2018-12-11 12:47:02 +0100632 .header(HttpHeaders.CONTENT_TYPE,
633 ContentType.APPLICATION_FORM_URLENCODED)
634 .entity(form).post(ClientResponse.class);
635
636 assertEquals(Status.OK.getStatusCode(), response.getStatus());
margaretha7497adf2019-11-26 13:13:57 +0100637 assertEquals("SUCCESS", response.getEntity(String.class));
margarethac750cbb2018-12-11 12:47:02 +0100638
639 response = searchWithAccessToken(accessToken);
640 node = JsonUtils.readTree(response.getEntity(String.class));
641 assertEquals(StatusCodes.INVALID_ACCESS_TOKEN,
642 node.at("/errors/0/0").asInt());
margaretha85273f12019-02-04 18:13:17 +0100643 assertEquals("Access token is invalid",
margarethac750cbb2018-12-11 12:47:02 +0100644 node.at("/errors/0/1").asText());
margarethac750cbb2018-12-11 12:47:02 +0100645 }
margaretha7a09e482019-11-14 14:34:07 +0100646
647 @Test
648 public void testListRegisteredClients ()
649 throws KustvaktException {
650
651 String clientName = "OAuth2DoryClient";
652 OAuth2ClientJson json = new OAuth2ClientJson();
653 json.setName(clientName);
654 json.setType(OAuth2ClientType.PUBLIC);
655 json.setDescription("This is dory client.");
656
657 registerClient("dory", json);
658
659 MultivaluedMap<String, String> form = new MultivaluedMapImpl();
660 form.add("client_id", superClientId);
661 form.add("client_secret", clientSecret);
662
663 ClientResponse response = resource().path(API_VERSION).path("oauth2")
margaretha77e74742019-11-15 12:15:20 +0100664 .path("client").path("list")
margaretha7a09e482019-11-14 14:34:07 +0100665 .header(Attributes.AUTHORIZATION, userAuthHeader)
666 .header(HttpHeaders.CONTENT_TYPE,
667 ContentType.APPLICATION_FORM_URLENCODED)
668 .entity(form).post(ClientResponse.class);
669
670 assertEquals(Status.OK.getStatusCode(), response.getStatus());
671
672 String entity = response.getEntity(String.class);
673 JsonNode node = JsonUtils.readTree(entity);
674
675 assertEquals(1, node.size());
676 assertEquals(clientName, node.at("/0/clientName").asText());
677 String clientId = node.at("/0/clientId").asText();
678 testDeregisterPublicClient(clientId, "dory");
679 }
margaretha31a9f522018-04-03 20:40:45 +0200680}