Skip to content

Commit

Permalink
fix: delete REDIRECT_URI cookie on successful login
Browse files Browse the repository at this point in the history
  • Loading branch information
its-felix committed Oct 22, 2023
1 parent 811ccef commit 3ab83ef
Show file tree
Hide file tree
Showing 7 changed files with 124 additions and 4 deletions.
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

<groupId>com.gw2auth</groupId>
<artifactId>oauth2-server</artifactId>
<version>1.58.0</version>
<version>1.58.1</version>
<packaging>jar</packaging>

<parent>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ public Customizer<OAuth2LoginConfigurer<HttpSecurity>> oauth2LoginCustomizer(@Qu
}

delegate.onAuthenticationSuccess(request, response, authentication);
requestCache.removeRequest(request, response);
});
};
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,8 @@ public Optional<Gw2AuthUserV2> resolveUserForToken(HttpServletRequest request, S
user = new Gw2AuthUserV2(account.id(), accountFederation.issuer(), accountFederation.idAtIssuer(), sessionId, currentSessionMetadata, encryptionKeyBytes);
request.setAttribute(REQUEST_ATTRIBUTE_NAME, user);

CookieHelper.clearCookieIfPresent(request, AuthenticationHelper.getCurrentResponse().orElseThrow(), Constants.REDIRECT_URI_COOKIE_NAME);

return Optional.of(user);
}
}
17 changes: 17 additions & 0 deletions src/main/java/com/gw2auth/oauth2/server/util/Constants.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,24 @@
package com.gw2auth.oauth2.server.util;

import org.springframework.security.web.savedrequest.CookieRequestCache;

import java.lang.reflect.Field;

public final class Constants {

public static final String LOGOUT_URL = "/auth/logout";
public static final String ACCESS_TOKEN_COOKIE_NAME = "BEARER";
public static final String REDIRECT_URI_COOKIE_NAME;

static {
try {
final Field field = CookieRequestCache.class.getDeclaredField("COOKIE_NAME");
final boolean wasAccessible = field.canAccess(null);
field.setAccessible(true);
REDIRECT_URI_COOKIE_NAME = (String) field.get(null);
field.setAccessible(wasAccessible);
} catch (ReflectiveOperationException e) {
throw new RuntimeException(e);
}
}
}
13 changes: 13 additions & 0 deletions src/main/java/com/gw2auth/oauth2/server/util/CookieHelper.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,19 @@ public static void clearCookie(HttpServletRequest request, HttpServletResponse r
response.addCookie(cookie);
}

public static void clearCookieIfPresent(HttpServletRequest request, HttpServletResponse response, String name) {
final Cookie[] cookies = request.getCookies();
if (cookies != null) {
for (Cookie cookie : cookies) {
if (cookie.getName().equals(name)) {
cookie.setMaxAge(0);
response.addCookie(cookie);
break;
}
}
}
}

