blob: 4ce03d1c46325cb929a07ce117e71e37ee39e174 [file] [log] [blame]
margarethaf0085122018-08-16 16:19:53 +02001package de.ids_mannheim.korap.web.controller;
2
margarethad4841562022-06-01 12:24:47 +02003import java.io.IOException;
margarethaf0085122018-08-16 16:19:53 +02004import java.net.URI;
margarethaca5472a2023-09-22 18:00:03 +02005import java.time.ZoneId;
6import java.time.ZonedDateTime;
7import java.util.HashSet;
8import java.util.Set;
margarethaf0085122018-08-16 16:19:53 +02009
margarethaf0085122018-08-16 16:19:53 +020010import org.apache.http.entity.ContentType;
margarethacc929592023-01-31 11:07:35 +010011import org.glassfish.jersey.client.ClientConfig;
12import org.glassfish.jersey.client.ClientProperties;
margarethab22a5852023-01-27 14:43:36 +010013import org.glassfish.jersey.uri.UriComponent;
margaretha93e602e2019-08-07 15:19:56 +020014import org.springframework.beans.factory.annotation.Autowired;
margarethaf0085122018-08-16 16:19:53 +020015import org.springframework.util.MultiValueMap;
16import org.springframework.web.util.UriComponentsBuilder;
17
18import com.fasterxml.jackson.databind.JsonNode;
19import com.google.common.net.HttpHeaders;
margaretha53c1ff82023-10-26 12:33:26 +020020import com.nimbusds.oauth2.sdk.GrantType;
margaretha5f5d3ed2023-08-30 23:48:52 +020021import com.nimbusds.oauth2.sdk.OAuth2Error;
margarethaf0085122018-08-16 16:19:53 +020022
23import de.ids_mannheim.korap.authentication.http.HttpAuthorizationHandler;
24import de.ids_mannheim.korap.config.Attributes;
25import de.ids_mannheim.korap.config.SpringJerseyTest;
margarethaca5472a2023-09-22 18:00:03 +020026import de.ids_mannheim.korap.constant.OAuth2Scope;
27import de.ids_mannheim.korap.encryption.RandomCodeGenerator;
margarethaf0085122018-08-16 16:19:53 +020028import de.ids_mannheim.korap.exceptions.KustvaktException;
margarethad4841562022-06-01 12:24:47 +020029import de.ids_mannheim.korap.exceptions.StatusCodes;
margarethae28cdd92022-03-29 09:42:08 +020030import de.ids_mannheim.korap.oauth2.constant.OAuth2ClientType;
margarethaca5472a2023-09-22 18:00:03 +020031import de.ids_mannheim.korap.oauth2.dao.AccessTokenDao;
32import de.ids_mannheim.korap.oauth2.dao.OAuth2ClientDao;
margaretha93e602e2019-08-07 15:19:56 +020033import de.ids_mannheim.korap.oauth2.dao.RefreshTokenDao;
margarethaca5472a2023-09-22 18:00:03 +020034import de.ids_mannheim.korap.oauth2.entity.AccessScope;
35import de.ids_mannheim.korap.oauth2.entity.AccessToken;
36import de.ids_mannheim.korap.oauth2.entity.OAuth2Client;
margarethaf0085122018-08-16 16:19:53 +020037import de.ids_mannheim.korap.utils.JsonUtils;
margaretha977fabe2022-04-28 09:23:47 +020038import de.ids_mannheim.korap.utils.TimeUtils;
margarethae28cdd92022-03-29 09:42:08 +020039import de.ids_mannheim.korap.web.input.OAuth2ClientJson;
margaretha96c309d2023-08-16 12:24:12 +020040import jakarta.ws.rs.ProcessingException;
41import jakarta.ws.rs.client.Client;
42import jakarta.ws.rs.client.ClientBuilder;
43import jakarta.ws.rs.client.Entity;
margaretha5f5d3ed2023-08-30 23:48:52 +020044import jakarta.ws.rs.client.Invocation.Builder;
margaretha96c309d2023-08-16 12:24:12 +020045import jakarta.ws.rs.client.WebTarget;
46import jakarta.ws.rs.core.Form;
47import jakarta.ws.rs.core.MultivaluedMap;
48import jakarta.ws.rs.core.Response;
49import jakarta.ws.rs.core.Response.Status;
margarethaf0085122018-08-16 16:19:53 +020050
Marc Kupietzd43a98d2023-09-22 17:11:46 +020051import static org.junit.jupiter.api.Assertions.*;
52
margaretha230effb2018-11-29 17:28:18 +010053/**
54 * Provides common methods and variables for OAuth2 tests,
55 * and does not run any test.
margarethaf0085122018-08-16 16:19:53 +020056 *
57 * @author margaretha
58 *
59 */
margarethaf370f542018-08-23 18:51:49 +020060public abstract class OAuth2TestBase extends SpringJerseyTest {
margarethaf0085122018-08-16 16:19:53 +020061
margaretha93e602e2019-08-07 15:19:56 +020062 @Autowired
margarethaca5472a2023-09-22 18:00:03 +020063 private AccessTokenDao tokenDao;
64 @Autowired
65 private OAuth2ClientDao clientDao;
66 @Autowired
67 private RandomCodeGenerator codeGenerator;
68 @Autowired
margaretha93e602e2019-08-07 15:19:56 +020069 protected RefreshTokenDao refreshTokenDao;
margarethae20a2802022-04-21 12:37:38 +020070
margarethaf0085122018-08-16 16:19:53 +020071 protected String publicClientId = "8bIDtZnH6NvRkW2Fq";
margarethaffb89502022-04-20 12:03:16 +020072 // without registered redirect URI
73 protected String publicClientId2 = "nW5qM63Rb2a7KdT9L";
margarethaf0085122018-08-16 16:19:53 +020074 protected String confidentialClientId = "9aHsGW6QflV13ixNpez";
margaretha35074692021-03-26 18:11:59 +010075 protected String confidentialClientId2 = "52atrL0ajex_3_5imd9Mgw";
margarethaf0085122018-08-16 16:19:53 +020076 protected String superClientId = "fCBbQkAyYzI4NzUxMg";
77 protected String clientSecret = "secret";
margarethad67b4272022-04-11 17:34:19 +020078 protected String state = "thisIsMyState";
margarethaf0085122018-08-16 16:19:53 +020079
margaretha74110b72022-03-28 12:16:51 +020080 public static String ACCESS_TOKEN_TYPE = "access_token";
81 public static String REFRESH_TOKEN_TYPE = "refresh_token";
margarethae20a2802022-04-21 12:37:38 +020082
margaretha35e1ca22023-11-16 22:00:01 +010083 protected int defaultRefreshTokenExpiry = TimeUtils
84 .convertTimeToSeconds("365D");
85
margarethad67b4272022-04-11 17:34:19 +020086 protected String clientURL = "http://example.client.com";
87 protected String clientRedirectUri = "https://example.client.com/redirect";
margarethae20a2802022-04-21 12:37:38 +020088
margarethaffb89502022-04-20 12:03:16 +020089 protected MultivaluedMap<String, String> getQueryParamsFromURI (URI uri) {
90 return UriComponent.decodeQuery(uri, true);
91 };
margaretha74110b72022-03-28 12:16:51 +020092
abcpro173fe8f22022-11-08 19:56:52 +000093 protected Form getSuperClientForm () {
94 Form form = new Form();
95 form.param("super_client_id", superClientId);
96 form.param("super_client_secret", clientSecret);
margarethae20a2802022-04-21 12:37:38 +020097 return form;
98 }
99
margaretha3cd2d5f2023-05-02 14:51:11 +0200100 protected String parseAuthorizationCode (Response response) {
margaretha35e1ca22023-11-16 22:00:01 +0100101
margaretha3cd2d5f2023-05-02 14:51:11 +0200102 assertEquals(Status.TEMPORARY_REDIRECT.getStatusCode(),
103 response.getStatus());
104
105 URI redirectUri = response.getLocation();
106 MultiValueMap<String, String> params = UriComponentsBuilder
107 .fromUri(redirectUri).build().getQueryParams();
108 return params.getFirst("code");
109 }
margaretha35e1ca22023-11-16 22:00:01 +0100110
abcpro173fe8f22022-11-08 19:56:52 +0000111 protected Response requestAuthorizationCode (String responseType,
margarethad67b4272022-04-11 17:34:19 +0200112 String clientId, String redirectUri, String scope, String state,
113 String authHeader) throws KustvaktException {
margarethaf0085122018-08-16 16:19:53 +0200114
margarethacc929592023-01-31 11:07:35 +0100115 ClientConfig clientConfig = new ClientConfig();
116 clientConfig.property(ClientProperties.FOLLOW_REDIRECTS, false);
117 Client client = ClientBuilder.newClient(clientConfig);
margaretha35e1ca22023-11-16 22:00:01 +0100118
margarethacc929592023-01-31 11:07:35 +0100119 WebTarget request = client.target(getBaseUri()).path(API_VERSION)
120 .path("oauth2").path("authorize");
121
margaretha0034a0c2022-05-17 10:37:41 +0200122 if (!responseType.isEmpty()) {
123 request = request.queryParam("response_type", responseType);
124 }
125 if (!clientId.isEmpty()) {
126 request = request.queryParam("client_id", clientId);
127 }
128 if (!redirectUri.isEmpty()) {
129 request = request.queryParam("redirect_uri", redirectUri);
130 }
131 if (!scope.isEmpty()) {
132 request = request.queryParam("scope", scope);
133 }
134 if (!state.isEmpty()) {
135 request = request.queryParam("state", state);
136 }
margaretha35e1ca22023-11-16 22:00:01 +0100137
138 Builder builder = request.request().header(Attributes.AUTHORIZATION,
139 authHeader);
140
margaretha5f5d3ed2023-08-30 23:48:52 +0200141 return builder.get();
margarethaf0085122018-08-16 16:19:53 +0200142 }
143
margarethae20a2802022-04-21 12:37:38 +0200144 protected String requestAuthorizationCode (String clientId,
margarethad67b4272022-04-11 17:34:19 +0200145 String authHeader) throws KustvaktException {
margarethaf0085122018-08-16 16:19:53 +0200146
abcpro173fe8f22022-11-08 19:56:52 +0000147 Response response = requestAuthorizationCode("code", clientId, "",
margaretha64ea6452023-01-30 12:39:19 +0100148 "search match_info", "", authHeader);
margarethaf0085122018-08-16 16:19:53 +0200149 assertEquals(Status.TEMPORARY_REDIRECT.getStatusCode(),
150 response.getStatus());
151 URI redirectUri = response.getLocation();
152
153 MultiValueMap<String, String> params = UriComponentsBuilder
154 .fromUri(redirectUri).build().getQueryParams();
155 return params.getFirst("code");
156 }
margarethae20a2802022-04-21 12:37:38 +0200157
158 protected String requestAuthorizationCode (String clientId,
159 String redirect_uri, String authHeader) throws KustvaktException {
abcpro173fe8f22022-11-08 19:56:52 +0000160 Response response = requestAuthorizationCode("code", clientId,
margaretha64ea6452023-01-30 12:39:19 +0100161 redirect_uri, "search", "", authHeader);
Akrondc6d73d2020-04-15 16:40:04 +0200162 assertEquals(Status.TEMPORARY_REDIRECT.getStatusCode(),
163 response.getStatus());
164 URI redirectUri = response.getLocation();
165
166 MultiValueMap<String, String> params = UriComponentsBuilder
167 .fromUri(redirectUri).build().getQueryParams();
168 return params.getFirst("code");
169 }
margarethae20a2802022-04-21 12:37:38 +0200170
margaretha35e1ca22023-11-16 22:00:01 +0100171 protected Response requestToken (Form form) throws KustvaktException {
172 return target().path(API_VERSION).path("oauth2").path("token").request()
margarethaf0085122018-08-16 16:19:53 +0200173 .header(HttpHeaders.X_FORWARDED_FOR, "149.27.0.32")
174 .header(HttpHeaders.CONTENT_TYPE,
175 ContentType.APPLICATION_FORM_URLENCODED)
margaretha35e1ca22023-11-16 22:00:01 +0100176 .post(Entity.form(form));
margarethaf0085122018-08-16 16:19:53 +0200177 }
178
179 // client credentials as form params
abcpro173fe8f22022-11-08 19:56:52 +0000180 protected Response requestTokenWithAuthorizationCodeAndForm (
margarethaf0085122018-08-16 16:19:53 +0200181 String clientId, String clientSecret, String code)
182 throws KustvaktException {
183
abcpro173fe8f22022-11-08 19:56:52 +0000184 Form form = new Form();
185 form.param("grant_type", "authorization_code");
186 form.param("client_id", clientId);
187 form.param("client_secret", clientSecret);
188 form.param("code", code);
margarethaf0085122018-08-16 16:19:53 +0200189
margaretha35e1ca22023-11-16 22:00:01 +0100190 return target().path(API_VERSION).path("oauth2").path("token").request()
margarethaf0085122018-08-16 16:19:53 +0200191 .header(HttpHeaders.CONTENT_TYPE,
192 ContentType.APPLICATION_FORM_URLENCODED)
abcpro173fe8f22022-11-08 19:56:52 +0000193 .post(Entity.form(form));
margarethaf0085122018-08-16 16:19:53 +0200194 }
margarethae20a2802022-04-21 12:37:38 +0200195
abcpro173fe8f22022-11-08 19:56:52 +0000196 protected Response requestTokenWithAuthorizationCodeAndForm (
Akrondc6d73d2020-04-15 16:40:04 +0200197 String clientId, String clientSecret, String code,
198 String redirectUri) throws KustvaktException {
199
abcpro173fe8f22022-11-08 19:56:52 +0000200 Form form = new Form();
201 form.param("grant_type", "authorization_code");
202 form.param("client_id", clientId);
203 form.param("client_secret", clientSecret);
204 form.param("code", code);
margarethae20a2802022-04-21 12:37:38 +0200205 if (redirectUri != null) {
abcpro173fe8f22022-11-08 19:56:52 +0000206 form.param("redirect_uri", redirectUri);
Akrondc6d73d2020-04-15 16:40:04 +0200207 }
208
margaretha35e1ca22023-11-16 22:00:01 +0100209 return target().path(API_VERSION).path("oauth2").path("token").request()
Akrondc6d73d2020-04-15 16:40:04 +0200210 .header(HttpHeaders.CONTENT_TYPE,
211 ContentType.APPLICATION_FORM_URLENCODED)
abcpro173fe8f22022-11-08 19:56:52 +0000212 .post(Entity.form(form));
Akrondc6d73d2020-04-15 16:40:04 +0200213 }
margarethaf0085122018-08-16 16:19:53 +0200214
215 // client credentials in authorization header
margarethae20a2802022-04-21 12:37:38 +0200216 protected JsonNode requestTokenWithAuthorizationCodeAndHeader (
217 String clientId, String code, String authHeader)
218 throws KustvaktException {
abcpro173fe8f22022-11-08 19:56:52 +0000219 Form form = new Form();
220 form.param("grant_type", "authorization_code");
221 form.param("client_id", clientId);
222 form.param("code", code);
margarethaf0085122018-08-16 16:19:53 +0200223
abcpro173fe8f22022-11-08 19:56:52 +0000224 Response response = target().path(API_VERSION).path("oauth2")
margaretha35e1ca22023-11-16 22:00:01 +0100225 .path("token").request()
abcpro1241bc4f2022-11-07 20:13:57 +0000226 .header(Attributes.AUTHORIZATION, authHeader)
margarethaf0085122018-08-16 16:19:53 +0200227 .header(HttpHeaders.CONTENT_TYPE,
228 ContentType.APPLICATION_FORM_URLENCODED)
abcpro173fe8f22022-11-08 19:56:52 +0000229 .post(Entity.form(form));
margarethaf0085122018-08-16 16:19:53 +0200230
margaretha3cd2d5f2023-05-02 14:51:11 +0200231 assertEquals(Status.OK.getStatusCode(), response.getStatus());
margaretha35e1ca22023-11-16 22:00:01 +0100232
abcpro173fe8f22022-11-08 19:56:52 +0000233 String entity = response.readEntity(String.class);
margarethaf0085122018-08-16 16:19:53 +0200234 return JsonUtils.readTree(entity);
235 }
236
abcpro173fe8f22022-11-08 19:56:52 +0000237 protected Response requestTokenWithDoryPassword (String clientId,
margarethaf0085122018-08-16 16:19:53 +0200238 String clientSecret) throws KustvaktException {
margaretha230effb2018-11-29 17:28:18 +0100239 return requestTokenWithPassword(clientId, clientSecret, "dory",
240 "password");
241 }
242
abcpro173fe8f22022-11-08 19:56:52 +0000243 protected Response requestTokenWithPassword (String clientId,
margaretha230effb2018-11-29 17:28:18 +0100244 String clientSecret, String username, String password)
245 throws KustvaktException {
abcpro173fe8f22022-11-08 19:56:52 +0000246 Form form = new Form();
247 form.param("grant_type", "password");
248 form.param("client_id", clientId);
margaretha35e1ca22023-11-16 22:00:01 +0100249 if (clientSecret != null && !clientSecret.isEmpty()) {
margaretha7ac20b12023-09-27 09:40:16 +0200250 form.param("client_secret", clientSecret);
251 }
abcpro173fe8f22022-11-08 19:56:52 +0000252 form.param("username", username);
253 form.param("password", password);
margarethaf0085122018-08-16 16:19:53 +0200254
255 return requestToken(form);
256 }
margarethae20a2802022-04-21 12:37:38 +0200257
margarethac750cbb2018-12-11 12:47:02 +0100258 protected void testRequestTokenWithRevokedRefreshToken (String clientId,
259 String clientSecret, String refreshToken) throws KustvaktException {
abcpro173fe8f22022-11-08 19:56:52 +0000260 Form form = new Form();
261 form.param("grant_type", GrantType.REFRESH_TOKEN.toString());
262 form.param("client_id", clientId);
263 form.param("client_secret", clientSecret);
264 form.param("refresh_token", refreshToken);
margarethac750cbb2018-12-11 12:47:02 +0100265 if (clientSecret != null) {
abcpro173fe8f22022-11-08 19:56:52 +0000266 form.param("client_secret", clientSecret);
margarethac750cbb2018-12-11 12:47:02 +0100267 }
margarethaf0085122018-08-16 16:19:53 +0200268
margaretha35e1ca22023-11-16 22:00:01 +0100269 Response response = target().path(API_VERSION).path("oauth2")
270 .path("token").request()
271 .header(HttpHeaders.X_FORWARDED_FOR, "149.27.0.32")
272 .header(HttpHeaders.CONTENT_TYPE,
273 ContentType.APPLICATION_FORM_URLENCODED)
274 .post(Entity.form(form));
margarethac750cbb2018-12-11 12:47:02 +0100275
abcpro173fe8f22022-11-08 19:56:52 +0000276 String entity = response.readEntity(String.class);
margarethac750cbb2018-12-11 12:47:02 +0100277 JsonNode node = JsonUtils.readTree(entity);
margaretha35e1ca22023-11-16 22:00:01 +0100278 assertEquals(OAuth2Error.INVALID_GRANT.getCode(),
279 node.at("/error").asText());
margarethac750cbb2018-12-11 12:47:02 +0100280 assertEquals("Refresh token has been revoked",
281 node.at("/error_description").asText());
282 }
margarethae20a2802022-04-21 12:37:38 +0200283
margaretha35e1ca22023-11-16 22:00:01 +0100284 protected Response registerClient (String username, OAuth2ClientJson json)
285 throws ProcessingException, KustvaktException {
abcpro173fe8f22022-11-08 19:56:52 +0000286 return target().path(API_VERSION).path("oauth2").path("client")
margaretha35e1ca22023-11-16 22:00:01 +0100287 .path("register").request()
margarethae28cdd92022-03-29 09:42:08 +0200288 .header(Attributes.AUTHORIZATION,
289 HttpAuthorizationHandler
290 .createBasicAuthorizationHeaderValue(username,
291 "password"))
292 .header(HttpHeaders.X_FORWARDED_FOR, "149.27.0.32")
293 .header(HttpHeaders.CONTENT_TYPE, ContentType.APPLICATION_JSON)
abcpro173fe8f22022-11-08 19:56:52 +0000294 .post(Entity.json(json));
margarethae28cdd92022-03-29 09:42:08 +0200295 }
margarethae20a2802022-04-21 12:37:38 +0200296
abcpro173fe8f22022-11-08 19:56:52 +0000297 protected Response registerConfidentialClient (String username)
margarethae28cdd92022-03-29 09:42:08 +0200298 throws KustvaktException {
margarethac750cbb2018-12-11 12:47:02 +0100299
margarethae28cdd92022-03-29 09:42:08 +0200300 OAuth2ClientJson json = new OAuth2ClientJson();
301 json.setName("OAuth2ClientTest");
302 json.setType(OAuth2ClientType.CONFIDENTIAL);
margaretha3ef1b812022-04-06 11:32:54 +0200303 json.setUrl(clientURL);
304 json.setRedirectURI(clientRedirectUri);
margarethae28cdd92022-03-29 09:42:08 +0200305 json.setDescription("This is a confidential test client.");
306
307 return registerClient(username, json);
308 }
margarethae20a2802022-04-21 12:37:38 +0200309
margaretha3ef1b812022-04-06 11:32:54 +0200310 protected void testConfidentialClientInfo (String clientId, String username)
margaretha35e1ca22023-11-16 22:00:01 +0100311 throws ProcessingException, KustvaktException {
margaretha3ef1b812022-04-06 11:32:54 +0200312 JsonNode clientInfo = retrieveClientInfo(clientId, username);
margaretha79f01442022-05-04 12:03:47 +0200313 assertEquals(clientId, clientInfo.at("/client_id").asText());
margaretha35e1ca22023-11-16 22:00:01 +0100314 assertEquals("OAuth2ClientTest",
315 clientInfo.at("/client_name").asText());
margaretha3ef1b812022-04-06 11:32:54 +0200316 assertEquals(OAuth2ClientType.CONFIDENTIAL.name(),
margaretha79f01442022-05-04 12:03:47 +0200317 clientInfo.at("/client_type").asText());
margaretha3ef1b812022-04-06 11:32:54 +0200318 assertEquals(username, clientInfo.at("/registered_by").asText());
margaretha79f01442022-05-04 12:03:47 +0200319 assertEquals(clientURL, clientInfo.at("/client_url").asText());
margarethae20a2802022-04-21 12:37:38 +0200320 assertEquals(clientRedirectUri,
margaretha79f01442022-05-04 12:03:47 +0200321 clientInfo.at("/client_redirect_uri").asText());
margaretha977fabe2022-04-28 09:23:47 +0200322 // 31536000 seconds
margaretha79f01442022-05-04 12:03:47 +0200323 assertEquals(defaultRefreshTokenExpiry,
margaretha977fabe2022-04-28 09:23:47 +0200324 clientInfo.at("/refresh_token_expiry").asInt());
margaretha3ef1b812022-04-06 11:32:54 +0200325 assertNotNull(clientInfo.at("/description"));
margarethad7163122022-04-11 09:42:41 +0200326 assertNotNull(clientInfo.at("/registration_date"));
327 assertTrue(clientInfo.at("/permitted").asBoolean());
328 assertTrue(clientInfo.at("/source").isMissingNode());
margarethae20a2802022-04-21 12:37:38 +0200329
margaretha3ef1b812022-04-06 11:32:54 +0200330 }
margarethae20a2802022-04-21 12:37:38 +0200331
margaretha35e1ca22023-11-16 22:00:01 +0100332 protected void deregisterClient (String username, String clientId)
333 throws ProcessingException, KustvaktException {
margarethae28cdd92022-03-29 09:42:08 +0200334
abcpro173fe8f22022-11-08 19:56:52 +0000335 Response response = target().path(API_VERSION).path("oauth2")
margaretha35e1ca22023-11-16 22:00:01 +0100336 .path("client").path("deregister").path(clientId).request()
margarethae28cdd92022-03-29 09:42:08 +0200337 .header(Attributes.AUTHORIZATION, HttpAuthorizationHandler
338 .createBasicAuthorizationHeaderValue(username, "pass"))
abcpro173fe8f22022-11-08 19:56:52 +0000339 .delete();
margarethae28cdd92022-03-29 09:42:08 +0200340
341 assertEquals(Status.OK.getStatusCode(), response.getStatus());
342 }
343
344 protected JsonNode retrieveClientInfo (String clientId, String username)
margaretha35e1ca22023-11-16 22:00:01 +0100345 throws ProcessingException, KustvaktException {
margarethab22a5852023-01-27 14:43:36 +0100346 Form form = new Form();
347 form.param("super_client_id", superClientId);
348 form.param("super_client_secret", clientSecret);
margaretha35e1ca22023-11-16 22:00:01 +0100349
abcpro173fe8f22022-11-08 19:56:52 +0000350 Response response = target().path(API_VERSION).path("oauth2")
margaretha35e1ca22023-11-16 22:00:01 +0100351 .path("client").path(clientId).request()
margaretha60b65d42024-06-06 09:05:16 +0200352 .header(Attributes.AUTHORIZATION, HttpAuthorizationHandler
353 .createBasicAuthorizationHeaderValue(username, "pass"))
margarethab22a5852023-01-27 14:43:36 +0100354 .header(HttpHeaders.CONTENT_TYPE,
355 ContentType.APPLICATION_FORM_URLENCODED)
356 .post(Entity.form(form));
margarethaf0085122018-08-16 16:19:53 +0200357
358 assertEquals(Status.OK.getStatusCode(), response.getStatus());
margarethae28cdd92022-03-29 09:42:08 +0200359
abcpro173fe8f22022-11-08 19:56:52 +0000360 String entity = response.readEntity(String.class);
margarethae28cdd92022-03-29 09:42:08 +0200361 return JsonUtils.readTree(entity);
margarethaf0085122018-08-16 16:19:53 +0200362 }
margaretha230effb2018-11-29 17:28:18 +0100363
abcpro173fe8f22022-11-08 19:56:52 +0000364 protected Response searchWithAccessToken (String accessToken) {
365 return target().path(API_VERSION).path("search")
margaretha230effb2018-11-29 17:28:18 +0100366 .queryParam("q", "Wasser").queryParam("ql", "poliqarp")
abcpro1241bc4f2022-11-07 20:13:57 +0000367 .request()
margarethaf0085122018-08-16 16:19:53 +0200368 .header(Attributes.AUTHORIZATION, "Bearer " + accessToken)
margaretha35e1ca22023-11-16 22:00:01 +0100369 .header(HttpHeaders.X_FORWARDED_FOR, "149.27.0.32").get();
margarethaf0085122018-08-16 16:19:53 +0200370 }
margaretha35e1ca22023-11-16 22:00:01 +0100371
margarethad4841562022-06-01 12:24:47 +0200372 protected void testSearchWithOAuth2Token (String accessToken)
373 throws KustvaktException, IOException {
abcpro173fe8f22022-11-08 19:56:52 +0000374 Response response = searchWithAccessToken(accessToken);
375 String entity = response.readEntity(String.class);
margaretha35e1ca22023-11-16 22:00:01 +0100376 assertEquals(Status.OK.getStatusCode(), response.getStatus());
margarethad4841562022-06-01 12:24:47 +0200377 JsonNode node = JsonUtils.readTree(entity);
378 assertNotNull(node);
379 assertEquals(25, node.at("/matches").size());
380 }
margaretha35e1ca22023-11-16 22:00:01 +0100381
margarethad4841562022-06-01 12:24:47 +0200382 protected void testSearchWithRevokedAccessToken (String accessToken)
383 throws KustvaktException {
abcpro173fe8f22022-11-08 19:56:52 +0000384 Response response = searchWithAccessToken(accessToken);
385 String entity = response.readEntity(String.class);
margaretha35e1ca22023-11-16 22:00:01 +0100386 assertEquals(Status.UNAUTHORIZED.getStatusCode(), response.getStatus());
margarethad4841562022-06-01 12:24:47 +0200387
388 JsonNode node = JsonUtils.readTree(entity);
389 assertEquals(StatusCodes.INVALID_ACCESS_TOKEN,
390 node.at("/errors/0/0").asInt());
391 assertEquals("Access token is invalid",
392 node.at("/errors/0/1").asText());
393 }
394
margarethae20a2802022-04-21 12:37:38 +0200395 protected void testRevokeTokenViaSuperClient (String token,
396 String userAuthHeader) {
abcpro173fe8f22022-11-08 19:56:52 +0000397 Form form = new Form();
398 form.param("token", token);
399 form.param("super_client_id", superClientId);
400 form.param("super_client_secret", clientSecret);
margaretha0afd44a2020-02-05 10:49:21 +0100401
abcpro173fe8f22022-11-08 19:56:52 +0000402 Response response = target().path(API_VERSION).path("oauth2")
margaretha35e1ca22023-11-16 22:00:01 +0100403 .path("revoke").path("super").request()
margaretha0afd44a2020-02-05 10:49:21 +0100404 .header(HttpHeaders.CONTENT_TYPE,
405 ContentType.APPLICATION_FORM_URLENCODED)
abcpro173fe8f22022-11-08 19:56:52 +0000406 .header(Attributes.AUTHORIZATION, userAuthHeader)
407 .post(Entity.form(form));
margaretha0afd44a2020-02-05 10:49:21 +0100408
409 assertEquals(Status.OK.getStatusCode(), response.getStatus());
abcpro173fe8f22022-11-08 19:56:52 +0000410 assertEquals("SUCCESS", response.readEntity(String.class));
margaretha0afd44a2020-02-05 10:49:21 +0100411 }
margarethaf0085122018-08-16 16:19:53 +0200412
margaretha74110b72022-03-28 12:16:51 +0200413 protected void testRevokeToken (String token, String clientId,
414 String clientSecret, String tokenType) {
abcpro173fe8f22022-11-08 19:56:52 +0000415 Form form = new Form();
416 form.param("token_type", tokenType);
417 form.param("token", token);
418 form.param("client_id", clientId);
margaretha74110b72022-03-28 12:16:51 +0200419 if (clientSecret != null) {
abcpro173fe8f22022-11-08 19:56:52 +0000420 form.param("client_secret", clientSecret);
margaretha74110b72022-03-28 12:16:51 +0200421 }
422
margaretha35e1ca22023-11-16 22:00:01 +0100423 Response response = target().path(API_VERSION).path("oauth2")
424 .path("revoke").request()
425 .header(HttpHeaders.CONTENT_TYPE,
426 ContentType.APPLICATION_FORM_URLENCODED)
427 .post(Entity.form(form));
margaretha74110b72022-03-28 12:16:51 +0200428
429 assertEquals(Status.OK.getStatusCode(), response.getStatus());
abcpro173fe8f22022-11-08 19:56:52 +0000430 assertEquals("SUCCESS", response.readEntity(String.class));
margaretha74110b72022-03-28 12:16:51 +0200431 }
margarethae20a2802022-04-21 12:37:38 +0200432
margaretha1ef2a032024-06-11 11:39:57 +0200433 protected JsonNode listUserClients (String username)
margaretha35e1ca22023-11-16 22:00:01 +0100434 throws ProcessingException, KustvaktException {
abcpro173fe8f22022-11-08 19:56:52 +0000435 Form form = getSuperClientForm();
436 Response response = target().path(API_VERSION).path("oauth2")
margaretha35e1ca22023-11-16 22:00:01 +0100437 .path("client").path("list").request()
margarethae20a2802022-04-21 12:37:38 +0200438 .header(Attributes.AUTHORIZATION, HttpAuthorizationHandler
439 .createBasicAuthorizationHeaderValue(username, "pwd"))
440 .header(HttpHeaders.CONTENT_TYPE,
441 ContentType.APPLICATION_FORM_URLENCODED)
abcpro173fe8f22022-11-08 19:56:52 +0000442 .post(Entity.form(form));
margarethae20a2802022-04-21 12:37:38 +0200443
444 assertEquals(Status.OK.getStatusCode(), response.getStatus());
445
abcpro173fe8f22022-11-08 19:56:52 +0000446 String entity = response.readEntity(String.class);
margarethae20a2802022-04-21 12:37:38 +0200447 return JsonUtils.readTree(entity);
448 }
margaretha35e1ca22023-11-16 22:00:01 +0100449
margaretha45ba7332023-01-31 11:39:52 +0100450 protected void testInvalidRedirectUri (String entity, String contentType,
451 boolean includeState, int status) throws KustvaktException {
margaretha9436ebe2022-04-22 11:48:37 +0200452 JsonNode node = JsonUtils.readTree(entity);
margaretha5f5d3ed2023-08-30 23:48:52 +0200453 assertEquals(OAuth2Error.INVALID_REQUEST.getCode(),
margaretha9436ebe2022-04-22 11:48:37 +0200454 node.at("/error").asText());
455 assertEquals("Invalid redirect URI",
456 node.at("/error_description").asText());
457 if (includeState) {
458 assertEquals(state, node.at("/state").asText());
459 }
460
margaretha45ba7332023-01-31 11:39:52 +0100461 assertEquals("application/json;charset=utf-8", contentType);
margaretha9436ebe2022-04-22 11:48:37 +0200462 assertEquals(Status.BAD_REQUEST.getStatusCode(), status);
463 }
margaretha35e1ca22023-11-16 22:00:01 +0100464
margarethaca5472a2023-09-22 18:00:03 +0200465 protected String createExpiredAccessToken () throws KustvaktException {
466 String authToken = codeGenerator.createRandomCode();
margaretha35e1ca22023-11-16 22:00:01 +0100467
margarethaca5472a2023-09-22 18:00:03 +0200468 // create new access token
469 OAuth2Client client = clientDao.retrieveClientById(publicClientId);
470
margaretha35e1ca22023-11-16 22:00:01 +0100471 ZonedDateTime now = ZonedDateTime
472 .now(ZoneId.of(Attributes.DEFAULT_TIME_ZONE));
margarethaca5472a2023-09-22 18:00:03 +0200473 Set<AccessScope> scopes = new HashSet<>();
474 scopes.add(new AccessScope(OAuth2Scope.EDIT_VC));
margaretha35e1ca22023-11-16 22:00:01 +0100475
margarethaca5472a2023-09-22 18:00:03 +0200476 AccessToken accessToken = new AccessToken();
477 accessToken.setCreatedDate(now.minusSeconds(5));
478 accessToken.setExpiryDate(now.minusSeconds(3));
479 accessToken.setToken(authToken);
480 accessToken.setScopes(scopes);
481 accessToken.setUserId("marlin");
482 accessToken.setClient(client);
483 accessToken.setUserAuthenticationTime(now.minusSeconds(5));
484 tokenDao.storeAccessToken(accessToken);
485 return authToken;
486 }
margarethaf0085122018-08-16 16:19:53 +0200487}