From 6fd4a02f955fd6570bd96d0193b59880f659774a Mon Sep 17 00:00:00 2001 From: Pedro Igor Date: Thu, 4 Oct 2018 19:27:43 -0300 Subject: [PATCH] [KEYCLOAK-8444] - Error when producing KeycloakSpringBootConfigResolver from spring security configuration --- .../KeycloakBaseSpringBootConfiguration.java | 14 +++--- .../KeycloakSpringBootConfigResolver.java | 22 +++------ ...ycloakSpringBootConfigResolverWrapper.java | 48 +++++++++++++++++++ .../KeycloakSpringConfigResolverWrapper.java | 46 ++++++++++++++++++ .../KeycloakWebSecurityConfigurerAdapter.java | 2 +- 5 files changed, 108 insertions(+), 24 deletions(-) create mode 100644 adapters/oidc/spring-boot-adapter-core/src/main/java/org/keycloak/adapters/springboot/KeycloakSpringBootConfigResolverWrapper.java create mode 100644 adapters/oidc/spring-security/src/main/java/org/keycloak/adapters/springsecurity/config/KeycloakSpringConfigResolverWrapper.java diff --git a/adapters/oidc/spring-boot-adapter-core/src/main/java/org/keycloak/adapters/springboot/KeycloakBaseSpringBootConfiguration.java b/adapters/oidc/spring-boot-adapter-core/src/main/java/org/keycloak/adapters/springboot/KeycloakBaseSpringBootConfiguration.java index 143368a007..47bc708718 100755 --- a/adapters/oidc/spring-boot-adapter-core/src/main/java/org/keycloak/adapters/springboot/KeycloakBaseSpringBootConfiguration.java +++ b/adapters/oidc/spring-boot-adapter-core/src/main/java/org/keycloak/adapters/springboot/KeycloakBaseSpringBootConfiguration.java @@ -32,10 +32,10 @@ import org.eclipse.jetty.server.handler.HandlerList; import org.eclipse.jetty.server.handler.HandlerWrapper; import org.eclipse.jetty.util.security.Constraint; import org.eclipse.jetty.webapp.WebAppContext; -import org.keycloak.adapters.KeycloakConfigResolver; import org.keycloak.adapters.jetty.KeycloakJettyAuthenticator; import org.keycloak.adapters.undertow.KeycloakServletExtension; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; import java.util.ArrayList; import java.util.HashSet; @@ -55,9 +55,9 @@ public class KeycloakBaseSpringBootConfiguration { KeycloakSpringBootConfigResolver.setAdapterConfig(keycloakProperties); } - @Autowired (required = false) - public void setKeycloakConfigResolvers(KeycloakConfigResolver configResolver) { - KeycloakSpringBootConfigResolver.setDelegateConfigResolver(configResolver); + @Autowired + public void setApplicationContext(ApplicationContext context) { + KeycloakSpringBootConfigResolverWrapper.setApplicationContext(context); } static class KeycloakBaseUndertowDeploymentInfoCustomizer { @@ -75,7 +75,7 @@ public class KeycloakBaseSpringBootConfiguration { deploymentInfo.setLoginConfig(loginConfig); - deploymentInfo.addInitParameter("keycloak.config.resolver", KeycloakSpringBootConfigResolver.class.getName()); + deploymentInfo.addInitParameter("keycloak.config.resolver", KeycloakSpringBootConfigResolverWrapper.class.getName()); deploymentInfo.addSecurityConstraints(getSecurityConstraints()); deploymentInfo.addServletExtension(new KeycloakServletExtension()); @@ -117,7 +117,7 @@ public class KeycloakBaseSpringBootConfiguration { public void customize(Server server) { KeycloakJettyAuthenticator keycloakJettyAuthenticator = new KeycloakJettyAuthenticator(); - keycloakJettyAuthenticator.setConfigResolver(new KeycloakSpringBootConfigResolver()); + keycloakJettyAuthenticator.setConfigResolver(new KeycloakSpringBootConfigResolverWrapper()); /* see org.eclipse.jetty.webapp.StandardDescriptorProcessor#visitSecurityConstraint for an example on how to map servlet spec to Constraints */ @@ -268,7 +268,7 @@ public class KeycloakBaseSpringBootConfiguration { context.addConstraint(tomcatConstraint); } - context.addParameter("keycloak.config.resolver", KeycloakSpringBootConfigResolver.class.getName()); + context.addParameter("keycloak.config.resolver", KeycloakSpringBootConfigResolverWrapper.class.getName()); } } } diff --git a/adapters/oidc/spring-boot-adapter-core/src/main/java/org/keycloak/adapters/springboot/KeycloakSpringBootConfigResolver.java b/adapters/oidc/spring-boot-adapter-core/src/main/java/org/keycloak/adapters/springboot/KeycloakSpringBootConfigResolver.java index 8e809c5480..2f90402cf6 100755 --- a/adapters/oidc/spring-boot-adapter-core/src/main/java/org/keycloak/adapters/springboot/KeycloakSpringBootConfigResolver.java +++ b/adapters/oidc/spring-boot-adapter-core/src/main/java/org/keycloak/adapters/springboot/KeycloakSpringBootConfigResolver.java @@ -17,7 +17,6 @@ package org.keycloak.adapters.springboot; -import org.keycloak.adapters.KeycloakConfigResolver; import org.keycloak.adapters.KeycloakDeployment; import org.keycloak.adapters.KeycloakDeploymentBuilder; import org.keycloak.adapters.OIDCHttpFacade; @@ -25,31 +24,22 @@ import org.keycloak.representations.adapters.config.AdapterConfig; public class KeycloakSpringBootConfigResolver implements org.keycloak.adapters.KeycloakConfigResolver { - private static AdapterConfig adapterConfig; - private static KeycloakConfigResolver delegateConfigResolver; - private KeycloakDeployment keycloakDeployment; + private static AdapterConfig adapterConfig; + @Override public KeycloakDeployment resolve(OIDCHttpFacade.Request request) { - if (delegateConfigResolver == null) { - if (keycloakDeployment != null) { - return keycloakDeployment; - } - - keycloakDeployment = KeycloakDeploymentBuilder.build(KeycloakSpringBootConfigResolver.adapterConfig); - + if (keycloakDeployment != null) { return keycloakDeployment; } - return delegateConfigResolver.resolve(request); + keycloakDeployment = KeycloakDeploymentBuilder.build(KeycloakSpringBootConfigResolver.adapterConfig); + + return keycloakDeployment; } static void setAdapterConfig(AdapterConfig adapterConfig) { KeycloakSpringBootConfigResolver.adapterConfig = adapterConfig; } - - static void setDelegateConfigResolver(KeycloakConfigResolver configResolver) { - KeycloakSpringBootConfigResolver.delegateConfigResolver = configResolver; - } } \ No newline at end of file diff --git a/adapters/oidc/spring-boot-adapter-core/src/main/java/org/keycloak/adapters/springboot/KeycloakSpringBootConfigResolverWrapper.java b/adapters/oidc/spring-boot-adapter-core/src/main/java/org/keycloak/adapters/springboot/KeycloakSpringBootConfigResolverWrapper.java new file mode 100644 index 0000000000..34ae3adefb --- /dev/null +++ b/adapters/oidc/spring-boot-adapter-core/src/main/java/org/keycloak/adapters/springboot/KeycloakSpringBootConfigResolverWrapper.java @@ -0,0 +1,48 @@ +/* + * Copyright 2018 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.adapters.springboot; + +import org.keycloak.adapters.KeycloakConfigResolver; +import org.keycloak.adapters.springsecurity.config.KeycloakSpringConfigResolverWrapper; +import org.springframework.beans.factory.NoSuchBeanDefinitionException; +import org.springframework.context.ApplicationContext; + +/** + *

A specific implementation of {@link KeycloakSpringConfigResolverWrapper} that first tries to register any {@link KeycloakConfigResolver} + * instance provided by the application. if none is provided, {@link KeycloakSpringBootConfigResolver} is set. + * + *

This implementation is specially useful when using Spring Boot and Spring Security in the same application where the same {@link KeycloakConfigResolver} + * instance must be used across the different stacks. + * + * @author Pedro Igor + */ +public class KeycloakSpringBootConfigResolverWrapper extends KeycloakSpringConfigResolverWrapper { + + private static ApplicationContext context; + + public KeycloakSpringBootConfigResolverWrapper() { + super(new KeycloakSpringBootConfigResolver()); + try { + setDelegate(context.getBean(KeycloakConfigResolver.class)); + } catch (NoSuchBeanDefinitionException ignore) { + } + } + + public static void setApplicationContext(ApplicationContext context) { + KeycloakSpringBootConfigResolverWrapper.context = context; + } +} diff --git a/adapters/oidc/spring-security/src/main/java/org/keycloak/adapters/springsecurity/config/KeycloakSpringConfigResolverWrapper.java b/adapters/oidc/spring-security/src/main/java/org/keycloak/adapters/springsecurity/config/KeycloakSpringConfigResolverWrapper.java new file mode 100644 index 0000000000..d467f320b2 --- /dev/null +++ b/adapters/oidc/spring-security/src/main/java/org/keycloak/adapters/springsecurity/config/KeycloakSpringConfigResolverWrapper.java @@ -0,0 +1,46 @@ +/* + * Copyright 2018 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.adapters.springsecurity.config; + +import org.keycloak.adapters.KeycloakConfigResolver; +import org.keycloak.adapters.KeycloakDeployment; +import org.keycloak.adapters.spi.HttpFacade; + +/** + * Spring applications may use different security stacks in order to enforce access based on the configuration provided + * by a {@code KeycloakDeployment}. This implementation of {@code KeycloakConfigResolver} wraps and avoid calling multiple + * {@code KeycloakConfigResolver} instances but only those defined by applications or set as default by the configuration. + * + * @author Pedro Igor + */ +public class KeycloakSpringConfigResolverWrapper implements KeycloakConfigResolver { + + private KeycloakConfigResolver delegate; + + public KeycloakSpringConfigResolverWrapper(KeycloakConfigResolver delegate) { + this.delegate = delegate; + } + + @Override + public KeycloakDeployment resolve(HttpFacade.Request facade) { + return delegate.resolve(facade); + } + + protected void setDelegate(KeycloakConfigResolver delegate) { + this.delegate = delegate; + } +} diff --git a/adapters/oidc/spring-security/src/main/java/org/keycloak/adapters/springsecurity/config/KeycloakWebSecurityConfigurerAdapter.java b/adapters/oidc/spring-security/src/main/java/org/keycloak/adapters/springsecurity/config/KeycloakWebSecurityConfigurerAdapter.java index 2f27b5899c..9d344971da 100644 --- a/adapters/oidc/spring-security/src/main/java/org/keycloak/adapters/springsecurity/config/KeycloakWebSecurityConfigurerAdapter.java +++ b/adapters/oidc/spring-security/src/main/java/org/keycloak/adapters/springsecurity/config/KeycloakWebSecurityConfigurerAdapter.java @@ -65,7 +65,7 @@ public abstract class KeycloakWebSecurityConfigurerAdapter extends WebSecurityCo protected AdapterDeploymentContext adapterDeploymentContext() throws Exception { AdapterDeploymentContextFactoryBean factoryBean; if (keycloakConfigResolver != null) { - factoryBean = new AdapterDeploymentContextFactoryBean(keycloakConfigResolver); + factoryBean = new AdapterDeploymentContextFactoryBean(new KeycloakSpringConfigResolverWrapper(keycloakConfigResolver)); } else { factoryBean = new AdapterDeploymentContextFactoryBean(keycloakConfigFileResource);