private static String getRequestContext(HttpServletRequest request) {
String contextPath = request.getContextPath();
return contextPath.isEmpty() ? "/" : contextPath;
Expand Down
6 changes: 3 additions & 3 deletions src/test/java/com/gw2auth/oauth2/server/SessionHandle.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public SessionHandle(String countryCode, String city, Double latitude, Double lo
}

public void addCookie(Cookie cookie) {
if (cookie.getMaxAge() > 0) {
if (cookie.getMaxAge() != 0) {
this.cookies.put(cookie.getName(), cookie);
} else {
this.cookies.remove(cookie.getName());
Expand Down Expand Up @@ -72,14 +72,14 @@ public MockHttpServletRequest postProcessRequest(MockHttpServletRequest request)

if (existingCookies != null) {
for (Cookie cookie : existingCookies) {
if (cookie.getMaxAge() > 0) {
if (cookie.getMaxAge() != 0) {
totalCookies.putIfAbsent(cookie.getName(), cookie);
}
}
}

for (Map.Entry<String, Cookie> entry : this.cookies.entrySet()) {
if (entry.getValue().getMaxAge() > 0) {
if (entry.getValue().getMaxAge() != 0) {
totalCookies.putIfAbsent(entry.getKey(), entry.getValue());
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2133,6 +2133,93 @@ public void refreshWithLegacyAttributes(SessionHandle sessionHandle, OAuth2Clien
assertNotEquals(refreshToken, tokenResponse.get("refresh_token").textValue());
}

@Test
public void unauthenticatedRequestShouldRememberURLAndRedirectUponLogin() throws Exception {
final ApplicationClientCreation applicationClientCreation = createApplicationClient(OAuth2ClientApiVersion.V0, OAuth2ClientType.CONFIDENTIAL);
final ApplicationClient applicationClient = applicationClientCreation.client();
final String clientSecret = applicationClientCreation.clientSecret();

// perform authorization request (should redirect to the login page)
final SessionHandle sessionHandle = new SessionHandle();
MvcResult result = performAuthorizeWithClient(sessionHandle, applicationClient, Set.of(OAuth2Scope.GW2_ACCOUNT)).andReturn();

// verify the redirect URI was saved
assertNotNull(sessionHandle.getCookie("REDIRECT_URI"));

// login
result = this.gw2AuthLoginExtension.login(sessionHandle, "issuer", UUID.randomUUID().toString())
.andExpectAll(this.gw2AuthLoginExtension.expectLoginSuccess())
.andReturn();

// verify the redirect URI was removed
assertNull(sessionHandle.getCookie("REDIRECT_URI"));

// follow redirect
result = this.mockMvc.perform(
get(URI.create(Objects.requireNonNull(result.getResponse().getRedirectedUrl())))
.with(sessionHandle)
)
.andDo(sessionHandle)
.andReturn();

// submit the consent
final String token = TestHelper.randomRootToken();
result = performSubmitConsent(
sessionHandle,
applicationClient,
URI.create(Objects.requireNonNull(result.getResponse().getRedirectedUrl())),
Map.of(this.gw2AccountId1st, "First.1234"),
Map.of(this.gw2AccountId1st, "First"),
Map.of(this.gw2AccountId1st, token),
Map.of(this.gw2AccountId1st, Set.of(Gw2ApiPermission.ACCOUNT)),
Set.of(Gw2ApiPermission.ACCOUNT)
).andReturn();

// verify the consent has been saved
final UUID accountId = this.testHelper.getAccountIdForCookie(sessionHandle).orElseThrow();
final ApplicationClientAccountEntity applicationClientAccountEntity = this.applicationClientAccountRepository.findByApplicationClientIdAndAccountId(
applicationClient.id(),
accountId
).orElse(null);
assertNotNull(applicationClientAccountEntity);
assertEquals(Set.of(OAuth2Scope.GW2_ACCOUNT.oauth2()), applicationClientAccountEntity.authorizedScopes());

// verify the authorization has been saved
final List<ApplicationClientAuthorizationWithGw2AccountIdsEntity> authorizations = this.applicationClientAuthorizationRepository.findAllWithGw2AccountIdsByAccountIdAndApplicationClientId(accountId, applicationClient.id());
assertEquals(1, authorizations.size());

final ApplicationClientAuthorizationWithGw2AccountIdsEntity clientAuthorization = authorizations.get(0);
assertEquals(Set.of(OAuth2Scope.GW2_ACCOUNT.oauth2()), clientAuthorization.authorization().authorizedScopes());
assertEquals(Set.of(this.gw2AccountId1st), clientAuthorization.gw2AccountIds());

// verify tokens have been saved
List<ApplicationClientAuthorizationTokenEntity> clientAuthorizationTokenEntities = this.applicationClientAuthorizationTokenRepository.findAllByApplicationClientAuthorizationIdAndAccountId(clientAuthorization.authorization().id(), accountId);
assertEquals(1, clientAuthorizationTokenEntities.size());

// set testing clock to token customizer
final Clock testingClock = Clock.fixed(Instant.now(), ZoneId.systemDefault());
this.gw2AuthClockedExtension.setClock(testingClock);

final String dummySubtoken = TestHelper.createSubtokenJWT(this.gw2AccountId1st, Set.of(Gw2ApiPermission.ACCOUNT), testingClock.instant(), Duration.ofMinutes(30L));

result = performRetrieveTokenByCode(
applicationClient,
clientSecret,
URI.create(Objects.requireNonNull(result.getResponse().getRedirectedUrl())),
Map.of(token, dummySubtoken),
Set.of(Gw2ApiPermission.ACCOUNT)
)
.andExpectAll(expectValidTokenResponse(OAuth2Scope.GW2_ACCOUNT))
.andReturn();

// verify the access token
assertTokenResponseV0(
result,
Map.of(this.gw2AccountId1st, Map.of("name", "First", "token", dummySubtoken)),
Set.of(OAuth2Scope.GW2_ACCOUNT)
);
}

private ResultActions performRetrieveTokensByRefreshTokenAndExpectValid(ApplicationClient applicationClient, String clientSecret, String refreshToken) throws Exception {
return performRetrieveTokensByRefreshToken(applicationClient, clientSecret, refreshToken)
.andExpectAll(expectValidTokenResponse());
Expand Down

0 comments on commit 3ab83ef

Please sign in to comment.