Use realm default signature algorithm for id_token_signed_response_alg
Closes #9695 Signed-off-by: Justin Tay <49700559+justin-tay@users.noreply.github.com>
This commit is contained in:
parent
c1a471755d
commit
30cd40e097
3 changed files with 147 additions and 3 deletions
|
@ -21,6 +21,7 @@ import org.keycloak.OAuth2Constants;
|
||||||
import org.keycloak.authentication.ClientAuthenticator;
|
import org.keycloak.authentication.ClientAuthenticator;
|
||||||
import org.keycloak.authentication.ClientAuthenticatorFactory;
|
import org.keycloak.authentication.ClientAuthenticatorFactory;
|
||||||
import org.keycloak.authentication.authenticators.client.JWTClientAuthenticator;
|
import org.keycloak.authentication.authenticators.client.JWTClientAuthenticator;
|
||||||
|
import org.keycloak.crypto.Algorithm;
|
||||||
import org.keycloak.jose.jwk.JSONWebKeySet;
|
import org.keycloak.jose.jwk.JSONWebKeySet;
|
||||||
import org.keycloak.jose.jwk.JWK;
|
import org.keycloak.jose.jwk.JWK;
|
||||||
import org.keycloak.jose.jwk.JWKParser;
|
import org.keycloak.jose.jwk.JWKParser;
|
||||||
|
@ -159,9 +160,7 @@ public class DescriptionConverter {
|
||||||
configWrapper.setAllowRegexPatternComparison(false);
|
configWrapper.setAllowRegexPatternComparison(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (clientOIDC.getIdTokenSignedResponseAlg() != null) {
|
configWrapper.setIdTokenSignedResponseAlg(clientOIDC.getIdTokenSignedResponseAlg());
|
||||||
configWrapper.setIdTokenSignedResponseAlg(clientOIDC.getIdTokenSignedResponseAlg());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (clientOIDC.getIdTokenEncryptedResponseAlg() != null) {
|
if (clientOIDC.getIdTokenEncryptedResponseAlg() != null) {
|
||||||
configWrapper.setIdTokenEncryptedResponseAlg(clientOIDC.getIdTokenEncryptedResponseAlg());
|
configWrapper.setIdTokenEncryptedResponseAlg(clientOIDC.getIdTokenEncryptedResponseAlg());
|
||||||
|
@ -379,6 +378,10 @@ public class DescriptionConverter {
|
||||||
throw new ClientRegistrationException("Illegal jwks format");
|
throw new ClientRegistrationException("Illegal jwks format");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
String defaultSignatureAlgorithm = session.getContext().getRealm().getDefaultSignatureAlgorithm();
|
||||||
|
if (Algorithm.RS256.equals(defaultSignatureAlgorithm) || StringUtil.isBlank(defaultSignatureAlgorithm)) {
|
||||||
|
defaultSignatureAlgorithm = null;
|
||||||
|
}
|
||||||
// KEYCLOAK-6771 Certificate Bound Token
|
// KEYCLOAK-6771 Certificate Bound Token
|
||||||
// https://tools.ietf.org/html/draft-ietf-oauth-mtls-08#section-6.5
|
// https://tools.ietf.org/html/draft-ietf-oauth-mtls-08#section-6.5
|
||||||
if (config.isUseMtlsHokToken()) {
|
if (config.isUseMtlsHokToken()) {
|
||||||
|
@ -391,6 +394,8 @@ public class DescriptionConverter {
|
||||||
}
|
}
|
||||||
if (config.getIdTokenSignedResponseAlg() != null) {
|
if (config.getIdTokenSignedResponseAlg() != null) {
|
||||||
response.setIdTokenSignedResponseAlg(config.getIdTokenSignedResponseAlg());
|
response.setIdTokenSignedResponseAlg(config.getIdTokenSignedResponseAlg());
|
||||||
|
} else if (defaultSignatureAlgorithm != null){
|
||||||
|
response.setIdTokenSignedResponseAlg(defaultSignatureAlgorithm);
|
||||||
}
|
}
|
||||||
if (config.getIdTokenEncryptedResponseAlg() != null) {
|
if (config.getIdTokenEncryptedResponseAlg() != null) {
|
||||||
response.setIdTokenEncryptedResponseAlg(config.getIdTokenEncryptedResponseAlg());
|
response.setIdTokenEncryptedResponseAlg(config.getIdTokenEncryptedResponseAlg());
|
||||||
|
|
|
@ -0,0 +1,105 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2024 Red Hat, Inc. and/or its affiliates
|
||||||
|
* and other contributors as indicated by the @author tags.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.keycloak.testsuite.client;
|
||||||
|
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.keycloak.client.registration.Auth;
|
||||||
|
import org.keycloak.crypto.Algorithm;
|
||||||
|
import org.keycloak.protocol.oidc.OIDCAdvancedConfigWrapper;
|
||||||
|
import org.keycloak.representations.idm.ClientInitialAccessCreatePresentation;
|
||||||
|
import org.keycloak.representations.idm.ClientInitialAccessPresentation;
|
||||||
|
import org.keycloak.representations.idm.ClientRepresentation;
|
||||||
|
import org.keycloak.representations.oidc.OIDCClientRepresentation;
|
||||||
|
import org.keycloak.testsuite.Assert;
|
||||||
|
import org.keycloak.testsuite.util.TokenSignatureUtil;
|
||||||
|
|
||||||
|
public class OIDCClientRegistrationDefaultSignatureTest extends AbstractClientRegistrationTest {
|
||||||
|
@Before
|
||||||
|
public void before() throws Exception {
|
||||||
|
super.before();
|
||||||
|
|
||||||
|
ClientInitialAccessPresentation token = adminClient.realm(REALM_NAME).clientInitialAccess().create(new ClientInitialAccessCreatePresentation(0, 10));
|
||||||
|
reg.auth(Auth.token(token));
|
||||||
|
}
|
||||||
|
|
||||||
|
private OIDCClientRepresentation createRep() {
|
||||||
|
OIDCClientRepresentation client = new OIDCClientRepresentation();
|
||||||
|
client.setClientName("RegistrationAccessTokenTest");
|
||||||
|
client.setClientUri("http://root");
|
||||||
|
client.setRedirectUris(Collections.singletonList("http://redirect"));
|
||||||
|
client.setFrontChannelLogoutUri("http://frontchannel");
|
||||||
|
client.setFrontchannelLogoutSessionRequired(true);
|
||||||
|
return client;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIdTokenSignedResponse() throws Exception {
|
||||||
|
OIDCClientRepresentation response = null;
|
||||||
|
OIDCClientRepresentation updated = null;
|
||||||
|
try {
|
||||||
|
TokenSignatureUtil.changeRealmTokenSignatureProvider(adminClient, Algorithm.ES512);
|
||||||
|
|
||||||
|
// create (no specification)
|
||||||
|
OIDCClientRepresentation clientRep = createRep();
|
||||||
|
|
||||||
|
response = reg.oidc().create(clientRep);
|
||||||
|
Assert.assertEquals(Algorithm.ES512, response.getIdTokenSignedResponseAlg());
|
||||||
|
|
||||||
|
// Test Keycloak representation
|
||||||
|
ClientRepresentation kcClient = getClient(response.getClientId());
|
||||||
|
OIDCAdvancedConfigWrapper config = OIDCAdvancedConfigWrapper.fromClientRepresentation(kcClient);
|
||||||
|
// Client representation of id.token.signed.response.alg is null as from realm
|
||||||
|
Assert.assertNull(config.getIdTokenSignedResponseAlg());
|
||||||
|
|
||||||
|
// update
|
||||||
|
reg.auth(Auth.token(response));
|
||||||
|
response.setIdTokenSignedResponseAlg(Algorithm.ES256);
|
||||||
|
updated = reg.oidc().update(response);
|
||||||
|
Assert.assertEquals(Algorithm.ES256, updated.getIdTokenSignedResponseAlg());
|
||||||
|
|
||||||
|
// Test Keycloak representation
|
||||||
|
kcClient = getClient(updated.getClientId());
|
||||||
|
config = OIDCAdvancedConfigWrapper.fromClientRepresentation(kcClient);
|
||||||
|
Assert.assertEquals(Algorithm.ES256, config.getIdTokenSignedResponseAlg());
|
||||||
|
|
||||||
|
// update after changing default realm token signature
|
||||||
|
TokenSignatureUtil.changeRealmTokenSignatureProvider(adminClient, Algorithm.ES384);
|
||||||
|
reg.auth(Auth.token(updated));
|
||||||
|
updated.setIdTokenSignedResponseAlg(null);
|
||||||
|
response = reg.oidc().update(updated);
|
||||||
|
Assert.assertEquals(Algorithm.ES384, response.getIdTokenSignedResponseAlg());
|
||||||
|
} finally {
|
||||||
|
// revert
|
||||||
|
TokenSignatureUtil.changeRealmTokenSignatureProvider(adminClient, Algorithm.RS256);
|
||||||
|
reg.auth(Auth.token(response));
|
||||||
|
response.setIdTokenSignedResponseAlg(null);
|
||||||
|
updated = reg.oidc().update(response);
|
||||||
|
Assert.assertNull(updated.getIdTokenSignedResponseAlg());
|
||||||
|
|
||||||
|
// Test Keycloak representation
|
||||||
|
ClientRepresentation kcClient = getClient(updated.getClientId());
|
||||||
|
OIDCAdvancedConfigWrapper config = OIDCAdvancedConfigWrapper.fromClientRepresentation(kcClient);
|
||||||
|
// Client representation of id.token.signed.response.alg is null as from realm
|
||||||
|
Assert.assertNull(config.getIdTokenSignedResponseAlg());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -477,6 +477,40 @@ public class OIDCClientRegistrationTest extends AbstractClientRegistrationTest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIdTokenSignedResponse() throws Exception {
|
||||||
|
OIDCClientRepresentation response = null;
|
||||||
|
OIDCClientRepresentation updated = null;
|
||||||
|
try {
|
||||||
|
// create (no specification)
|
||||||
|
OIDCClientRepresentation clientRep = createRep();
|
||||||
|
|
||||||
|
response = reg.oidc().create(clientRep);
|
||||||
|
Assert.assertNull(response.getIdTokenSignedResponseAlg());
|
||||||
|
|
||||||
|
// Test Keycloak representation
|
||||||
|
ClientRepresentation kcClient = getClient(response.getClientId());
|
||||||
|
OIDCAdvancedConfigWrapper config = OIDCAdvancedConfigWrapper.fromClientRepresentation(kcClient);
|
||||||
|
Assert.assertNull(config.getIdTokenSignedResponseAlg());
|
||||||
|
|
||||||
|
// update
|
||||||
|
reg.auth(Auth.token(response));
|
||||||
|
response.setIdTokenSignedResponseAlg(Algorithm.ES256);
|
||||||
|
updated = reg.oidc().update(response);
|
||||||
|
Assert.assertEquals(Algorithm.ES256, updated.getIdTokenSignedResponseAlg());
|
||||||
|
|
||||||
|
// Test Keycloak representation
|
||||||
|
kcClient = getClient(updated.getClientId());
|
||||||
|
config = OIDCAdvancedConfigWrapper.fromClientRepresentation(kcClient);
|
||||||
|
Assert.assertEquals(Algorithm.ES256, config.getIdTokenSignedResponseAlg());
|
||||||
|
} finally {
|
||||||
|
// revert
|
||||||
|
reg.auth(Auth.token(updated));
|
||||||
|
updated.setIdTokenSignedResponseAlg(null);
|
||||||
|
reg.oidc().update(updated);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testTokenEndpointSigningAlg() throws Exception {
|
public void testTokenEndpointSigningAlg() throws Exception {
|
||||||
OIDCClientRepresentation response = null;
|
OIDCClientRepresentation response = null;
|
||||||
|
|
Loading…
Reference in a new issue