From 9c01d819cb8d1709503e61db62f630686d5a1c5e Mon Sep 17 00:00:00 2001 From: Takashi Norimatsu Date: Thu, 6 Jan 2022 08:56:03 +0900 Subject: [PATCH] Client Policies : An executor rejecting all requests Closes #9097 --- .../executor/RejectRequestExecutor.java | 43 ++++++++++++ .../RejectRequestExecutorFactory.java | 66 +++++++++++++++++++ ...ecutor.ClientPolicyExecutorProviderFactory | 3 +- .../client/AbstractClientPoliciesTest.java | 1 + .../testsuite/client/ClientPoliciesTest.java | 38 +++++++++++ 5 files changed, 150 insertions(+), 1 deletion(-) create mode 100644 services/src/main/java/org/keycloak/services/clientpolicy/executor/RejectRequestExecutor.java create mode 100644 services/src/main/java/org/keycloak/services/clientpolicy/executor/RejectRequestExecutorFactory.java diff --git a/services/src/main/java/org/keycloak/services/clientpolicy/executor/RejectRequestExecutor.java b/services/src/main/java/org/keycloak/services/clientpolicy/executor/RejectRequestExecutor.java new file mode 100644 index 0000000000..f80337b261 --- /dev/null +++ b/services/src/main/java/org/keycloak/services/clientpolicy/executor/RejectRequestExecutor.java @@ -0,0 +1,43 @@ +/* + * 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.OAuthErrorException; +import org.keycloak.models.KeycloakSession; +import org.keycloak.representations.idm.ClientPolicyExecutorConfigurationRepresentation; +import org.keycloak.services.clientpolicy.ClientPolicyContext; +import org.keycloak.services.clientpolicy.ClientPolicyException; + +/** + * @author Takashi Norimatsu + */ +public class RejectRequestExecutor implements ClientPolicyExecutorProvider { + + public RejectRequestExecutor(KeycloakSession session) { + } + + @Override + public String getProviderId() { + return RejectRequestExecutorFactory.PROVIDER_ID; + } + + @Override + public void executeOnEvent(ClientPolicyContext context) throws ClientPolicyException { + throw new ClientPolicyException(OAuthErrorException.INVALID_REQUEST, "request not allowed"); + } +} diff --git a/services/src/main/java/org/keycloak/services/clientpolicy/executor/RejectRequestExecutorFactory.java b/services/src/main/java/org/keycloak/services/clientpolicy/executor/RejectRequestExecutorFactory.java new file mode 100644 index 0000000000..0f069c2c14 --- /dev/null +++ b/services/src/main/java/org/keycloak/services/clientpolicy/executor/RejectRequestExecutorFactory.java @@ -0,0 +1,66 @@ +/* + * 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.Scope; +import org.keycloak.models.KeycloakSession; +import org.keycloak.models.KeycloakSessionFactory; +import org.keycloak.provider.ProviderConfigProperty; + +/** + * @author Takashi Norimatsu + */ +public class RejectRequestExecutorFactory implements ClientPolicyExecutorProviderFactory { + + public static final String PROVIDER_ID = "reject-request"; + + @Override + public ClientPolicyExecutorProvider create(KeycloakSession session) { + return new RejectRequestExecutor(session); + } + + @Override + public void init(Scope config) { + } + + @Override + public void postInit(KeycloakSessionFactory factory) { + } + + @Override + public void close() { + } + + @Override + public String getId() { + return PROVIDER_ID; + } + + @Override + public String getHelpText() { + return "It rejects all requests from clients."; + } + + @Override + public List getConfigProperties() { + return Collections.emptyList(); + } +} diff --git a/services/src/main/resources/META-INF/services/org.keycloak.services.clientpolicy.executor.ClientPolicyExecutorProviderFactory b/services/src/main/resources/META-INF/services/org.keycloak.services.clientpolicy.executor.ClientPolicyExecutorProviderFactory index 43d03ba9c6..4e39c85116 100644 --- a/services/src/main/resources/META-INF/services/org.keycloak.services.clientpolicy.executor.ClientPolicyExecutorProviderFactory +++ b/services/src/main/resources/META-INF/services/org.keycloak.services.clientpolicy.executor.ClientPolicyExecutorProviderFactory @@ -15,4 +15,5 @@ org.keycloak.protocol.oidc.grants.ciba.clientpolicy.executor.SecureCibaSignedAut org.keycloak.protocol.oidc.grants.ciba.clientpolicy.executor.SecureCibaAuthenticationRequestSigningAlgorithmExecutorFactory org.keycloak.services.clientpolicy.executor.SecureLogoutExecutorFactory org.keycloak.services.clientpolicy.executor.RejectResourceOwnerPasswordCredentialsGrantExecutorFactory -org.keycloak.services.clientpolicy.executor.ClientSecretRotationExecutorFactory \ No newline at end of file +org.keycloak.services.clientpolicy.executor.ClientSecretRotationExecutorFactory +org.keycloak.services.clientpolicy.executor.RejectRequestExecutorFactory diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/client/AbstractClientPoliciesTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/client/AbstractClientPoliciesTest.java index d59fabee79..c7fb6677e2 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/client/AbstractClientPoliciesTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/client/AbstractClientPoliciesTest.java @@ -181,6 +181,7 @@ public abstract class AbstractClientPoliciesTest extends AbstractKeycloakTest { protected static final String ERR_MSG_MISSING_NONCE = "Missing parameter: nonce"; protected static final String ERR_MSG_MISSING_STATE = "Missing parameter: state"; protected static final String ERR_MSG_CLIENT_REG_FAIL = "Failed to send request"; + protected static final String ERR_MSG_REQ_NOT_ALLOWED = "request not allowed"; protected ClientRegistration reg; diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/client/ClientPoliciesTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/client/ClientPoliciesTest.java index fdc8df1377..d05b7702bc 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/client/ClientPoliciesTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/client/ClientPoliciesTest.java @@ -79,6 +79,7 @@ import org.keycloak.services.clientpolicy.executor.ConsentRequiredExecutorFactor import org.keycloak.services.clientpolicy.executor.FullScopeDisabledExecutorFactory; import org.keycloak.services.clientpolicy.executor.HolderOfKeyEnforcerExecutorFactory; import org.keycloak.services.clientpolicy.executor.PKCEEnforcerExecutorFactory; +import org.keycloak.services.clientpolicy.executor.RejectRequestExecutorFactory; import org.keycloak.services.clientpolicy.executor.RejectResourceOwnerPasswordCredentialsGrantExecutorFactory; import org.keycloak.services.clientpolicy.executor.SecureClientAuthenticatorExecutorFactory; import org.keycloak.services.clientpolicy.executor.SecureClientUrisExecutorFactory; @@ -2738,6 +2739,43 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest { } + @Test + public void testRejectRequestExecutor() throws Exception { + // register profiles + String json = (new ClientProfilesBuilder()).addProfile( + (new ClientProfileBuilder()).createProfile(PROFILE_NAME, "Le Premier Profil") + .addExecutor(RejectRequestExecutorFactory.PROVIDER_ID, null) + .toRepresentation() + ).toString(); + updateProfiles(json); + + String clientBetaId = generateSuffixedName("Beta-App"); + createClientByAdmin(clientBetaId, (ClientRepresentation clientRep) -> { + clientRep.setSecret("secretBeta"); + }); + + // register policies + json = (new ClientPoliciesBuilder()).addPolicy( + (new ClientPolicyBuilder()).createPolicy(POLICY_NAME, "La Premiere Politique", Boolean.TRUE) + .addCondition(AnyClientConditionFactory.PROVIDER_ID, + createAnyClientConditionConfig()) + .addProfile(PROFILE_NAME) + .toRepresentation() + ).toString(); + updatePolicies(json); + + try { + oauth.clientId(clientBetaId); + oauth.openLoginForm(); + assertEquals(OAuthErrorException.INVALID_REQUEST, oauth.getCurrentQuery().get(OAuth2Constants.ERROR)); + assertEquals(ERR_MSG_REQ_NOT_ALLOWED, oauth.getCurrentQuery().get(OAuth2Constants.ERROR_DESCRIPTION)); + revertToBuiltinProfiles(); + successfulLoginAndLogout(clientBetaId, "secretBeta"); + } catch (Exception e) { + fail(); + } + } + private void openVerificationPage(String verificationUri) { driver.navigate().to(verificationUri); }