[KEYCLOAK-8444] - Error when producing KeycloakSpringBootConfigResolver from spring security configuration

This commit is contained in:
Pedro Igor 2018-10-04 19:27:43 -03:00
parent 531ee3a1be
commit 6fd4a02f95
5 changed files with 108 additions and 24 deletions

View file

@ -32,10 +32,10 @@ import org.eclipse.jetty.server.handler.HandlerList;
import org.eclipse.jetty.server.handler.HandlerWrapper; import org.eclipse.jetty.server.handler.HandlerWrapper;
import org.eclipse.jetty.util.security.Constraint; import org.eclipse.jetty.util.security.Constraint;
import org.eclipse.jetty.webapp.WebAppContext; import org.eclipse.jetty.webapp.WebAppContext;
import org.keycloak.adapters.KeycloakConfigResolver;
import org.keycloak.adapters.jetty.KeycloakJettyAuthenticator; import org.keycloak.adapters.jetty.KeycloakJettyAuthenticator;
import org.keycloak.adapters.undertow.KeycloakServletExtension; import org.keycloak.adapters.undertow.KeycloakServletExtension;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashSet; import java.util.HashSet;
@ -55,9 +55,9 @@ public class KeycloakBaseSpringBootConfiguration {
KeycloakSpringBootConfigResolver.setAdapterConfig(keycloakProperties); KeycloakSpringBootConfigResolver.setAdapterConfig(keycloakProperties);
} }
@Autowired (required = false) @Autowired
public void setKeycloakConfigResolvers(KeycloakConfigResolver configResolver) { public void setApplicationContext(ApplicationContext context) {
KeycloakSpringBootConfigResolver.setDelegateConfigResolver(configResolver); KeycloakSpringBootConfigResolverWrapper.setApplicationContext(context);
} }
static class KeycloakBaseUndertowDeploymentInfoCustomizer { static class KeycloakBaseUndertowDeploymentInfoCustomizer {
@ -75,7 +75,7 @@ public class KeycloakBaseSpringBootConfiguration {
deploymentInfo.setLoginConfig(loginConfig); deploymentInfo.setLoginConfig(loginConfig);
deploymentInfo.addInitParameter("keycloak.config.resolver", KeycloakSpringBootConfigResolver.class.getName()); deploymentInfo.addInitParameter("keycloak.config.resolver", KeycloakSpringBootConfigResolverWrapper.class.getName());
deploymentInfo.addSecurityConstraints(getSecurityConstraints()); deploymentInfo.addSecurityConstraints(getSecurityConstraints());
deploymentInfo.addServletExtension(new KeycloakServletExtension()); deploymentInfo.addServletExtension(new KeycloakServletExtension());
@ -117,7 +117,7 @@ public class KeycloakBaseSpringBootConfiguration {
public void customize(Server server) { public void customize(Server server) {
KeycloakJettyAuthenticator keycloakJettyAuthenticator = new KeycloakJettyAuthenticator(); KeycloakJettyAuthenticator keycloakJettyAuthenticator = new KeycloakJettyAuthenticator();
keycloakJettyAuthenticator.setConfigResolver(new KeycloakSpringBootConfigResolver()); keycloakJettyAuthenticator.setConfigResolver(new KeycloakSpringBootConfigResolverWrapper());
/* see org.eclipse.jetty.webapp.StandardDescriptorProcessor#visitSecurityConstraint for an example /* see org.eclipse.jetty.webapp.StandardDescriptorProcessor#visitSecurityConstraint for an example
on how to map servlet spec to Constraints */ on how to map servlet spec to Constraints */
@ -268,7 +268,7 @@ public class KeycloakBaseSpringBootConfiguration {
context.addConstraint(tomcatConstraint); context.addConstraint(tomcatConstraint);
} }
context.addParameter("keycloak.config.resolver", KeycloakSpringBootConfigResolver.class.getName()); context.addParameter("keycloak.config.resolver", KeycloakSpringBootConfigResolverWrapper.class.getName());
} }
} }
} }

View file

@ -17,7 +17,6 @@
package org.keycloak.adapters.springboot; package org.keycloak.adapters.springboot;
import org.keycloak.adapters.KeycloakConfigResolver;
import org.keycloak.adapters.KeycloakDeployment; import org.keycloak.adapters.KeycloakDeployment;
import org.keycloak.adapters.KeycloakDeploymentBuilder; import org.keycloak.adapters.KeycloakDeploymentBuilder;
import org.keycloak.adapters.OIDCHttpFacade; import org.keycloak.adapters.OIDCHttpFacade;
@ -25,14 +24,12 @@ import org.keycloak.representations.adapters.config.AdapterConfig;
public class KeycloakSpringBootConfigResolver implements org.keycloak.adapters.KeycloakConfigResolver { public class KeycloakSpringBootConfigResolver implements org.keycloak.adapters.KeycloakConfigResolver {
private static AdapterConfig adapterConfig;
private static KeycloakConfigResolver delegateConfigResolver;
private KeycloakDeployment keycloakDeployment; private KeycloakDeployment keycloakDeployment;
private static AdapterConfig adapterConfig;
@Override @Override
public KeycloakDeployment resolve(OIDCHttpFacade.Request request) { public KeycloakDeployment resolve(OIDCHttpFacade.Request request) {
if (delegateConfigResolver == null) {
if (keycloakDeployment != null) { if (keycloakDeployment != null) {
return keycloakDeployment; return keycloakDeployment;
} }
@ -42,14 +39,7 @@ public class KeycloakSpringBootConfigResolver implements org.keycloak.adapters.K
return keycloakDeployment; return keycloakDeployment;
} }
return delegateConfigResolver.resolve(request);
}
static void setAdapterConfig(AdapterConfig adapterConfig) { static void setAdapterConfig(AdapterConfig adapterConfig) {
KeycloakSpringBootConfigResolver.adapterConfig = adapterConfig; KeycloakSpringBootConfigResolver.adapterConfig = adapterConfig;
} }
static void setDelegateConfigResolver(KeycloakConfigResolver configResolver) {
KeycloakSpringBootConfigResolver.delegateConfigResolver = configResolver;
}
} }

View file

@ -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;
/**
* <p>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.
*
* <p>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 <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
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;
}
}

View file

@ -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 <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
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;
}
}

View file

@ -65,7 +65,7 @@ public abstract class KeycloakWebSecurityConfigurerAdapter extends WebSecurityCo
protected AdapterDeploymentContext adapterDeploymentContext() throws Exception { protected AdapterDeploymentContext adapterDeploymentContext() throws Exception {
AdapterDeploymentContextFactoryBean factoryBean; AdapterDeploymentContextFactoryBean factoryBean;
if (keycloakConfigResolver != null) { if (keycloakConfigResolver != null) {
factoryBean = new AdapterDeploymentContextFactoryBean(keycloakConfigResolver); factoryBean = new AdapterDeploymentContextFactoryBean(new KeycloakSpringConfigResolverWrapper(keycloakConfigResolver));
} }
else { else {
factoryBean = new AdapterDeploymentContextFactoryBean(keycloakConfigFileResource); factoryBean = new AdapterDeploymentContextFactoryBean(keycloakConfigFileResource);