From 2d876d31c543cf2c544f367a0b89e1b356586089 Mon Sep 17 00:00:00 2001 From: Felix <23635466+its-felix@users.noreply.github.com> Date: Fri, 8 Nov 2024 23:12:18 +0100 Subject: [PATCH] feat: switch to accesstoken via query --- pom.xml | 2 +- .../server/service/gw2/Gw2ApiService.java | 1 + .../server/service/gw2/Gw2ApiServiceImpl.java | 7 ++++ .../oauth2/server/RequestMatchers.java | 32 +++++++++++++++++++ .../server/oauth2/OAuth2ServerTest.java | 10 +++--- .../Gw2AccountApiTokenServiceImplTest.java | 9 +++--- .../VerificationControllerTest.java | 11 ++++--- 7 files changed, 57 insertions(+), 15 deletions(-) create mode 100644 src/test/java/com/gw2auth/oauth2/server/RequestMatchers.java diff --git a/pom.xml b/pom.xml index e1be4c92..e9184d65 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ com.gw2auth oauth2-server - 1.88.0 + 1.89.0 jar diff --git a/src/main/java/com/gw2auth/oauth2/server/service/gw2/Gw2ApiService.java b/src/main/java/com/gw2auth/oauth2/server/service/gw2/Gw2ApiService.java index 62378087..fc921345 100644 --- a/src/main/java/com/gw2auth/oauth2/server/service/gw2/Gw2ApiService.java +++ b/src/main/java/com/gw2auth/oauth2/server/service/gw2/Gw2ApiService.java @@ -12,6 +12,7 @@ public interface Gw2ApiService { String API_VERSION_PARAM = "v"; String API_VERSION = "2021-07-15T13:00:00.000Z"; + String ACCESS_TOKEN_PARAM = "access_token"; Gw2TokenInfo getTokenInfo(String gw2ApiToken); diff --git a/src/main/java/com/gw2auth/oauth2/server/service/gw2/Gw2ApiServiceImpl.java b/src/main/java/com/gw2auth/oauth2/server/service/gw2/Gw2ApiServiceImpl.java index b79302e3..cc51d5e2 100644 --- a/src/main/java/com/gw2auth/oauth2/server/service/gw2/Gw2ApiServiceImpl.java +++ b/src/main/java/com/gw2auth/oauth2/server/service/gw2/Gw2ApiServiceImpl.java @@ -133,6 +133,10 @@ private T getFromAPI(String url, MultiValueMap query, String query = new LinkedMultiValueMap<>(query); query.set(API_VERSION_PARAM, API_VERSION); + if (token != null) { + query.set(ACCESS_TOKEN_PARAM, token); + } + final Long timeoutAt = Optional.ofNullable(TIMEOUT_AT_TL.get()).map(Deque::peekLast).orElse(null); ResponseEntity response; @@ -179,6 +183,7 @@ private T getFromAPI(String url, MultiValueMap query, String } private static HttpHeaders buildRequestHeaders(String token) { + /* if (token == null) { return HttpHeaders.EMPTY; } @@ -187,6 +192,8 @@ private static HttpHeaders buildRequestHeaders(String token) { headers.add("Authorization", "Bearer " + token); return headers; + */ + return HttpHeaders.EMPTY; } private static boolean validateToken(String token) { diff --git a/src/test/java/com/gw2auth/oauth2/server/RequestMatchers.java b/src/test/java/com/gw2auth/oauth2/server/RequestMatchers.java new file mode 100644 index 00000000..17d7e4de --- /dev/null +++ b/src/test/java/com/gw2auth/oauth2/server/RequestMatchers.java @@ -0,0 +1,32 @@ +package com.gw2auth.oauth2.server; + +import org.hamcrest.core.IsAnything; +import org.hamcrest.core.IsEqual; +import org.springframework.http.client.ClientHttpRequest; +import org.springframework.test.web.client.RequestMatcher; +import org.springframework.web.util.UriComponents; +import org.springframework.web.util.UriComponentsBuilder; + +import java.util.Optional; + +import static org.springframework.test.web.client.match.MockRestRequestMatchers.queryParam; + +public final class RequestMatchers { + + public static RequestMatcher matchAuthorizedRequest() { + return queryParam("access_token", new IsAnything<>()); + } + + public static RequestMatcher matchAuthorizedRequest(String accessToken) { + return queryParam("access_token", new IsEqual<>(accessToken)); + } + + public static Optional extractAccessToken(ClientHttpRequest request) { + final String token = UriComponentsBuilder.fromUri(request.getURI()) + .build() + .getQueryParams() + .getFirst("access_token"); + + return Optional.ofNullable(token); + } +} diff --git a/src/test/java/com/gw2auth/oauth2/server/oauth2/OAuth2ServerTest.java b/src/test/java/com/gw2auth/oauth2/server/oauth2/OAuth2ServerTest.java index 7eb01ca1..18da959a 100644 --- a/src/test/java/com/gw2auth/oauth2/server/oauth2/OAuth2ServerTest.java +++ b/src/test/java/com/gw2auth/oauth2/server/oauth2/OAuth2ServerTest.java @@ -79,6 +79,8 @@ import static com.gw2auth.oauth2.server.Assertions.assertInstantEquals; import static com.gw2auth.oauth2.server.Matchers.*; +import static com.gw2auth.oauth2.server.RequestMatchers.extractAccessToken; +import static com.gw2auth.oauth2.server.RequestMatchers.matchAuthorizedRequest; import static org.junit.jupiter.api.Assertions.*; import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf; import static org.springframework.test.web.client.ExpectedCount.times; @@ -1299,11 +1301,11 @@ public void consentSubmitWithUnexpectedGW2APIException(SessionHandle sessionHand this.gw2RestServer.reset(); this.gw2RestServer.expect(times(2), requestTo(new StringStartsWith("/v2/createsubtoken"))) .andExpect(method(HttpMethod.GET)) - .andExpect(MockRestRequestMatchers.header("Authorization", new StringStartsWith("Bearer "))) + .andExpect(matchAuthorizedRequest()) .andExpect(queryParam("permissions", split(",", containingAll(Gw2ApiPermission.ACCOUNT.gw2())))) .andExpect(queryParam("expire", asInstant(instantWithinTolerance(Instant.now().plus(Duration.ofMinutes(30L)), Duration.ofSeconds(5L))))) .andRespond((request) -> { - final String gw2ApiToken = request.getHeaders().getFirst("Authorization").replaceFirst("Bearer ", ""); + final String gw2ApiToken = extractAccessToken(request).orElseThrow(); final String subtoken; if (gw2ApiToken.equals(tokenA)) { @@ -2469,11 +2471,11 @@ private void prepareGw2RestServerForCreateSubToken(Map subtokenB if (!subtokenByGw2ApiToken.isEmpty()) { this.gw2RestServer.expect(times(subtokenByGw2ApiToken.size()), requestTo(new StringStartsWith("/v2/createsubtoken"))) .andExpect(method(HttpMethod.GET)) - .andExpect(MockRestRequestMatchers.header("Authorization", new StringStartsWith("Bearer "))) + .andExpect(matchAuthorizedRequest()) .andExpect(queryParam("permissions", split(",", containingAll(expectedGw2ApiPermissionStrs)))) .andExpect(queryParam("expire", asInstant(instantWithinTolerance(Instant.now().plus(Duration.ofMinutes(30L)), Duration.ofSeconds(5L))))) .andRespond((request) -> { - final String gw2ApiToken = request.getHeaders().getFirst("Authorization").replaceFirst("Bearer ", ""); + final String gw2ApiToken = extractAccessToken(request).orElseThrow(); final String subtoken = subtokenByGw2ApiToken.get(gw2ApiToken); if (subtoken == null || subtoken.isEmpty()) { diff --git a/src/test/java/com/gw2auth/oauth2/server/service/gw2account/apitoken/Gw2AccountApiTokenServiceImplTest.java b/src/test/java/com/gw2auth/oauth2/server/service/gw2account/apitoken/Gw2AccountApiTokenServiceImplTest.java index 7458bd71..322d742a 100644 --- a/src/test/java/com/gw2auth/oauth2/server/service/gw2account/apitoken/Gw2AccountApiTokenServiceImplTest.java +++ b/src/test/java/com/gw2auth/oauth2/server/service/gw2account/apitoken/Gw2AccountApiTokenServiceImplTest.java @@ -6,7 +6,6 @@ import com.gw2auth.oauth2.server.repository.gw2account.apitoken.Gw2AccountApiTokenEntity; import com.gw2auth.oauth2.server.repository.gw2account.apitoken.Gw2AccountApiTokenRepository; import com.gw2auth.oauth2.server.service.Gw2ApiPermission; -import org.hamcrest.core.IsEqual; import org.hamcrest.core.StringStartsWith; import org.json.JSONObject; import org.junit.jupiter.api.extension.RegisterExtension; @@ -20,7 +19,6 @@ import org.springframework.http.MediaType; import org.springframework.mock.http.client.MockClientHttpResponse; import org.springframework.test.web.client.MockRestServiceServer; -import org.springframework.test.web.client.match.MockRestRequestMatchers; import java.nio.charset.StandardCharsets; import java.time.Clock; @@ -32,6 +30,7 @@ import java.util.UUID; import static com.gw2auth.oauth2.server.Assertions.assertInstantEquals; +import static com.gw2auth.oauth2.server.RequestMatchers.matchAuthorizedRequest; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.springframework.test.web.client.ExpectedCount.times; import static org.springframework.test.web.client.match.MockRestRequestMatchers.method; @@ -95,7 +94,7 @@ public void checkTokenValidityWithUpdatedGw2AccountNames(SessionHandle sessionHa // prepare the mock server for the upcoming account request this.gw2RestServer.expect(times(1), requestTo(new StringStartsWith("/v2/account"))) .andExpect(method(HttpMethod.GET)) - .andExpect(MockRestRequestMatchers.header("Authorization", new IsEqual<>("Bearer " + gw2ApiToken))) + .andExpect(matchAuthorizedRequest(gw2ApiToken)) .andRespond((request) -> { final JSONObject responseJson = new JSONObject(Map.of( "id", gw2AccountId.toString(), @@ -153,7 +152,7 @@ public void checkTokenValidityWithFailingGw2ApiRequest(SessionHandle sessionHand // prepare the mock server for the upcoming account request this.gw2RestServer.expect(times(1), requestTo(new StringStartsWith("/v2/account"))) .andExpect(method(HttpMethod.GET)) - .andExpect(MockRestRequestMatchers.header("Authorization", new IsEqual<>("Bearer " + gw2ApiToken))) + .andExpect(matchAuthorizedRequest(gw2ApiToken)) .andRespond((request) -> { final MockClientHttpResponse response = new MockClientHttpResponse( "{}".getBytes(StandardCharsets.UTF_8), @@ -207,7 +206,7 @@ public void checkTokenValidityWithInvalidApiToken(SessionHandle sessionHandle) { // prepare the mock server for the upcoming account request this.gw2RestServer.expect(times(1), requestTo(new StringStartsWith("/v2/account"))) .andExpect(method(HttpMethod.GET)) - .andExpect(MockRestRequestMatchers.header("Authorization", new IsEqual<>("Bearer " + gw2ApiToken))) + .andExpect(matchAuthorizedRequest(gw2ApiToken)) .andRespond((request) -> { final MockClientHttpResponse response = new MockClientHttpResponse( "{}".getBytes(StandardCharsets.UTF_8), diff --git a/src/test/java/com/gw2auth/oauth2/server/web/verification/VerificationControllerTest.java b/src/test/java/com/gw2auth/oauth2/server/web/verification/VerificationControllerTest.java index 4b97a75c..6238ef99 100644 --- a/src/test/java/com/gw2auth/oauth2/server/web/verification/VerificationControllerTest.java +++ b/src/test/java/com/gw2auth/oauth2/server/web/verification/VerificationControllerTest.java @@ -37,6 +37,7 @@ import java.util.stream.Collectors; import static com.gw2auth.oauth2.server.Matchers.*; +import static com.gw2auth.oauth2.server.RequestMatchers.matchAuthorizedRequest; import static org.junit.jupiter.api.Assertions.*; import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf; import static org.springframework.test.web.client.ExpectedCount.max; @@ -769,7 +770,7 @@ public void startSubmitAndCancelChallenge(SessionHandle sessionHandle) throws Ex private void prepareGw2RestServerForTransactionsRequest(String gw2ApiToken, int addDummyValues, int itemId, int quantity, long price, Instant created) { this.gw2RestServer.expect(requestTo(new StringStartsWith("/v2/commerce/transactions/current/buys"))) .andExpect(method(HttpMethod.GET)) - .andExpect(MockRestRequestMatchers.header("Authorization", "Bearer " + gw2ApiToken)) + .andExpect(matchAuthorizedRequest(gw2ApiToken)) .andRespond((request) -> { final org.json.JSONArray result = new org.json.JSONArray(); @@ -801,7 +802,7 @@ private void prepareGw2RestServerForTransactionsRequest(String gw2ApiToken, int private void prepareGw2RestServerForTokenInfoRequest(String gw2ApiToken, String apiTokenName, Set gw2ApiPermissions) { this.gw2RestServer.expect(requestTo(new StringStartsWith("/v2/tokeninfo"))) .andExpect(method(HttpMethod.GET)) - .andExpect(MockRestRequestMatchers.header("Authorization", "Bearer " + gw2ApiToken)) + .andExpect(matchAuthorizedRequest(gw2ApiToken)) .andRespond((request) -> { final MockClientHttpResponse response = new MockClientHttpResponse(new JSONObject(Map.of( "name", apiTokenName, @@ -825,7 +826,7 @@ private void prepareGw2RestServerForCharactersRequest(String gw2ApiToken, int ad this.gw2RestServer.expect(requestTo(new StringStartsWith("/v2/characters"))) .andExpect(method(HttpMethod.GET)) - .andExpect(MockRestRequestMatchers.header("Authorization", "Bearer " + gw2ApiToken)) + .andExpect(matchAuthorizedRequest(gw2ApiToken)) .andRespond((request) -> { final MockClientHttpResponse response = new MockClientHttpResponse(new JSONArray(characters).toString().getBytes(StandardCharsets.UTF_8), HttpStatus.OK); response.getHeaders().setContentType(MediaType.APPLICATION_JSON); @@ -837,7 +838,7 @@ private void prepareGw2RestServerForCharactersRequest(String gw2ApiToken, int ad private void preparedGw2RestServerForCreateSubtoken(String gw2ApiToken, String gw2ApiSubtoken, Set requestPermissions, Instant expire) { this.gw2RestServer.expect(requestTo(new StringStartsWith("/v2/createsubtoken"))) .andExpect(method(HttpMethod.GET)) - .andExpect(MockRestRequestMatchers.header("Authorization", "Bearer " + gw2ApiToken)) + .andExpect(matchAuthorizedRequest(gw2ApiToken)) .andExpect(queryParam("permissions", split(",", containingAll(requestPermissions.stream().map(Gw2ApiPermission::gw2).toArray(String[]::new))))) .andExpect(queryParam("expire", asInstant(instant(expire)))) .andRespond((request) -> { @@ -851,7 +852,7 @@ private void preparedGw2RestServerForCreateSubtoken(String gw2ApiToken, String g private void preparedGw2RestServerForAccountRequest(UUID gw2AccountId, String gw2ApiToken) { this.gw2RestServer.expect(max(2), requestTo(new StringStartsWith("/v2/account"))) .andExpect(method(HttpMethod.GET)) - .andExpect(MockRestRequestMatchers.header("Authorization", "Bearer " + gw2ApiToken)) + .andExpect(matchAuthorizedRequest(gw2ApiToken)) .andRespond((request) -> { final MockClientHttpResponse response = new MockClientHttpResponse(new JSONObject(Map.of( "id", gw2AccountId,