Add the nonce attribute when the client session context is recreated (#33422)

Closes #33355


Signed-off-by: rmartinc <rmartinc@redhat.com>
Co-authored-by: Tomas Kralik <tomas.kralik@pbktechnology.cz>
This commit is contained in:
Ricardo Martin 2024-10-02 09:44:25 +02:00 committed by GitHub
parent ef48a3a360
commit 6e471a8477
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 29 additions and 9 deletions

View file

@ -99,7 +99,6 @@ import org.keycloak.util.TokenUtil;
import java.util.Arrays;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
@ -1180,8 +1179,12 @@ public class TokenManager {
String scope = oldRefreshToken.getScope();
Object reuseId = oldRefreshToken.getOtherClaims().get(Constants.REUSE_ID);
boolean offlineTokenRequested = Arrays.asList(scope.split(" ")).contains(OAuth2Constants.OFFLINE_ACCESS) ;
if (offlineTokenRequested)
if (offlineTokenRequested) {
clientSessionCtx = DefaultClientSessionContext.fromClientSessionAndScopeParameter(clientSession, scope, session);
if (oldRefreshToken.getNonce() != null) {
clientSessionCtx.setAttribute(OIDCLoginProtocol.NONCE_PARAM, oldRefreshToken.getNonce());
}
}
generateRefreshToken(offlineTokenRequested);
if (realm.isRevokeRefreshToken()) {
refreshToken.getOtherClaims().put(Constants.REUSE_ID, reuseId);

View file

@ -46,6 +46,7 @@ import org.keycloak.testsuite.AssertEvents;
import org.keycloak.testsuite.admin.ApiUtil;
import org.keycloak.testsuite.updaters.ClientAttributeUpdater;
import org.keycloak.testsuite.util.OAuthClient;
import org.keycloak.util.TokenUtil;
/**
*
@ -62,7 +63,7 @@ public class NonceBackwardsCompatibleMapperTest extends AbstractTestRealmKeycloa
@Test
public void testNonceWithoutMapper() throws JsonProcessingException {
testNonce(false);
testNonce(false, false);
}
@Test
@ -70,7 +71,18 @@ public class NonceBackwardsCompatibleMapperTest extends AbstractTestRealmKeycloa
ClientResource testApp = ApiUtil.findClientByClientId(testRealm(), "test-app");
String mapperId = createNonceMapper(testApp);
try {
testNonce(true);
testNonce(true, false);
} finally {
testApp.getProtocolMappers().delete(mapperId);
}
}
@Test
public void testOfflineSessionNonceWithMapper() throws JsonProcessingException {
ClientResource testApp = ApiUtil.findClientByClientId(testRealm(), "test-app");
String mapperId = createNonceMapper(testApp);
try {
testNonce(true, true);
} finally {
testApp.getProtocolMappers().delete(mapperId);
}
@ -142,9 +154,12 @@ public class NonceBackwardsCompatibleMapperTest extends AbstractTestRealmKeycloa
testIntrospection(idTokenString, nonce, true);
}
private void testNonce(boolean mapper) throws JsonProcessingException {
private void testNonce(boolean mapper, boolean offlineSession) throws JsonProcessingException {
String nonce = KeycloakModelUtils.generateId();
oauth.nonce(nonce);
if (offlineSession) {
oauth.scope(OAuth2Constants.OFFLINE_ACCESS);
}
oauth.doLogin("test-user@localhost", "password");
EventRepresentation loginEvent = events.expectLogin().assertEvent();
@ -158,12 +173,14 @@ public class NonceBackwardsCompatibleMapperTest extends AbstractTestRealmKeycloa
RefreshToken refreshToken = oauth.parseRefreshToken(response.getRefreshToken());
checkNonce(nonce, refreshToken.getNonce(), mapper);
EventRepresentation tokenEvent = events.expectCodeToToken(loginEvent.getDetails().get(Details.CODE_ID),
loginEvent.getSessionId()).assertEvent();
EventRepresentation tokenEvent = events.expectCodeToToken(loginEvent.getDetails().get(Details.CODE_ID), loginEvent.getSessionId())
.detail(Details.REFRESH_TOKEN_TYPE, offlineSession? TokenUtil.TOKEN_TYPE_OFFLINE : TokenUtil.TOKEN_TYPE_REFRESH)
.assertEvent();
response = oauth.doRefreshTokenRequest(response.getRefreshToken(), "password");
events.expectRefresh(tokenEvent.getDetails().get(Details.REFRESH_TOKEN_ID),
loginEvent.getSessionId()).assertEvent();
events.expectRefresh(tokenEvent.getDetails().get(Details.REFRESH_TOKEN_ID), loginEvent.getSessionId())
.detail(Details.REFRESH_TOKEN_TYPE, offlineSession? TokenUtil.TOKEN_TYPE_OFFLINE : TokenUtil.TOKEN_TYPE_REFRESH)
.assertEvent();
token = oauth.verifyToken(response.getAccessToken());
checkNonce(nonce, token.getNonce(), mapper);