SGF-648 - Enhance @EnableSecurity to provide a default implementation of the GemFire AuthInitialize interface.
(cherry picked from commit 3859f70e45f32b23ba5d332d49d5ae724d7e0bbf) Signed-off-by: John Blum <jblum@pivotal.io>
This commit is contained in:
@@ -99,6 +99,7 @@ public class ApacheShiroSecurityConfiguration extends AbstractAnnotationConfigSu
|
||||
* @see org.springframework.beans.factory.BeanFactory
|
||||
*/
|
||||
@Override
|
||||
@SuppressWarnings("all")
|
||||
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
|
||||
|
||||
super.setBeanFactory(Optional.ofNullable(beanFactory)
|
||||
@@ -197,10 +198,12 @@ public class ApacheShiroSecurityConfiguration extends AbstractAnnotationConfigSu
|
||||
protected List<Realm> resolveRealms() {
|
||||
|
||||
try {
|
||||
Map<String, Realm> realmBeans = getListableBeanFactory()
|
||||
.getBeansOfType(Realm.class, false, true);
|
||||
Map<String, Realm> realmBeans = getListableBeanFactory().getBeansOfType(Realm.class, false, true);
|
||||
|
||||
List<Realm> realms = new ArrayList<>(CollectionUtils.nullSafeMap(realmBeans).values());
|
||||
Collections.sort(realms, OrderComparator.INSTANCE);
|
||||
|
||||
realms.sort(OrderComparator.INSTANCE);
|
||||
|
||||
return realms;
|
||||
}
|
||||
catch (Exception ignore) {
|
||||
@@ -278,6 +281,7 @@ public class ApacheShiroSecurityConfiguration extends AbstractAnnotationConfigSu
|
||||
* @inheritDoc
|
||||
*/
|
||||
@Override
|
||||
@SuppressWarnings("all")
|
||||
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
|
||||
return ClassUtils.isPresent(APACHE_SHIRO_LIFECYCLE_BEAN_POST_PROCESSOR_CLASS_NAME,
|
||||
context.getClassLoader());
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
* Copyright 2017 the original author or authors.
|
||||
*
|
||||
* 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.springframework.data.gemfire.config.annotation;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Properties;
|
||||
|
||||
import org.springframework.context.annotation.Condition;
|
||||
import org.springframework.context.annotation.ConditionContext;
|
||||
import org.springframework.context.annotation.Conditional;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.core.type.AnnotatedTypeMetadata;
|
||||
import org.springframework.data.gemfire.config.annotation.support.AutoConfiguredAuthenticationInitializer;
|
||||
import org.springframework.data.gemfire.config.annotation.support.EmbeddedServiceConfigurationSupport;
|
||||
import org.springframework.data.gemfire.util.PropertiesBuilder;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* The {@link AutoConfiguredAuthenticationConfiguration} class is a Spring {@link Configuration @Configuration} class
|
||||
* that auto-configures Pivotal GemFire / Apache Geode Authentication by providing a implementation
|
||||
* of the {@link org.apache.geode.security.AuthInitialize} interface along with setting the necessary GemFire / Geode
|
||||
* properties.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see java.util.Properties
|
||||
* @see org.apache.geode.security.AuthInitialize
|
||||
* @see org.springframework.context.annotation.Condition
|
||||
* @see org.springframework.context.annotation.Conditional
|
||||
* @see org.springframework.context.annotation.Configuration
|
||||
* @see org.springframework.core.env.Environment
|
||||
* @see org.springframework.data.gemfire.config.annotation.EnableBeanFactoryLocator
|
||||
* @see org.springframework.data.gemfire.config.annotation.support.AutoConfiguredAuthenticationInitializer
|
||||
* @see org.springframework.data.gemfire.config.annotation.support.EmbeddedServiceConfigurationSupport
|
||||
* @see org.springframework.data.gemfire.util.PropertiesBuilder
|
||||
* @since 2.0.0
|
||||
*/
|
||||
@Configuration
|
||||
@EnableBeanFactoryLocator
|
||||
@Conditional(AutoConfiguredAuthenticationConfiguration.AutoConfiguredAuthenticationCondition.class)
|
||||
public class AutoConfiguredAuthenticationConfiguration extends EmbeddedServiceConfigurationSupport {
|
||||
|
||||
protected static final String AUTO_CONFIGURED_AUTH_INIT_STATIC_FACTORY_METHOD =
|
||||
AutoConfiguredAuthenticationInitializer.class.getName().concat(".newAuthenticationInitializer");
|
||||
|
||||
protected static final String SECURITY_CLIENT_AUTH_INIT = "security-client-auth-init";
|
||||
protected static final String SECURITY_PEER_AUTH_INIT = "security-peer-auth-init";
|
||||
|
||||
/* (non-Javadoc) */
|
||||
@Override
|
||||
protected Class getAnnotationType() {
|
||||
return EnableSecurity.class;
|
||||
}
|
||||
|
||||
/* (non-Javadoc) */
|
||||
@Override
|
||||
protected Properties toGemFireProperties(Map<String, Object> annotationAttributes) {
|
||||
|
||||
return Optional.of(PropertiesBuilder.create())
|
||||
.filter(builder -> isMatch(environment()))
|
||||
.map(builder -> builder
|
||||
.setProperty(SECURITY_CLIENT_AUTH_INIT, AUTO_CONFIGURED_AUTH_INIT_STATIC_FACTORY_METHOD)
|
||||
.setProperty(SECURITY_PEER_AUTH_INIT, AUTO_CONFIGURED_AUTH_INIT_STATIC_FACTORY_METHOD))
|
||||
.map(PropertiesBuilder::build)
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
/* (non-Javadoc) */
|
||||
private static boolean isMatch(Environment environment) {
|
||||
return StringUtils.hasText(environment.getProperty(
|
||||
AutoConfiguredAuthenticationInitializer.SDG_SECURITY_USERNAME_PROPERTY));
|
||||
}
|
||||
|
||||
public static class AutoConfiguredAuthenticationCondition implements Condition {
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("all")
|
||||
public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
|
||||
return isMatch(conditionContext.getEnvironment());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -47,7 +47,8 @@ import org.springframework.context.annotation.Import;
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Inherited
|
||||
@Documented
|
||||
@Import({ ApacheShiroSecurityConfiguration.class, GeodeIntegratedSecurityConfiguration.class })
|
||||
@Import({ ApacheShiroSecurityConfiguration.class, AutoConfiguredAuthenticationConfiguration.class,
|
||||
GeodeIntegratedSecurityConfiguration.class })
|
||||
@UsesGemFireProperties
|
||||
@SuppressWarnings({ "unused" })
|
||||
public @interface EnableSecurity {
|
||||
@@ -117,6 +118,24 @@ public @interface EnableSecurity {
|
||||
*/
|
||||
String securityPostProcessorClassName() default "";
|
||||
|
||||
/**
|
||||
* The {@literal security-username} used by a GemFire cache client application required to authenticate.
|
||||
*
|
||||
* Defaults to unset.
|
||||
*
|
||||
* Use the {@literal spring.data.gemfire.security.username} in {@literal application.properties}.
|
||||
*/
|
||||
String securityUsername() default "";
|
||||
|
||||
/**
|
||||
* The {@literal security-password} used by a GemFire cache client application required to authenticate.
|
||||
*
|
||||
* Defaults to unset.
|
||||
*
|
||||
* Use the {@literal spring.data.gemfire.security.password} in {@literal application.properties}.
|
||||
*/
|
||||
String securityPassword() default "";
|
||||
|
||||
/**
|
||||
* Sets the Geode System Property referring to the location of an Apache Shiro INI file used to configure
|
||||
* the Apache Shiro Security Framework to secure Apache Geode.
|
||||
|
||||
@@ -61,7 +61,6 @@ public class GeodeIntegratedSecurityConfiguration extends EmbeddedServiceConfigu
|
||||
*/
|
||||
protected boolean isShiroSecurityConfigured() {
|
||||
try {
|
||||
// NOTE experimental...
|
||||
//return resolveBean(ApacheShiroSecurityConfiguration.class).isRealmsPresent();
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* Copyright 2017 the original author or authors.
|
||||
*
|
||||
* 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.springframework.data.gemfire.config.annotation.support;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.Properties;
|
||||
|
||||
import org.apache.geode.LogWriter;
|
||||
import org.apache.geode.distributed.DistributedMember;
|
||||
import org.apache.geode.security.AuthInitialize;
|
||||
import org.apache.geode.security.AuthenticationFailedException;
|
||||
import org.springframework.context.EnvironmentAware;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.data.gemfire.support.WiringDeclarableSupport;
|
||||
|
||||
/**
|
||||
* The {@link AbstractAuthInitialize} class is an abstract support class and basic implementation
|
||||
* of the {@link AuthInitialize} interface used in the authentication of a client or peer
|
||||
* with a secure GemFire/Geode cluster.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see java.util.Properties
|
||||
* @see org.apache.geode.security.AuthInitialize
|
||||
* @see org.springframework.context.EnvironmentAware
|
||||
* @see org.springframework.core.env.Environment
|
||||
* @see org.springframework.data.gemfire.support.WiringDeclarableSupport
|
||||
* @since 2.0.0
|
||||
*/
|
||||
public abstract class AbstractAuthInitialize extends WiringDeclarableSupport
|
||||
implements AuthInitialize, EnvironmentAware {
|
||||
|
||||
private Environment environment;
|
||||
|
||||
/**
|
||||
* Sets a reference to the configured Spring {@link Environment}.
|
||||
*
|
||||
* @param environment reference to the configured Spring {@link Environment}.
|
||||
* @see org.springframework.core.env.Environment
|
||||
*/
|
||||
@Override
|
||||
@SuppressWarnings("all")
|
||||
public void setEnvironment(Environment environment) {
|
||||
this.environment = environment;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a reference to the configured Spring {@link Environment}.
|
||||
*
|
||||
* @return a reference to the configured Spring {@link Environment}.
|
||||
* @see org.springframework.core.env.Environment
|
||||
*/
|
||||
protected Optional<Environment> getEnvironment() {
|
||||
return Optional.ofNullable(this.environment);
|
||||
}
|
||||
|
||||
/* (non-Javadoc */
|
||||
@Override
|
||||
@SuppressWarnings("deprecation")
|
||||
public final void init(LogWriter logWriter, LogWriter logWriter1) throws AuthenticationFailedException {
|
||||
doInit();
|
||||
}
|
||||
|
||||
protected void doInit() {
|
||||
}
|
||||
|
||||
/* (non-Javadoc */
|
||||
@Override
|
||||
public final Properties getCredentials(Properties properties, DistributedMember distributedMember, boolean isPeer)
|
||||
throws AuthenticationFailedException {
|
||||
|
||||
return doGetCredentials(properties);
|
||||
}
|
||||
|
||||
protected abstract Properties doGetCredentials(Properties properties);
|
||||
|
||||
/* (non-Javadoc */
|
||||
@Override
|
||||
public void close() {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright 2017 the original author or authors.
|
||||
*
|
||||
* 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.springframework.data.gemfire.config.annotation.support;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
import org.apache.shiro.util.StringUtils;
|
||||
|
||||
/**
|
||||
* The AutoConfiguredAuthenticationInitializer class...
|
||||
*
|
||||
* @author John Blum
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class AutoConfiguredAuthenticationInitializer extends AbstractAuthInitialize {
|
||||
|
||||
public static final String SDG_SECURITY_USERNAME_PROPERTY = "spring.data.gemfire.security.username";
|
||||
public static final String SDG_SECURITY_PASSWORD_PROPERTY = "spring.data.gemfire.security.password";
|
||||
|
||||
public static final String SECURITY_USERNAME_PROPERTY = "security-username";
|
||||
public static final String SECURITY_PASSWORD_PROPERTY = "security-password";
|
||||
|
||||
/**
|
||||
* Factory method used to construct a new instance of {@link AutoConfiguredAuthenticationInitializer}.
|
||||
*
|
||||
* @return a new instance of {@link AutoConfiguredAuthenticationInitializer}.
|
||||
* @see org.springframework.data.gemfire.config.annotation.support.AutoConfiguredAuthenticationInitializer
|
||||
*/
|
||||
public static AutoConfiguredAuthenticationInitializer newAuthenticationInitializer() {
|
||||
return new AutoConfiguredAuthenticationInitializer();
|
||||
}
|
||||
|
||||
/* (non-Javadoc) */
|
||||
@Override
|
||||
protected Properties doGetCredentials(Properties properties) {
|
||||
|
||||
getEnvironment()
|
||||
.filter(environment -> StringUtils.hasText(environment.getProperty(SDG_SECURITY_USERNAME_PROPERTY)))
|
||||
.ifPresent(environment -> {
|
||||
|
||||
String securityUsername = environment.getProperty(SDG_SECURITY_USERNAME_PROPERTY);
|
||||
String securityPassword = environment.getProperty(SDG_SECURITY_PASSWORD_PROPERTY);
|
||||
|
||||
properties.setProperty(SECURITY_USERNAME_PROPERTY, securityUsername);
|
||||
properties.setProperty(SECURITY_PASSWORD_PROPERTY, securityPassword);
|
||||
|
||||
});
|
||||
|
||||
return properties;
|
||||
}
|
||||
}
|
||||
@@ -77,8 +77,11 @@ public class GemfireBeanFactoryLocator implements BeanFactoryAware, BeanNameAwar
|
||||
* @see #afterPropertiesSet()
|
||||
*/
|
||||
public static GemfireBeanFactoryLocator newBeanFactoryLocator() {
|
||||
|
||||
GemfireBeanFactoryLocator beanFactoryLocator = new GemfireBeanFactoryLocator();
|
||||
|
||||
beanFactoryLocator.afterPropertiesSet();
|
||||
|
||||
return beanFactoryLocator;
|
||||
}
|
||||
|
||||
@@ -99,6 +102,7 @@ public class GemfireBeanFactoryLocator implements BeanFactoryAware, BeanNameAwar
|
||||
* @see #afterPropertiesSet()
|
||||
*/
|
||||
public static GemfireBeanFactoryLocator newBeanFactoryLocator(BeanFactory beanFactory, String associatedBeanName) {
|
||||
|
||||
Assert.isTrue(beanFactory == null || StringUtils.hasText(associatedBeanName),
|
||||
"associatedBeanName must be specified when BeanFactory is not null");
|
||||
|
||||
@@ -121,6 +125,7 @@ public class GemfireBeanFactoryLocator implements BeanFactoryAware, BeanNameAwar
|
||||
* @see org.springframework.beans.factory.BeanFactory
|
||||
*/
|
||||
protected static BeanFactory resolveBeanFactory(String beanFactoryKey) {
|
||||
|
||||
BeanFactory beanFactory = BEAN_FACTORIES.get(beanFactoryKey);
|
||||
|
||||
Assert.isTrue(BEAN_FACTORIES.isEmpty() || beanFactory != null,
|
||||
@@ -142,12 +147,15 @@ public class GemfireBeanFactoryLocator implements BeanFactoryAware, BeanNameAwar
|
||||
* @see org.springframework.beans.factory.BeanFactory
|
||||
*/
|
||||
protected static synchronized BeanFactory resolveSingleBeanFactory() {
|
||||
|
||||
if (!BEAN_FACTORIES.isEmpty()) {
|
||||
|
||||
boolean allTheSameBeanFactory = true;
|
||||
|
||||
BeanFactory currentBeanFactory = null;
|
||||
|
||||
for (BeanFactory beanFactory : BEAN_FACTORIES.values()) {
|
||||
|
||||
allTheSameBeanFactory &= nullOrEquals(currentBeanFactory, beanFactory);
|
||||
currentBeanFactory = beanFactory;
|
||||
|
||||
@@ -178,10 +186,12 @@ public class GemfireBeanFactoryLocator implements BeanFactoryAware, BeanNameAwar
|
||||
* @see org.springframework.beans.factory.BeanFactory
|
||||
*/
|
||||
protected static synchronized void registerAliases(Set<String> names, BeanFactory beanFactory) {
|
||||
|
||||
Assert.isTrue(nullSafeSet(names).isEmpty() || beanFactory != null,
|
||||
"BeanFactory must not be null when aliases are specified");
|
||||
|
||||
for (String name : nullSafeSet(names)) {
|
||||
|
||||
BeanFactory existingBeanFactory = BEAN_FACTORIES.putIfAbsent(name, beanFactory);
|
||||
|
||||
Assert.isTrue(nullOrEquals(existingBeanFactory, beanFactory),
|
||||
@@ -204,6 +214,7 @@ public class GemfireBeanFactoryLocator implements BeanFactoryAware, BeanNameAwar
|
||||
*/
|
||||
@Override
|
||||
public void afterPropertiesSet() {
|
||||
|
||||
BeanFactory beanFactory = getBeanFactory();
|
||||
|
||||
registerAliases(resolveAndInitializeBeanNamesWithAliases(beanFactory), beanFactory);
|
||||
@@ -221,9 +232,11 @@ public class GemfireBeanFactoryLocator implements BeanFactoryAware, BeanNameAwar
|
||||
* @see #getAssociatedBeanName()
|
||||
*/
|
||||
Set<String> resolveAndInitializeBeanNamesWithAliases(BeanFactory beanFactory) {
|
||||
|
||||
String associatedBeanName = getAssociatedBeanName();
|
||||
|
||||
if (beanFactory != null && StringUtils.hasText(associatedBeanName)) {
|
||||
|
||||
String[] beanAliases = beanFactory.getAliases(associatedBeanName);
|
||||
|
||||
this.associatedBeanNameWithAliases = new TreeSet<>();
|
||||
@@ -272,8 +285,8 @@ public class GemfireBeanFactoryLocator implements BeanFactoryAware, BeanNameAwar
|
||||
* @see #resolveSingleBeanFactory()
|
||||
*/
|
||||
public BeanFactory useBeanFactory(String beanFactoryKey) {
|
||||
return newBeanFactoryReference(StringUtils.hasText(beanFactoryKey) ? resolveBeanFactory(beanFactoryKey)
|
||||
: resolveSingleBeanFactory()).get();
|
||||
return newBeanFactoryReference(StringUtils.hasText(beanFactoryKey)
|
||||
? resolveBeanFactory(beanFactoryKey) : resolveSingleBeanFactory()).get();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -380,6 +393,7 @@ public class GemfireBeanFactoryLocator implements BeanFactoryAware, BeanNameAwar
|
||||
* @see org.springframework.beans.factory.BeanFactory
|
||||
*/
|
||||
public BeanFactory get() {
|
||||
|
||||
BeanFactory beanFactory = this.beanFactory.get();
|
||||
|
||||
Assert.state(beanFactory != null, UNINITIALIZED_BEAN_FACTORY_REFERENCE_MESSAGE);
|
||||
|
||||
@@ -85,6 +85,7 @@ public abstract class WiringDeclarableSupport extends DeclarableSupport {
|
||||
* @see #newBeanConfigurer(BeanFactory, String)
|
||||
*/
|
||||
protected boolean configureThis(BeanFactory beanFactory, String templateBeanName) {
|
||||
|
||||
BeanConfigurerSupport beanConfigurer = newBeanConfigurer(beanFactory, templateBeanName);
|
||||
|
||||
beanConfigurer.configureBean(this);
|
||||
@@ -122,11 +123,13 @@ public abstract class WiringDeclarableSupport extends DeclarableSupport {
|
||||
* @see org.springframework.beans.factory.BeanFactory
|
||||
*/
|
||||
protected BeanConfigurerSupport newBeanConfigurer(BeanFactory beanFactory, String templateBeanName) {
|
||||
|
||||
BeanConfigurerSupport beanConfigurer = new BeanConfigurerSupport();
|
||||
|
||||
beanConfigurer.setBeanFactory(beanFactory);
|
||||
|
||||
if (StringUtils.hasText(templateBeanName)) {
|
||||
|
||||
Assert.isTrue(beanFactory.containsBean(templateBeanName),
|
||||
String.format("Cannot find bean with name [%s]", templateBeanName));
|
||||
|
||||
|
||||
Reference in New Issue
Block a user