diff --git a/build.gradle b/build.gradle index 60a8d1e1..29d044b9 100644 --- a/build.gradle +++ b/build.gradle @@ -32,8 +32,8 @@ description = 'Spring Data Geode' group = 'org.springframework.data' archivesBaseName = project.name -sourceCompatibility = 1.6 -targetCompatibility = 1.6 +sourceCompatibility = 1.8 +targetCompatibility = 1.8 sourceSets { main { @@ -115,6 +115,7 @@ dependencies { // Java & 3rd Party Dependencies optional "javax.enterprise:cdi-api:$cdiVersion" compile "org.aspectj:aspectjweaver:$aspectjVersion" + optional "org.apache.shiro:shiro-spring:$shiroVersion" compile "com.fasterxml.jackson.core:jackson-annotations:$jacksonVersion" compile "com.fasterxml.jackson.core:jackson-databind:$jacksonVersion" diff --git a/gradle.properties b/gradle.properties index 44e211da..05bad395 100644 --- a/gradle.properties +++ b/gradle.properties @@ -13,6 +13,7 @@ mockitoVersion=1.10.19 multiThreadedtcVersion=1.01 openwebbeansVersion=1.2.8 servletApiVersion=2.5 +shiroVersion=1.3.2 slf4jVersion=1.7.21 spring.range="[4.0.0, 5.0.0)" springVersion=4.3.3.RELEASE diff --git a/pom.xml b/pom.xml index ccf4012e..6dafafe9 100644 --- a/pom.xml +++ b/pom.xml @@ -20,6 +20,7 @@ SGF 2.7.7 + 1.3.2 2.5.0 1.1.0-incubating-SNAPSHOT 2.0.2 @@ -28,6 +29,7 @@ 4.3.3.RELEASE 1.12.4.RELEASE 1.1.0.RELEASE + 1.8 @@ -124,6 +126,12 @@ ${aspectj} + + org.apache.shiro + shiro-spring + ${apache-shiro.version} + + com.fasterxml.jackson.core jackson-annotations diff --git a/src/main/java/org/springframework/data/gemfire/config/annotation/AbstractCacheConfiguration.java b/src/main/java/org/springframework/data/gemfire/config/annotation/AbstractCacheConfiguration.java index 135bfb68..3ae6c7c0 100644 --- a/src/main/java/org/springframework/data/gemfire/config/annotation/AbstractCacheConfiguration.java +++ b/src/main/java/org/springframework/data/gemfire/config/annotation/AbstractCacheConfiguration.java @@ -88,8 +88,7 @@ public abstract class AbstractCacheConfiguration implements BeanClassLoaderAware private static final AtomicBoolean CUSTOM_EDITORS_REGISTERED = new AtomicBoolean(false); private static final AtomicBoolean DEFINED_INDEXES_APPLICATION_LISTENER_REGISTERED = new AtomicBoolean(false); private static final AtomicBoolean DISK_STORE_DIRECTORY_BEAN_POST_PROCESSOR_REGISTERED = new AtomicBoolean(false); - private static final AtomicBoolean PDX_DISK_STORE_AWARE_BEAN_FACTORY_POST_PROCESSOR_REGISTERED = - new AtomicBoolean(false); + private static final AtomicBoolean PDX_DISK_STORE_AWARE_BEAN_FACTORY_POST_PROCESSOR_REGISTERED = new AtomicBoolean(false); protected static final boolean DEFAULT_CLOSE = true; protected static final boolean DEFAULT_COPY_ON_READ = false; @@ -270,7 +269,6 @@ public abstract class AbstractCacheConfiguration implements BeanClassLoaderAware registerCustomEditorBeanFactoryPostProcessor(importMetadata); registerDefinedIndexesApplicationListener(importMetadata); registerDiskStoreDirectoryBeanPostProcessor(importMetadata); - registerPdxDiskStoreAwareBeanFactoryPostProcessor(importMetadata); } /** @@ -323,6 +321,8 @@ public abstract class AbstractCacheConfiguration implements BeanClassLoaderAware setPdxPersistent(Boolean.TRUE.equals(enablePdxAttributes.get("persistent"))); setPdxReadSerialized(Boolean.TRUE.equals(enablePdxAttributes.get("readSerialized"))); setPdxSerializer(resolvePdxSerializer((String) enablePdxAttributes.get("serializerBeanName"))); + + registerPdxDiskStoreAwareBeanFactoryPostProcessor(importMetadata); } } @@ -383,9 +383,13 @@ public abstract class AbstractCacheConfiguration implements BeanClassLoaderAware /* (non-Javadoc) */ protected void registerPdxDiskStoreAwareBeanFactoryPostProcessor(AnnotationMetadata importMetadata) { - if (PDX_DISK_STORE_AWARE_BEAN_FACTORY_POST_PROCESSOR_REGISTERED.compareAndSet(false, true)) { - register(BeanDefinitionBuilder.rootBeanDefinition(PdxDiskStoreAwareBeanFactoryPostProcessor.class) - .setRole(BeanDefinition.ROLE_INFRASTRUCTURE).getBeanDefinition()); + if (StringUtils.hasText(pdxDiskStoreName())) { + if (PDX_DISK_STORE_AWARE_BEAN_FACTORY_POST_PROCESSOR_REGISTERED.compareAndSet(false, true)) { + register(BeanDefinitionBuilder.rootBeanDefinition(PdxDiskStoreAwareBeanFactoryPostProcessor.class) + .setRole(BeanDefinition.ROLE_INFRASTRUCTURE) + .addConstructorArgValue(pdxDiskStoreName()) + .getBeanDefinition()); + } } } diff --git a/src/main/java/org/springframework/data/gemfire/config/annotation/ApacheShiroSecurityConfiguration.java b/src/main/java/org/springframework/data/gemfire/config/annotation/ApacheShiroSecurityConfiguration.java new file mode 100644 index 00000000..2b0a600c --- /dev/null +++ b/src/main/java/org/springframework/data/gemfire/config/annotation/ApacheShiroSecurityConfiguration.java @@ -0,0 +1,255 @@ +/* + * Copyright 2016 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.lang.reflect.Field; +import java.util.Collections; +import java.util.List; + +import javax.annotation.PostConstruct; + +import org.apache.geode.cache.GemFireCache; +import org.apache.geode.internal.security.SecurityService; +import org.apache.shiro.SecurityUtils; +import org.apache.shiro.mgt.DefaultSecurityManager; +import org.apache.shiro.realm.Realm; +import org.apache.shiro.spring.LifecycleBeanPostProcessor; +import org.springframework.beans.factory.ListableBeanFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.config.BeanPostProcessor; +import org.springframework.context.annotation.Bean; +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.context.annotation.ConfigurationCondition; +import org.springframework.core.type.AnnotatedTypeMetadata; +import org.springframework.data.gemfire.util.CollectionUtils; +import org.springframework.util.Assert; +import org.springframework.util.ClassUtils; +import org.springframework.util.ReflectionUtils; + +/** + * The {@link ApacheShiroSecurityConfiguration} class is a Spring {@link Configuration @Configuration} component + * responsible for configuring and initializing the Apache Shiro security framework in order to secure Apache Geode + * administrative and data access operations. + * + * @author John Blum + * @see org.apache.geode.cache.GemFireCache + * @see org.apache.geode.internal.security.SecurityService + * @see org.apache.shiro.mgt.SecurityManager + * @see org.apache.shiro.spring.LifecycleBeanPostProcessor + * @see org.springframework.context.annotation.Condition + * @see org.springframework.context.annotation.Conditional + * @since 1.0.0 + */ +@Configuration +@Conditional(ApacheShiroSecurityConfiguration.ApacheShiroPresentCondition.class) +@SuppressWarnings("unused") +public class ApacheShiroSecurityConfiguration { + + @Autowired(required = false) + private List realms = Collections.emptyList(); + + @Autowired(required = false) + private org.apache.shiro.mgt.SecurityManager shiroSecurityManager; + + /** + * {@link Bean} definition to configure and register an Apache Shiro, Spring {@link LifecycleBeanPostProcessor} + * used to automatically call lifecycle callback methods on Shiro security components during Spring container + * initialization and destruction phases. + * + * The registration of this {@link Bean} definition is dependent upon whether the user is using Apache Shiro + * to secure Apache Geode, which is determined by the presence of Apache Shiro {@link Realm Realms} + * declared in the Spring {@link org.springframework.context.ApplicationContext}. + * + * @return an Apache Shiro, Spring {@link LifecycleBeanPostProcessor} bean. + * @see org.apache.shiro.spring.LifecycleBeanPostProcessor + */ + @Bean + //@Conditional(ShiroRealmsConfigured.class) + public BeanPostProcessor shiroLifecycleBeanPostProcessor() { + return new LifecycleBeanPostProcessor(); + } + + /** + * {@link Bean} definition used to configure and register an Apache Shiro + * {@link org.apache.shiro.mgt.SecurityManager} implementation to secure Apache Geode. + * + * The registration of this {@link Bean} definition is dependent upon whether the user is using Apache Shiro + * to secure Apache Geode, which is determined by the presence of Apache Shiro {@link Realm Realms} + * declared in the Spring {@link org.springframework.context.ApplicationContext}. + * + * This {@link Bean} definition declares a dependency on the Apache Geode {@link GemFireCache} instance + * in order to ensure the Geode cache is created and initialized first, thus evaluating any security configuration + * logic internally in Apache Geode that may potentially overwrite the Spring configuration. + * + * @return an Apache Shiro {@link org.apache.shiro.mgt.SecurityManager} implementation used to secure Apache Geode. + * @see org.apache.shiro.mgt.SecurityManager + * @see #isRealmsPresent() + * @see #getRealms() + */ + @Bean + //@Conditional(ShiroRealmsConfigured.class) + public org.apache.shiro.mgt.SecurityManager shiroSecurityManager(GemFireCache gemfireCache) { + return (isRealmsPresent() ? new DefaultSecurityManager(getRealms()) : null); + } + + /** + * Post processes the Apache Shiro security components by registering the Apach Shiro + * {@link org.apache.shiro.mgt.SecurityManager} if present with the Apache Shiro security framework + * and proceeds to enable Apache Geode security. + * + * @throws IllegalStateException if an Apache Shiro {@link org.apache.shiro.mgt.SecurityManager} is present + * and Apache Geode security could not be enabled. + * @see #registerSecurityManager(org.apache.shiro.mgt.SecurityManager) + * @see #enableApacheGeodeSecurity() + */ + @PostConstruct + public void postProcess() { + if (this.shiroSecurityManager != null) { + registerSecurityManager(this.shiroSecurityManager); + + if (!enableApacheGeodeSecurity()) { + throw new IllegalStateException("Failed to enable security services in Apache Geode"); + } + } + } + + /** + * Registers the given Apache Shiro {@link org.apache.shiro.mgt.SecurityManager} with the Apache Shiro + * security framework. + * + * @param securityManager {@link org.apache.shiro.mgt.SecurityManager} to register. + * @return the given {@link org.apache.shiro.mgt.SecurityManager} reference. + * @throws IllegalArgumentException if {@link org.apache.shiro.mgt.SecurityManager} is {@literal null}. + * @see org.apache.shiro.SecurityUtils#setSecurityManager(org.apache.shiro.mgt.SecurityManager) + * @see org.apache.shiro.mgt.SecurityManager + */ + protected org.apache.shiro.mgt.SecurityManager registerSecurityManager( + org.apache.shiro.mgt.SecurityManager securityManager) { + + Assert.notNull(securityManager, "The Apache Shiro SecurityManager to register must not be null"); + + SecurityUtils.setSecurityManager(securityManager); + + return securityManager; + } + + /** + * Sets the Apache Geode, Integrated Security {@link SecurityService} property {@literal isIntegratedSecurity} + * to {@literal true} to indicate that Apache Geode security is enabled. + * + * @return a boolean value indicating whether Apache Geode's Integrated Security framework services + * were successfully enabled. + * @see org.apache.geode.internal.security.SecurityService#getSecurityService() + */ + protected boolean enableApacheGeodeSecurity() { + SecurityService securityService = SecurityService.getSecurityService(); + + if (securityService != null) { + Field isIntegratedSecurity = ReflectionUtils.findField(securityService.getClass(), + "isIntegratedSecurity", Boolean.TYPE); + + if (isIntegratedSecurity != null) { + ReflectionUtils.makeAccessible(isIntegratedSecurity); + ReflectionUtils.setField(isIntegratedSecurity, securityService, true); + + return true; + } + } + + return false; + } + + /** + * Returns the {@link List} of Apache Shiro {@link Realm Realms} configured in + * this Spring {@link org.springframework.context.ApplicationContext}. + * + * @return a {@link List} of configured/declared Apache Shiro {@link Realm Realms}. + * @see org.apache.shiro.realm.Realm + */ + protected List getRealms() { + return this.realms; + } + + /** + * Determines whether any Apache Shiro {@link Realm Realms} were configured in + * this Spring {@link org.springframework.context.ApplicationContext}. + * + * @return a boolean value indicating whether any Apache Shiro {@link Realm Realms} were declared and configured + * in this Spring {@link org.springframework.context.ApplicationContext}. + * @see #getRealms() + */ + protected boolean isRealmsPresent() { + return !CollectionUtils.isEmpty(getRealms()); + } + + /** + * A Spring {@link Condition} to determine whether the user has included (declared) the 'shiro-spring' dependency + * on their application's classpath, which is necessary for configuring Apache Shiro to secure Apache Geode + * in a Spring context. + * + * @see org.springframework.context.annotation.Condition + */ + public static class ApacheShiroPresentCondition implements Condition { + + protected static final String APACHE_SHIRO_LIFECYCLE_BEAN_POST_PROCESOR_CLASS_NAME = + "org.apache.shiro.spring.LifecycleBeanPostProcessor"; + + /** + * @inheritDoc + */ + @Override + public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { + return ClassUtils.isPresent(APACHE_SHIRO_LIFECYCLE_BEAN_POST_PROCESOR_CLASS_NAME, + context.getClassLoader()); + } + } + + /** + * A Spring {@link Condition} implementation that determines whether the user declared and configured + * any Apache Shiro {@link Realm Realms}, which are necessary to configure the Apache Shiro security framework + * with security meta-data used to secure Apache Geode. + * + * @see org.springframework.context.annotation.ConfigurationCondition + */ + public static class ShiroRealmsConfigured implements ConfigurationCondition { + + /** + * @inheritDoc + */ + @Override + public ConfigurationPhase getConfigurationPhase() { + return ConfigurationPhase.REGISTER_BEAN; + } + + /** + * @inheritDoc + */ + @Override + public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { + ListableBeanFactory beanFactory = context.getBeanFactory(); + + ApacheShiroSecurityConfiguration securityConfiguration = + beanFactory.getBean(ApacheShiroSecurityConfiguration.class); + + return (securityConfiguration.isRealmsPresent() || !beanFactory.getBeansOfType(Realm.class).isEmpty()); + } + } +} diff --git a/src/main/java/org/springframework/data/gemfire/config/annotation/AuthConfiguration.java b/src/main/java/org/springframework/data/gemfire/config/annotation/AuthConfiguration.java index 1c27e15f..09e2626f 100644 --- a/src/main/java/org/springframework/data/gemfire/config/annotation/AuthConfiguration.java +++ b/src/main/java/org/springframework/data/gemfire/config/annotation/AuthConfiguration.java @@ -40,6 +40,18 @@ public class AuthConfiguration extends EmbeddedServiceConfigurationSupport { public static final String DEFAULT_SECURITY_LOG_LEVEL = "config"; + protected static final String GEMFIRE_SECURITY_PROPERTY_FILE = "gemfireSecurityPropertyFile"; + protected static final String SECURITY_CLIENT_ACCESSOR = "security-client-accessor"; + protected static final String SECURITY_CLIENT_ACCESSOR_POST_PROCESSOR = "security-client-accessor-pp"; + protected static final String SECURITY_CLIENT_AUTH_INIT = "security-client-auth-init"; + protected static final String SECURITY_CLIENT_AUTHENTICATOR = "security-client-authenticator"; + protected static final String SECURITY_CLIENT_DIFFIE_HELLMAN_ALGORITHM = "security-client-dhalgo"; + protected static final String SECURITY_LOG_FILE = "security-log-file"; + protected static final String SECURITY_LOG_LEVEL = "security-log-level"; + protected static final String SECURITY_PEER_AUTH_INIT = "security-peer-auth-init"; + protected static final String SECURITY_PEER_AUTHENTICATOR = "security-peer-authenticator"; + protected static final String SECURITY_PEER_VERIFY_MEMBER_TIMEOUT = "security-peer-verifymember-timeout"; + /* (non-Javadoc) */ @Override protected Class getAnnotationType() { @@ -51,32 +63,32 @@ public class AuthConfiguration extends EmbeddedServiceConfigurationSupport { protected Properties toGemFireProperties(Map annotationAttributes) { PropertiesBuilder gemfireProperties = PropertiesBuilder.create(); - gemfireProperties.setProperty("gemfireSecurityPropertyFile", annotationAttributes.get("securityPropertiesFile")); + gemfireProperties.setProperty(GEMFIRE_SECURITY_PROPERTY_FILE, annotationAttributes.get("securityPropertiesFile")); - gemfireProperties.setProperty("security-client-accessor", annotationAttributes.get("clientAccessor")); + gemfireProperties.setProperty(SECURITY_CLIENT_ACCESSOR, annotationAttributes.get("clientAccessor")); - gemfireProperties.setProperty("security-client-accessor-pp", + gemfireProperties.setProperty(SECURITY_CLIENT_ACCESSOR_POST_PROCESSOR, annotationAttributes.get("clientAccessPostOperation")); - gemfireProperties.setProperty("security-client-auth-init", + gemfireProperties.setProperty(SECURITY_CLIENT_AUTH_INIT, annotationAttributes.get("clientAuthenticationInitializer")); - gemfireProperties.setProperty("security-client-authenticator", annotationAttributes.get("clientAuthenticator")); + gemfireProperties.setProperty(SECURITY_CLIENT_AUTHENTICATOR, annotationAttributes.get("clientAuthenticator")); - gemfireProperties.setProperty("security-client-dhalgo", + gemfireProperties.setProperty(SECURITY_CLIENT_DIFFIE_HELLMAN_ALGORITHM, annotationAttributes.get("clientDiffieHellmanAlgorithm")); - gemfireProperties.setProperty("security-peer-auth-init", + gemfireProperties.setProperty(SECURITY_PEER_AUTH_INIT, annotationAttributes.get("peerAuthenticationInitializer")); - gemfireProperties.setProperty("security-peer-authenticator", annotationAttributes.get("peerAuthenticator")); + gemfireProperties.setProperty(SECURITY_PEER_AUTHENTICATOR, annotationAttributes.get("peerAuthenticator")); - gemfireProperties.setPropertyIfNotDefault("security-peer-verifymember-timeout", + gemfireProperties.setPropertyIfNotDefault(SECURITY_PEER_VERIFY_MEMBER_TIMEOUT, annotationAttributes.get("peerVerifyMemberTimeout"), DEFAULT_PEER_VERIFY_MEMBER_TIMEOUT); - gemfireProperties.setProperty("security-log-file", annotationAttributes.get("securityLogFile")); + gemfireProperties.setProperty(SECURITY_LOG_FILE, annotationAttributes.get("securityLogFile")); - gemfireProperties.setPropertyIfNotDefault("security-log-level", + gemfireProperties.setPropertyIfNotDefault(SECURITY_LOG_LEVEL, annotationAttributes.get("securityLogLevel"), DEFAULT_SECURITY_LOG_LEVEL); return gemfireProperties.build(); diff --git a/src/main/java/org/springframework/data/gemfire/config/annotation/EnableSecurity.java b/src/main/java/org/springframework/data/gemfire/config/annotation/EnableSecurity.java new file mode 100644 index 00000000..37da4957 --- /dev/null +++ b/src/main/java/org/springframework/data/gemfire/config/annotation/EnableSecurity.java @@ -0,0 +1,111 @@ +/* + * Copyright 2016 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.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.apache.geode.security.AuthInitialize; +import org.springframework.context.annotation.Import; + +/** + * The {@link EnableSecurity} annotation marks a Spring {@link org.springframework.context.annotation.Configuration} + * annotated class to configure and enable Apache Geode's Security features for authentication, authorization + * and post processing. + * + * @author John Blum + * @see GeodeIntegratedSecurityConfiguration + * @see org.apache.geode.security.AuthInitialize + * @see org.apache.geode.security.SecurityManager + * @since 1.0.0 + */ +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.RUNTIME) +@Inherited +@Documented +@Import({ ApacheShiroSecurityConfiguration.class, GeodeIntegratedSecurityConfiguration.class }) +@SuppressWarnings("unused") +public @interface EnableSecurity { + + /** + * Used for authentication. Static creation method returning an {@link AuthInitialize} object, + * which obtains credentials for clients. + * + * Defaults to unset. + */ + String clientAuthenticationInitializer() default ""; + + /** + * Used with authentication. Static creation method returning an {@link AuthInitialize} object, which obtains + * credentials for peers in a distributed system. + * + * Defaults to unset. + */ + String peerAuthenticationInitializer() default ""; + + /** + * Specifies the application {@link Class} type implementing the Apache Geode + * {@link org.apache.geode.security.SecurityManager} interface to enable security in Apache Geode. + * + * Defaults to {@link Void}. + */ + Class securityManagerClass() default Void.class; + + /** + * Specifies the fully-qualified class name of the application {@link Class} implementing the Apache Geode + * {@link org.apache.geode.security.SecurityManager} interface to enable security in Apache Geode. + * + * Use this Annotation attribute if you are uncertain whether the application class is on the classpath or not. + * + * Default is unset. + */ + String securityManagerClassName() default ""; + + /** + * Specifies the application {@link Class} type implementing the Apache Geode + * {@link org.apache.geode.security.PostProcessor} interface, which used to transform sensitive data + * returned from secure data access operations. + * + * Defaults to {@link Void}. + */ + Class securityPostProcessorClass() default Void.class; + + /** + * Specifies the fully-qualified class name of the application {@link Class} implementing the Apache Geode + * {@link org.apache.geode.security.PostProcessor} interface, which used to transform sensitive data + * returned from secure data access operations. + * + * Use this Annotation attribute if you are uncertain whether the application class is on the classpath or not. + * + * Default is unset. + */ + String securityPostProcessorClassName() 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. + * + * Default is unset. + */ + String shiroIniResourcePath() default ""; + +} diff --git a/src/main/java/org/springframework/data/gemfire/config/annotation/GeodeIntegratedSecurityConfiguration.java b/src/main/java/org/springframework/data/gemfire/config/annotation/GeodeIntegratedSecurityConfiguration.java new file mode 100644 index 00000000..2d062023 --- /dev/null +++ b/src/main/java/org/springframework/data/gemfire/config/annotation/GeodeIntegratedSecurityConfiguration.java @@ -0,0 +1,91 @@ +/* + * Copyright 2016 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.Properties; + +import org.springframework.data.gemfire.config.annotation.support.EmbeddedServiceConfigurationSupport; +import org.springframework.data.gemfire.util.PropertiesBuilder; + +/** + * The {@link GeodeIntegratedSecurityConfiguration} class is a {@link EmbeddedServiceConfigurationSupport} implementation + * that enables Apache Geode's Integrated Security framework and services. + * + * @author John Blum + * @see org.springframework.data.gemfire.config.annotation.support.EmbeddedServiceConfigurationSupport + * @since 1.0.0 + */ +@SuppressWarnings("unused") +public class GeodeIntegratedSecurityConfiguration extends EmbeddedServiceConfigurationSupport { + + protected static final String SECURITY_CLIENT_AUTH_INIT = "security-client-auth-init"; + protected static final String SECURITY_PEER_AUTH_INIT = "security-peer-auth-init"; + protected static final String SECURITY_MANAGER = "security-manager"; + protected static final String SECURITY_POST_PROCESSOR = "security-post-processor"; + protected static final String SECURITY_SHIRO_INIT = "security-shiro-init"; + + /** + * @inheritDoc + */ + @Override + protected Class getAnnotationType() { + return EnableSecurity.class; + } + + /* (non-Javadoc) */ + protected boolean isShiroSecurityConfigured() { + return false; + } + + /* (non-Javadoc) */ + protected boolean isShiroSecurityNotConfigured() { + return !isShiroSecurityConfigured(); + } + + /** + * @inheritDoc + */ + @Override + protected Properties toGemFireProperties(Map annotationAttributes) { + PropertiesBuilder gemfireProperties = new PropertiesBuilder(); + + gemfireProperties.setProperty(SECURITY_CLIENT_AUTH_INIT, + annotationAttributes.get("clientAuthenticationInitializer")); + + gemfireProperties.setProperty(SECURITY_PEER_AUTH_INIT, + annotationAttributes.get("peerAuthenticationInitializer")); + + if (isShiroSecurityNotConfigured()) { + gemfireProperties.setPropertyIfNotDefault(SECURITY_MANAGER, + annotationAttributes.get("securityManagerClass"), Void.class); + + gemfireProperties.setProperty(SECURITY_MANAGER, annotationAttributes.get("securityManagerClassName")); + + gemfireProperties.setProperty(SECURITY_SHIRO_INIT, annotationAttributes.get("shiroIniResourcePath")); + } + + gemfireProperties.setPropertyIfNotDefault(SECURITY_POST_PROCESSOR, + annotationAttributes.get("securityPostProcessorClass"), Void.class); + + gemfireProperties.setProperty(SECURITY_POST_PROCESSOR, + annotationAttributes.get("securityPostProcessorClassName")); + + return gemfireProperties.build(); + } +} diff --git a/src/main/java/org/springframework/data/gemfire/config/support/PdxDiskStoreAwareBeanFactoryPostProcessor.java b/src/main/java/org/springframework/data/gemfire/config/support/PdxDiskStoreAwareBeanFactoryPostProcessor.java index 85ed5a30..98c1d4d0 100644 --- a/src/main/java/org/springframework/data/gemfire/config/support/PdxDiskStoreAwareBeanFactoryPostProcessor.java +++ b/src/main/java/org/springframework/data/gemfire/config/support/PdxDiskStoreAwareBeanFactoryPostProcessor.java @@ -89,7 +89,8 @@ public class PdxDiskStoreAwareBeanFactoryPostProcessor implements BeanFactoryPos * @see org.springframework.beans.factory.config.ConfigurableListableBeanFactory#getBeanNamesForType(Class) */ private void postProcessPdxDiskStoreDependencies(ConfigurableListableBeanFactory beanFactory, - final Class... beanTypes) { + Class... beanTypes) { + for (Class beanType : beanTypes) { for (String beanName : beanFactory.getBeanNamesForType(beanType)) { if (!beanName.equalsIgnoreCase(getPdxDiskStoreName())) { diff --git a/src/main/java/org/springframework/data/gemfire/util/ArrayUtils.java b/src/main/java/org/springframework/data/gemfire/util/ArrayUtils.java index cb49c757..5df4c519 100644 --- a/src/main/java/org/springframework/data/gemfire/util/ArrayUtils.java +++ b/src/main/java/org/springframework/data/gemfire/util/ArrayUtils.java @@ -32,6 +32,7 @@ public abstract class ArrayUtils { * @param elements variable list of arguments to return as an array. * @return an arry for the given varargs {@code elements}. */ + @SafeVarargs public static T[] asArray(T... elements) { return elements; } @@ -45,7 +46,7 @@ public abstract class ArrayUtils { * @return the first element in the array or {@literal null} if the array is null or empty. * @see #getFirst(Object[], Object) */ - public static T getFirst(T... array) { + public static T getFirst(T[] array) { return getFirst(array, null); } diff --git a/src/test/java/org/springframework/data/gemfire/GemfireTemplateIntegrationTests.java b/src/test/java/org/springframework/data/gemfire/GemfireTemplateIntegrationTests.java index 9a35d8ad..9ee185b2 100644 --- a/src/test/java/org/springframework/data/gemfire/GemfireTemplateIntegrationTests.java +++ b/src/test/java/org/springframework/data/gemfire/GemfireTemplateIntegrationTests.java @@ -205,7 +205,7 @@ public class GemfireTemplateIntegrationTests { public void get() { String key = getKey(getUser("imaPigg")); - assertThat(usersTemplate.get(key)).isEqualTo(users.get(key)); + assertThat(usersTemplate.get(key)).isEqualTo(users.get(key)); assertNullEquals(users.get("mrT"), usersTemplate.get("mrT")); } @@ -233,11 +233,11 @@ public class GemfireTemplateIntegrationTests { User mandyHandy = users.get(getKey(getUser("mandyHandy"))); assertThat(mandyHandy).isNotNull(); - assertThat(usersTemplate.remove(getKey(mandyHandy))).isEqualTo(mandyHandy); + assertThat(usersTemplate.remove(getKey(mandyHandy))).isEqualTo(mandyHandy); assertThat(users.containsKey(getKey(mandyHandy))).isFalse(); assertThat(users.containsValue(mandyHandy)).isFalse(); assertThat(users.containsKey("loisGriffon")).isFalse(); - assertThat(usersTemplate.remove("loisGriffon")).isNull(); + assertThat(usersTemplate.remove("loisGriffon")).isNull(); assertThat(users.containsKey("loisGriffon")).isFalse(); } diff --git a/src/test/java/org/springframework/data/gemfire/GemfireTemplateUnitTests.java b/src/test/java/org/springframework/data/gemfire/GemfireTemplateUnitTests.java index f65ec2a1..cf7805bf 100644 --- a/src/test/java/org/springframework/data/gemfire/GemfireTemplateUnitTests.java +++ b/src/test/java/org/springframework/data/gemfire/GemfireTemplateUnitTests.java @@ -211,7 +211,7 @@ public class GemfireTemplateUnitTests extends AbstractUnitAndIntegrationTestsWit when(mockQuery.execute(eq(expectedParams))).thenReturn(mockSelectResults); when(mockSelectResults.asList()).thenReturn(Collections.singletonList(1)); - assertThat(template.findUnique(expectedQuery, expectedParams)).isEqualTo(1); + assertThat((Object) template.findUnique(expectedQuery, expectedParams)).isEqualTo(1); verify(mockRegion, atLeastOnce()).getRegionService(); verify(mockRegionService, times(1)).getQueryService(); @@ -227,7 +227,7 @@ public class GemfireTemplateUnitTests extends AbstractUnitAndIntegrationTestsWit when(mockQuery.execute(eq(expectedParams))).thenReturn("test"); - assertThat(template.findUnique(expectedQuery, expectedParams)).isEqualTo("test"); + assertThat((Object) template.findUnique(expectedQuery, expectedParams)).isEqualTo("test"); verify(mockRegion, atLeastOnce()).getRegionService(); verify(mockRegionService, times(1)).getQueryService(); @@ -246,7 +246,7 @@ public class GemfireTemplateUnitTests extends AbstractUnitAndIntegrationTestsWit when(mockSelectResults.asList()).thenReturn(Arrays.asList(1, 2)); try { - assertThat(template.findUnique(expectedQuery, expectedParams)).isEqualTo(1); + assertThat((Object) template.findUnique(expectedQuery, expectedParams)).isEqualTo(1); } finally { verify(mockRegion, atLeastOnce()).getRegionService(); diff --git a/src/test/java/org/springframework/data/gemfire/config/annotation/AbstractCacheConfigurationUnitTests.java b/src/test/java/org/springframework/data/gemfire/config/annotation/AbstractCacheConfigurationUnitTests.java index 215d7999..49cc715a 100644 --- a/src/test/java/org/springframework/data/gemfire/config/annotation/AbstractCacheConfigurationUnitTests.java +++ b/src/test/java/org/springframework/data/gemfire/config/annotation/AbstractCacheConfigurationUnitTests.java @@ -201,8 +201,8 @@ public class AbstractCacheConfigurationUnitTests { MappingPdxSerializer pdxSerializer = cacheConfiguration.newPdxSerializer(); assertThat(pdxSerializer).isNotNull(); - assertThat(invokeMethod(pdxSerializer, "getConversionService")).isEqualTo(mockConversionService); - assertThat(invokeMethod(pdxSerializer, "getMappingContext")).isEqualTo(mockMappingContext); + assertThat((Object) invokeMethod(pdxSerializer, "getConversionService")).isEqualTo(mockConversionService); + assertThat((Object) invokeMethod(pdxSerializer, "getMappingContext")).isEqualTo(mockMappingContext); verify(mockBeanFactory, times(1)).getConversionService(); verifyZeroInteractions(mockConversionService); @@ -216,8 +216,8 @@ public class AbstractCacheConfigurationUnitTests { MappingPdxSerializer pdxSerializer = cacheConfiguration.newPdxSerializer(); assertThat(pdxSerializer).isNotNull(); - assertThat(invokeMethod(pdxSerializer, "getConversionService")).isInstanceOf(ConversionService.class); - assertThat(invokeMethod(pdxSerializer, "getMappingContext")).isInstanceOf(GemfireMappingContext.class); + assertThat((Object) invokeMethod(pdxSerializer, "getConversionService")).isInstanceOf(ConversionService.class); + assertThat((Object) invokeMethod(pdxSerializer, "getMappingContext")).isInstanceOf(GemfireMappingContext.class); } protected static class TestCacheConfiguration extends AbstractCacheConfiguration { diff --git a/src/test/java/org/springframework/data/gemfire/config/xml/GemfireV7GatewayNamespaceTest.java b/src/test/java/org/springframework/data/gemfire/config/xml/GemfireV7GatewayNamespaceTest.java index 266521d5..07c858a9 100644 --- a/src/test/java/org/springframework/data/gemfire/config/xml/GemfireV7GatewayNamespaceTest.java +++ b/src/test/java/org/springframework/data/gemfire/config/xml/GemfireV7GatewayNamespaceTest.java @@ -15,6 +15,7 @@ */ package org.springframework.data.gemfire.config.xml; +import static org.assertj.core.api.Assertions.assertThat; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; @@ -114,11 +115,11 @@ public class GemfireV7GatewayNamespaceTest extends RecreatingSpringApplicationCo assertNotNull(gatewaySenderFactoryBean); assertNotNull(TestUtils.readField("cache", gatewaySenderFactoryBean)); - assertEquals(2, TestUtils.readField("remoteDistributedSystemId", gatewaySenderFactoryBean)); - assertEquals(10, TestUtils.readField("alertThreshold", gatewaySenderFactoryBean)); + assertThat((Object) TestUtils.readField("remoteDistributedSystemId", gatewaySenderFactoryBean)).isEqualTo(2); + assertThat((Object) TestUtils.readField("alertThreshold", gatewaySenderFactoryBean)).isEqualTo(10); assertTrue(Boolean.TRUE.equals(TestUtils.readField("batchConflationEnabled", gatewaySenderFactoryBean))); - assertEquals(11, TestUtils.readField("batchSize", gatewaySenderFactoryBean)); - assertEquals(12, TestUtils.readField("dispatcherThreads", gatewaySenderFactoryBean)); + assertThat((Object) TestUtils.readField("batchSize", gatewaySenderFactoryBean)).isEqualTo(11); + assertThat((Object) TestUtils.readField("dispatcherThreads", gatewaySenderFactoryBean)).isEqualTo(12); assertEquals(false, TestUtils.readField("diskSynchronous", gatewaySenderFactoryBean)); assertEquals(true, TestUtils.readField("manualStart", gatewaySenderFactoryBean)); @@ -190,10 +191,10 @@ public class GemfireV7GatewayNamespaceTest extends RecreatingSpringApplicationCo assertNotNull(gatewaySenderFactoryBean); assertNotNull(TestUtils.readField("cache", gatewaySenderFactoryBean)); - assertEquals(3, TestUtils.readField("remoteDistributedSystemId", gatewaySenderFactoryBean)); + assertThat((Integer) TestUtils.readField("remoteDistributedSystemId", gatewaySenderFactoryBean)).isEqualTo(3); assertTrue(Boolean.TRUE.equals(TestUtils.readField("batchConflationEnabled", gatewaySenderFactoryBean))); - assertEquals(50, TestUtils.readField("batchSize", gatewaySenderFactoryBean)); - assertEquals(10, TestUtils.readField("dispatcherThreads", gatewaySenderFactoryBean)); + assertThat((Object) TestUtils.readField("batchSize", gatewaySenderFactoryBean)).isEqualTo(50); + assertThat((Object) TestUtils.readField("dispatcherThreads", gatewaySenderFactoryBean)).isEqualTo(10); assertEquals(true, TestUtils.readField("manualStart", gatewaySenderFactoryBean)); List eventFilters = TestUtils.readField("eventFilters", gatewaySenderFactoryBean); diff --git a/src/test/java/org/springframework/data/gemfire/function/execution/AbstractFunctionExecutionTest.java b/src/test/java/org/springframework/data/gemfire/function/execution/AbstractFunctionExecutionTest.java index 2b1cd337..2377cfff 100644 --- a/src/test/java/org/springframework/data/gemfire/function/execution/AbstractFunctionExecutionTest.java +++ b/src/test/java/org/springframework/data/gemfire/function/execution/AbstractFunctionExecutionTest.java @@ -16,13 +16,9 @@ package org.springframework.data.gemfire.function.execution; -import static org.hamcrest.CoreMatchers.containsString; -import static org.hamcrest.CoreMatchers.equalTo; -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.CoreMatchers.isA; -import static org.hamcrest.CoreMatchers.notNullValue; -import static org.hamcrest.CoreMatchers.nullValue; -import static org.junit.Assert.assertThat; +import static org.assertj.core.api.Assertions.assertThat; +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.isA; import static org.mockito.Matchers.any; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.mock; @@ -95,8 +91,8 @@ public class AbstractFunctionExecutionTest { Iterable actualResults = functionExecution.setFunction(mockFunction) .setArgs(args).setTimeout(500).execute(); - assertThat(actualResults, is(notNullValue())); - assertThat(actualResults, is(equalTo((Iterable) results))); + assertThat(actualResults).isNotNull(); + assertThat(actualResults).isEqualTo((Iterable) results); verify(mockExecution, times(1)).withArgs(eq(args)); verify(mockExecution, never()).withCollector(any(ResultCollector.class)); @@ -122,7 +118,7 @@ public class AbstractFunctionExecutionTest { } }; - assertThat(String.valueOf(functionExecution.executeAndExtract()), is(equalTo("test"))); + assertThat(functionExecution.executeAndExtract()).isEqualTo("test"); } @Test @@ -140,7 +136,7 @@ public class AbstractFunctionExecutionTest { } }; - assertThat(String.valueOf(functionExecution.executeAndExtract()), is(equalTo("one"))); + assertThat(functionExecution.executeAndExtract()).isEqualTo("one"); } @Test @@ -156,7 +152,7 @@ public class AbstractFunctionExecutionTest { } }; - assertThat(functionExecution.executeAndExtract(), is(nullValue())); + assertThat((Object) functionExecution.executeAndExtract()).isNull(); } @Test @@ -172,7 +168,7 @@ public class AbstractFunctionExecutionTest { } }; - assertThat(functionExecution.executeAndExtract(), is(nullValue())); + assertThat((Object) functionExecution.executeAndExtract()).isNull(); } @Test @@ -194,5 +190,4 @@ public class AbstractFunctionExecutionTest { functionExecution.setFunctionId("TestFunction").executeAndExtract(); } - } diff --git a/src/test/java/org/springframework/data/gemfire/repository/support/SimpleGemfireRepositoryIntegrationTests.java b/src/test/java/org/springframework/data/gemfire/repository/support/SimpleGemfireRepositoryIntegrationTests.java index 69a4548d..71ac8596 100644 --- a/src/test/java/org/springframework/data/gemfire/repository/support/SimpleGemfireRepositoryIntegrationTests.java +++ b/src/test/java/org/springframework/data/gemfire/repository/support/SimpleGemfireRepositoryIntegrationTests.java @@ -143,9 +143,9 @@ public class SimpleGemfireRepositoryIntegrationTests { repository.save(Arrays.asList(johnBlum, jonBloom, juanBlume)); assertThat(template.getRegion().size()).isEqualTo(3); - assertThat(template.get(johnBlum.getId())).isEqualTo(johnBlum); - assertThat(template.get(jonBloom.getId())).isEqualTo(jonBloom); - assertThat(template.get(juanBlume.getId())).isEqualTo(juanBlume); + assertThat(template.get(johnBlum.getId())).isEqualTo(johnBlum); + assertThat(template.get(jonBloom.getId())).isEqualTo(jonBloom); + assertThat(template.get(juanBlume.getId())).isEqualTo(juanBlume); } @SuppressWarnings("rawtypes") diff --git a/src/test/java/org/springframework/data/gemfire/util/ArrayUtilsUnitTests.java b/src/test/java/org/springframework/data/gemfire/util/ArrayUtilsUnitTests.java index 0f7b7266..7f57bdb4 100644 --- a/src/test/java/org/springframework/data/gemfire/util/ArrayUtilsUnitTests.java +++ b/src/test/java/org/springframework/data/gemfire/util/ArrayUtilsUnitTests.java @@ -60,13 +60,13 @@ public class ArrayUtilsUnitTests { @Test public void getFirstWithNonNullArray() { - assertThat(ArrayUtils.getFirst(1, 2, 3)).isEqualTo(1); + assertThat(ArrayUtils.getFirst(ArrayUtils.asArray(1, 2, 3))).isEqualTo(1); } @Test public void getFirstWithNullOrEmptyArrayAndNoDefaultReturnsNull() { - assertThat(ArrayUtils.getFirst((Object[]) null)).isNull(); - assertThat(ArrayUtils.getFirst()).isNull(); + assertThat((Object) ArrayUtils.getFirst(null)).isNull(); + assertThat((Object) ArrayUtils.getFirst(new Object[0])).isNull(); } @Test diff --git a/template.mf b/template.mf index 25151251..12eedcb0 100644 --- a/template.mf +++ b/template.mf @@ -3,8 +3,10 @@ Bundle-Name: Spring Data Geode Bundle-SymbolicName: org.springframework.data.gemfire Bundle-Vendor: Pivotal Software, Inc. Import-Package: sun.reflect;version="0";resolution:=optional -Import-Template: javax.enterprise.*;version="[1.0,2.0)";resolution:=optional, +Import-Template: javax.annotation.*;version="[1.0,2.0)";resolution:=optional, + javax.enterprise.*;version="[1.0,2.0)";resolution:=optional, org.apache.commons.logging.*;version="[1.1.1, 2.0.0)", + org.apache.shiro.*;version="[1.3.0, 2.0.0)";resolutioin:=optional, org.aopalliance.*;version="[1.0.0, 2.0.0)";resolution:=optional, org.aspectj.*;version="[1.8.2, 2.0.0)";resolution:=optional, com.fasterxml.jackson.*;version="[2.4.1,3.0.0)";resolution:=optional,