Allowing client registration access token rotation deactivation
This commit is contained in:
parent
e374e309c6
commit
dbe0c27bcf
6 changed files with 189 additions and 2 deletions
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* Copyright 2022 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.models;
|
||||
|
||||
public class ClientRegistrationAccessTokenConstants {
|
||||
|
||||
public static final String ROTATION_ENABLED = "client.registration.access.token.enabled";
|
||||
|
||||
private ClientRegistrationAccessTokenConstants(){}
|
||||
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* Copyright 2022 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.services.clientpolicy.executor;
|
||||
|
||||
import org.keycloak.models.ClientRegistrationAccessTokenConstants;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.representations.idm.ClientPolicyExecutorConfigurationRepresentation;
|
||||
import org.keycloak.services.clientpolicy.ClientPolicyContext;
|
||||
import org.keycloak.services.clientpolicy.ClientPolicyException;
|
||||
|
||||
public class RegistrationAccessTokenRotationDisabledExecutor implements ClientPolicyExecutorProvider<ClientPolicyExecutorConfigurationRepresentation> {
|
||||
|
||||
private final String providerId;
|
||||
private final KeycloakSession session;
|
||||
|
||||
public RegistrationAccessTokenRotationDisabledExecutor(String providerId, KeycloakSession session) {
|
||||
this.providerId = providerId;
|
||||
this.session = session;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getProviderId() {
|
||||
return providerId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void executeOnEvent(ClientPolicyContext context) throws ClientPolicyException {
|
||||
if (session.getAttribute(ClientRegistrationAccessTokenConstants.ROTATION_ENABLED) == null){
|
||||
return;
|
||||
}
|
||||
session.setAttribute(ClientRegistrationAccessTokenConstants.ROTATION_ENABLED, false);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
* Copyright 2022 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.services.clientpolicy.executor;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import org.keycloak.Config;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.KeycloakSessionFactory;
|
||||
import org.keycloak.provider.ProviderConfigProperty;
|
||||
|
||||
public class RegistrationAccessTokenRotationDisabledExecutorFactory implements ClientPolicyExecutorProviderFactory {
|
||||
|
||||
public static final String PROVIDER_ID = "registration-access-token-rotation-disabled";
|
||||
|
||||
@Override
|
||||
public String getHelpText() {
|
||||
return "Disables registration access rotation for the client.";
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ProviderConfigProperty> getConfigProperties() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClientPolicyExecutorProvider create(KeycloakSession session) {
|
||||
return new RegistrationAccessTokenRotationDisabledExecutor(getId(), session);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(Config.Scope config) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postInit(KeycloakSessionFactory factory) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return PROVIDER_ID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSupported() {
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -22,6 +22,7 @@ import org.keycloak.events.EventBuilder;
|
|||
import org.keycloak.events.EventType;
|
||||
import org.keycloak.models.ClientInitialAccessModel;
|
||||
import org.keycloak.models.ClientModel;
|
||||
import org.keycloak.models.ClientRegistrationAccessTokenConstants;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.ModelDuplicateException;
|
||||
import org.keycloak.models.RealmModel;
|
||||
|
@ -142,6 +143,7 @@ public abstract class AbstractClientRegistrationProvider implements ClientRegist
|
|||
event.event(EventType.CLIENT_UPDATE).client(clientId);
|
||||
|
||||
ClientModel client = session.getContext().getRealm().getClientByClientId(clientId);
|
||||
session.setAttribute(ClientRegistrationAccessTokenConstants.ROTATION_ENABLED, true);
|
||||
RegistrationAuth registrationAuth = auth.requireUpdate(context, client);
|
||||
|
||||
if (!client.getClientId().equals(rep.getClientId())) {
|
||||
|
@ -165,9 +167,15 @@ public abstract class AbstractClientRegistrationProvider implements ClientRegist
|
|||
}
|
||||
|
||||
if (auth.isRegistrationAccessToken()) {
|
||||
String registrationAccessToken = ClientRegistrationTokenUtils.updateRegistrationAccessToken(session, client, auth.getRegistrationAuth());
|
||||
String registrationAccessToken;
|
||||
if ((boolean) session.getAttribute(ClientRegistrationAccessTokenConstants.ROTATION_ENABLED)) {
|
||||
registrationAccessToken = ClientRegistrationTokenUtils.updateRegistrationAccessToken(session, client, auth.getRegistrationAuth());
|
||||
} else {
|
||||
registrationAccessToken = ClientRegistrationTokenUtils.updateTokenSignature(session, auth);
|
||||
}
|
||||
rep.setRegistrationAccessToken(registrationAccessToken);
|
||||
}
|
||||
session.removeAttribute(ClientRegistrationAccessTokenConstants.ROTATION_ENABLED);
|
||||
|
||||
try {
|
||||
session.getContext().setClient(client);
|
||||
|
|
|
@ -18,4 +18,5 @@ org.keycloak.services.clientpolicy.executor.RejectResourceOwnerPasswordCredentia
|
|||
org.keycloak.services.clientpolicy.executor.ClientSecretRotationExecutorFactory
|
||||
org.keycloak.services.clientpolicy.executor.RejectRequestExecutorFactory
|
||||
org.keycloak.services.clientpolicy.executor.IntentClientBindCheckExecutorFactory
|
||||
org.keycloak.services.clientpolicy.executor.SuppressRefreshTokenRotationExecutorFactory
|
||||
org.keycloak.services.clientpolicy.executor.SuppressRefreshTokenRotationExecutorFactory
|
||||
org.keycloak.services.clientpolicy.executor.RegistrationAccessTokenRotationDisabledExecutorFactory
|
||||
|
|
|
@ -111,6 +111,7 @@ import org.keycloak.services.clientpolicy.executor.FullScopeDisabledExecutorFact
|
|||
import org.keycloak.services.clientpolicy.executor.HolderOfKeyEnforcerExecutorFactory;
|
||||
import org.keycloak.services.clientpolicy.executor.IntentClientBindCheckExecutorFactory;
|
||||
import org.keycloak.services.clientpolicy.executor.PKCEEnforcerExecutorFactory;
|
||||
import org.keycloak.services.clientpolicy.executor.RegistrationAccessTokenRotationDisabledExecutorFactory;
|
||||
import org.keycloak.services.clientpolicy.executor.RejectRequestExecutorFactory;
|
||||
import org.keycloak.services.clientpolicy.executor.RejectResourceOwnerPasswordCredentialsGrantExecutorFactory;
|
||||
import org.keycloak.services.clientpolicy.executor.SecureClientAuthenticatorExecutorFactory;
|
||||
|
@ -3391,6 +3392,38 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
|
|||
assertEquals("no claim for an intent value for ID token" , oauth.getCurrentFragment().get(OAuth2Constants.ERROR_DESCRIPTION));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRegistrationAccessTokenRotationDisabledExecutor() throws Exception {
|
||||
// register profiles - client autoConfigured to disable registration access token rotation
|
||||
String json = new ClientProfilesBuilder().addProfile(
|
||||
new ClientProfileBuilder().createProfile(PROFILE_NAME, "Test Profile")
|
||||
.addExecutor(
|
||||
RegistrationAccessTokenRotationDisabledExecutorFactory.PROVIDER_ID,
|
||||
new ClientPolicyExecutorConfigurationRepresentation()
|
||||
)
|
||||
.toRepresentation()
|
||||
).toString();
|
||||
updateProfiles(json);
|
||||
|
||||
// register policies
|
||||
json = new ClientPoliciesBuilder().addPolicy(
|
||||
new ClientPolicyBuilder().createPolicy(POLICY_NAME, "Test Policy", Boolean.TRUE)
|
||||
.addCondition(AnyClientConditionFactory.PROVIDER_ID,
|
||||
createAnyClientConditionConfig())
|
||||
.addProfile(PROFILE_NAME)
|
||||
.toRepresentation()
|
||||
).toString();
|
||||
updatePolicies(json);
|
||||
|
||||
String clientId = createClientDynamically(generateSuffixedName(CLIENT_NAME), r -> {});
|
||||
OIDCClientRepresentation createdClient = getClientDynamically(clientId);
|
||||
|
||||
updateClientDynamically(clientId, clientRep ->
|
||||
clientRep.setTokenEndpointAuthMethod(OIDCLoginProtocol.CLIENT_SECRET_BASIC));
|
||||
|
||||
assertEquals(createdClient.getRegistrationAccessToken(), getClientDynamically(clientId).getRegistrationAccessToken());
|
||||
}
|
||||
|
||||
private void openVerificationPage(String verificationUri) {
|
||||
driver.navigate().to(verificationUri);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue