diff --git a/spring-data-geode/src/main/java/org/springframework/data/gemfire/config/annotation/ApacheShiroSecurityConfiguration.java b/spring-data-geode/src/main/java/org/springframework/data/gemfire/config/annotation/ApacheShiroSecurityConfiguration.java index e84db0aa5..32e272551 100644 --- a/spring-data-geode/src/main/java/org/springframework/data/gemfire/config/annotation/ApacheShiroSecurityConfiguration.java +++ b/spring-data-geode/src/main/java/org/springframework/data/gemfire/config/annotation/ApacheShiroSecurityConfiguration.java @@ -122,9 +122,17 @@ protected ListableBeanFactory getListableBeanFactory() { @Bean public BeanFactoryPostProcessor shiroGemFireBeanFactoryPostProcessor() { - return configurableListableBeanFactory -> - SpringUtils.addDependsOn(configurableListableBeanFactory.getBeanDefinition("gemfireCache"), - "shiroSecurityManager"); + return configurableListableBeanFactory -> { + + if (configurableListableBeanFactory.containsBean("gemfireCache")) { + SpringUtils.addDependsOn(configurableListableBeanFactory.getBeanDefinition("gemfireCache"), + "shiroSecurityManager"); + } + else if (configurableListableBeanFactory.containsBean("locatorApplication")) { + SpringUtils.addDependsOn(configurableListableBeanFactory.getBeanDefinition("locatorApplication"), + "shiroSecurityManager"); + } + }; } /** @@ -251,9 +259,6 @@ private boolean isEnabled(Environment environment) { return environment.getProperty(SPRING_DATA_GEMFIRE_SECURITY_SHIRO_ENABLED, Boolean.class, true); } - /** - * @inheritDoc - */ @Override public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { return isEnabled(context.getEnvironment()) && isApacheShiroPresent(context); diff --git a/spring-data-geode/src/main/java/org/springframework/data/gemfire/config/annotation/AuthenticationBeanConfiguration.java b/spring-data-geode/src/main/java/org/springframework/data/gemfire/config/annotation/AuthenticationBeanConfiguration.java new file mode 100644 index 000000000..3de0bd4d6 --- /dev/null +++ b/spring-data-geode/src/main/java/org/springframework/data/gemfire/config/annotation/AuthenticationBeanConfiguration.java @@ -0,0 +1,175 @@ +/* + * Copyright 2022 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 + * + * https://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.Annotation; +import java.util.function.Supplier; + +import org.apache.shiro.util.Assert; + +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.support.BeanDefinitionBuilder; +import org.springframework.beans.factory.support.BeanDefinitionRegistry; +import org.springframework.beans.factory.support.BeanNameGenerator; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.ImportAware; +import org.springframework.core.annotation.AnnotationAttributes; +import org.springframework.core.type.AnnotationMetadata; +import org.springframework.data.gemfire.config.annotation.support.AbstractAnnotationConfigSupport; +import org.springframework.data.gemfire.config.annotation.support.Authentication; +import org.springframework.lang.NonNull; +import org.springframework.lang.Nullable; +import org.springframework.util.StringUtils; + +/** + * Spring {@link Configuration} class used to configure and register an {@link Authentication} object + * based on security (auth) configuration metadata supplied in the {@link EnableSecurity} annotation. + * + * @author John Blum + * @see java.lang.annotation.Annotation + * @see org.springframework.beans.factory.config.BeanDefinition + * @see org.springframework.beans.factory.support.BeanDefinitionBuilder + * @see org.springframework.beans.factory.support.BeanDefinitionRegistry + * @see org.springframework.beans.factory.support.BeanNameGenerator + * @see org.springframework.context.annotation.Configuration + * @see org.springframework.context.annotation.ImportAware + * @see org.springframework.data.gemfire.config.annotation.support.AbstractAnnotationConfigSupport + * @see org.springframework.data.gemfire.config.annotation.support.Authentication + * @since 1.0.0 + */ +@Configuration +public class AuthenticationBeanConfiguration extends AbstractAnnotationConfigSupport implements ImportAware { + + private static final char[] EMPTY_CHAR_ARRAY = {}; + + private String username; + private String password; + + @Override + protected Class getAnnotationType() { + return EnableSecurity.class; + } + + protected void setUsername(@Nullable String username) { + this.username = username; + } + + private @Nullable String getUsername() { + return this.username; + } + + protected void setPassword(@Nullable String password) { + this.password = password; + } + + private @Nullable String getPassword() { + return this.password; + } + + @Override + public void setImportMetadata(@NonNull AnnotationMetadata importMetadata) { + + if (isAnnotationPresent(importMetadata)) { + + AnnotationAttributes enableSecurityAttributes = getAnnotationAttributes(importMetadata); + + setUsername(resolveProperty(securityProperty("username"), String.class, + enableSecurityAttributes.getString("securityUsername"))); + + setPassword(resolveProperty(securityProperty("password"), String.class, + enableSecurityAttributes.getString("securityPassword"))); + } + } + + @Bean + @SuppressWarnings("unused") + public @NonNull Authentication springDataGeodeAuthentication() { + return SpringDataGeodeAuthentication.from(this::getUsername, this::getPassword); + } + + private void registerAuthenticationBean(@NonNull BeanDefinitionRegistry registry, + @NonNull BeanNameGenerator beanNameGenerator) { + + if (isAuthenticationCredentialsSet(getUsername(), nullSafeToCharArray(getPassword()))) { + + BeanDefinition authenticationBean = + BeanDefinitionBuilder.rootBeanDefinition(SpringDataGeodeAuthentication.class) + .addConstructorArgValue(getUsername()) + .addConstructorArgValue(getPassword()) + .setRole(BeanDefinition.ROLE_INFRASTRUCTURE) + .getBeanDefinition(); + + String beanName = beanNameGenerator.generateBeanName(authenticationBean, registry); + + registry.registerBeanDefinition(beanName, authenticationBean); + } + } + + protected boolean isAuthenticationCredentialsSet(String username, char[] password) { + return StringUtils.hasText(username) && nullSafeCharArray(password).length > 0; + } + + private @NonNull char[] nullSafeCharArray(@Nullable char[] array) { + return array != null ? array : EMPTY_CHAR_ARRAY; + } + + private @NonNull char[] nullSafeToCharArray(@Nullable String value) { + return value != null ? value.trim().toCharArray() : EMPTY_CHAR_ARRAY; + } + + protected static class SpringDataGeodeAuthentication implements Authentication { + + public static @NonNull SpringDataGeodeAuthentication from(@NonNull Supplier username, + @NonNull Supplier password) { + + return new SpringDataGeodeAuthentication(username, password); + } + + private final Supplier username; + private final Supplier password; + + protected SpringDataGeodeAuthentication(@NonNull Supplier username, @NonNull Supplier password) { + this.username = require(username, "Username [%s] is required", username); + this.password = require(password, "Password [%s] is required", password); + } + + private T require(T target, String message, Object... arguments) { + Assert.notNull(target, String.format(message, arguments)); + return target; + } + + @Override + public boolean isRequested() { + return StringUtils.hasText(getPrincipal()) && StringUtils.hasText(getCredentials()); + } + + @Override + public @NonNull String getPrincipal() { + return this.username.get(); + } + + @Override + public @NonNull String getCredentials() { + return this.password.get(); + } + + @Override + public String toString() { + return getPrincipal(); + } + } +} diff --git a/spring-data-geode/src/main/java/org/springframework/data/gemfire/config/annotation/AutoConfiguredAuthenticationConfiguration.java b/spring-data-geode/src/main/java/org/springframework/data/gemfire/config/annotation/AutoConfiguredAuthenticationConfiguration.java index 68696eab1..79f98e124 100644 --- a/spring-data-geode/src/main/java/org/springframework/data/gemfire/config/annotation/AutoConfiguredAuthenticationConfiguration.java +++ b/spring-data-geode/src/main/java/org/springframework/data/gemfire/config/annotation/AutoConfiguredAuthenticationConfiguration.java @@ -22,113 +22,152 @@ import java.util.Optional; import java.util.Properties; +import org.apache.geode.security.AuthInitialize; + +import org.apache.shiro.util.Assert; + +import org.springframework.beans.factory.annotation.Autowired; 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.Import; -import org.springframework.core.Ordered; -import org.springframework.core.annotation.Order; +import org.springframework.context.annotation.ConfigurationCondition; +import org.springframework.context.annotation.Lazy; import org.springframework.core.env.Environment; import org.springframework.core.type.AnnotatedTypeMetadata; +import org.springframework.data.gemfire.GemFireProperties; +import org.springframework.data.gemfire.config.annotation.support.Authentication; import org.springframework.data.gemfire.config.annotation.support.AutoConfiguredAuthenticationInitializer; import org.springframework.data.gemfire.config.support.RestTemplateConfigurer; import org.springframework.data.gemfire.util.CollectionUtils; import org.springframework.http.HttpHeaders; import org.springframework.http.client.ClientHttpRequestInterceptor; import org.springframework.http.client.ClientHttpResponse; +import org.springframework.lang.NonNull; +import org.springframework.lang.Nullable; import org.springframework.util.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** - * 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. + * The {@link AutoConfiguredAuthenticationConfiguration} class is a Spring {@link Configuration} class + * that auto-configures Apache Geode Authentication by providing an implementation of the {@link AuthInitialize} + * interface along with setting the necessary Apache Geode {@link Properties}. * * @author John Blum + * @see java.net.Authenticator + * @see java.net.PasswordAuthentication * @see java.util.Properties * @see org.apache.geode.security.AuthInitialize + * @see org.springframework.beans.factory.config.ConfigurableListableBeanFactory * @see org.springframework.context.annotation.Bean * @see org.springframework.context.annotation.Condition - * @see org.springframework.context.annotation.Conditional * @see org.springframework.context.annotation.Configuration - * @see org.springframework.context.annotation.Import + * @see org.springframework.context.annotation.ConfigurationCondition * @see org.springframework.core.env.Environment + * @see org.springframework.data.gemfire.GemFireProperties * @see org.springframework.data.gemfire.config.annotation.EnableBeanFactoryLocator + * @see org.springframework.data.gemfire.config.annotation.support.Authentication * @see org.springframework.data.gemfire.config.annotation.support.AutoConfiguredAuthenticationInitializer + * @see org.springframework.data.gemfire.config.support.RestTemplateConfigurer * @see org.springframework.data.gemfire.util.PropertiesBuilder + * @see org.springframework.http.client.ClientHttpRequestInterceptor * @since 2.0.0 */ @Configuration -@Import(BeanFactoryLocatorConfiguration.class) -@Conditional(AutoConfiguredAuthenticationConfiguration.AutoConfiguredAuthenticationCondition.class) +@EnableBeanFactoryLocator +@Conditional(AutoConfiguredAuthenticationConfiguration.AuthenticationAutoConfigurationEnabledCondition.class) @SuppressWarnings("unused") public class AutoConfiguredAuthenticationConfiguration { + private static final char[] EMPTY_CHAR_ARRAY = {}; + protected static final String AUTO_CONFIGURED_AUTH_INIT_STATIC_FACTORY_METHOD = AutoConfiguredAuthenticationInitializer.class.getName().concat(".newAuthenticationInitializer"); protected static final String DEFAULT_USERNAME = "test"; protected static final String DEFAULT_PASSWORD = DEFAULT_USERNAME; protected static final String HTTP_PROTOCOL = "HTTP"; - protected static final String SECURITY_CLIENT_AUTH_INIT = "security-client-auth-init"; - protected static final String SECURITY_PASSWORD = "security-password"; - protected static final String SECURITY_PEER_AUTH_INIT = "security-peer-auth-init"; - protected static final String SECURITY_USERNAME = "security-username"; + protected static final String PROPERTY_SOURCE_NAME = AutoConfiguredAuthenticationConfiguration.class.getName(); + protected static final String SECURITY_CLIENT_AUTH_INIT = GemFireProperties.SECURITY_CLIENT_AUTH_INIT.getName(); + protected static final String SECURITY_PEER_AUTH_INIT = GemFireProperties.SECURITY_PEER_AUTH_INIT.getName(); + protected static final String SECURITY_USERNAME = AutoConfiguredAuthenticationInitializer.SECURITY_USERNAME_PROPERTY; + protected static final String SECURITY_PASSWORD = AutoConfiguredAuthenticationInitializer.SECURITY_PASSWORD_PROPERTY; - private Logger logger = LoggerFactory.getLogger(getClass()); + private final Logger logger = LoggerFactory.getLogger(getClass()); + + protected @NonNull Logger getLogger() { + return this.logger; + } + + protected void logDebug(String message, Object... args) { + + Logger logger = getLogger(); + + if (logger.isDebugEnabled()) { + logger.debug(message, args); + } + } @Bean("GemFireSecurityAuthenticator") - public Authenticator authenticator(Environment environment) { + public @Nullable Authenticator authenticator( + @Autowired(required = false) @Lazy Authentication authentication) { + + return Optional.ofNullable(authentication) + .filter(Authentication::isRequested) + .map(this::newAuthenticator) + .map(this::registerAuthenticator) + .orElse(null); + } + + private @NonNull Authenticator newAuthenticator(@NonNull Authentication authentication) { + + Assert.notNull(authentication, "Authentication must not be null"); + Assert.state(authentication.isRequested(), "Authentication was not requested"); - Authenticator authenticator = new Authenticator() { + return new Authenticator() { @Override protected PasswordAuthentication getPasswordAuthentication() { - String username = - environment.getProperty(AutoConfiguredAuthenticationInitializer.SDG_SECURITY_USERNAME_PROPERTY, - DEFAULT_USERNAME); - - String password = - environment.getProperty(AutoConfiguredAuthenticationInitializer.SDG_SECURITY_PASSWORD_PROPERTY, - DEFAULT_PASSWORD); + String username = authentication.getPrincipal(); + String password = authentication.getCredentials(); return new PasswordAuthentication(username, password.toCharArray()); } }; + } - Authenticator.setDefault(authenticator); + private @NonNull Authenticator registerAuthenticator(@NonNull Authenticator authenticator) { + + if (authenticator != null) { + Authenticator.setDefault(authenticator); + } return authenticator; } - ClientHttpRequestInterceptor loggingAwareClientHttpRequestInterceptor() { + @NonNull ClientHttpRequestInterceptor loggingAwareClientHttpRequestInterceptor() { return (request, body, execution) -> { - logger.debug("HTTP Request URI [{}]", request.getURI()); + logDebug("HTTP Request URI [{}]", request.getURI()); HttpHeaders httpHeaders = request.getHeaders(); CollectionUtils.nullSafeSet(httpHeaders.keySet()).forEach(httpHeaderName -> - logger.debug("HTTP Request Header Name [{}] Value [{}]", + logDebug("HTTP Request Header Name [{}] Value [{}]", httpHeaderName, httpHeaders.get(httpHeaderName))); ClientHttpResponse response = execution.execute(request, body); - if (this.logger.isDebugEnabled()) { - try { - this.logger.debug("HTTP Response Status Code [{}] Message [{}]", - response.getRawStatusCode(), response.getStatusText()); - } - catch (IOException cause) { - this.logger.debug("Error occurred getting HTTP Response Status Code and Message", cause); - } + try { + logDebug("HTTP Response Status Code [{}] Message [{}]", + response.getStatusCode().value(), response.getStatusText()); + } + catch (IOException cause) { + logDebug("Error occurred getting HTTP Response Status Code and Message", cause); } return response; @@ -136,12 +175,11 @@ ClientHttpRequestInterceptor loggingAwareClientHttpRequestInterceptor() { } @Bean - @Order(Ordered.LOWEST_PRECEDENCE) public RestTemplateConfigurer loggingAwareRestTemplateConfigurer() { - return restTemplate -> restTemplate.getInterceptors().add(loggingAwareClientHttpRequestInterceptor()); + return restTemplate -> restTemplate.getInterceptors().add(loggingAwareClientHttpRequestInterceptor()); } - ClientHttpRequestInterceptor securityAwareClientHttpRequestInterceptor() { + @NonNull ClientHttpRequestInterceptor securityAwareClientHttpRequestInterceptor() { return (request, body, execution) -> { @@ -151,15 +189,18 @@ ClientHttpRequestInterceptor securityAwareClientHttpRequestInterceptor() { Authenticator.requestPasswordAuthentication(uri.getHost(), null, uri.getPort(), HTTP_PROTOCOL, null, uri.getScheme()); - String username = passwordAuthentication.getUserName(); - char[] password = passwordAuthentication.getPassword(); + if (passwordAuthentication != null) { - if (isAuthenticationEnabled(username, password)) { + String username = passwordAuthentication.getUserName(); + char[] password = passwordAuthentication.getPassword(); - HttpHeaders requestHeaders = request.getHeaders(); + if (isAuthenticationCredentialsSet(username, password)) { - requestHeaders.add(SECURITY_USERNAME, username); - requestHeaders.add(SECURITY_PASSWORD, String.valueOf(password)); + HttpHeaders requestHeaders = request.getHeaders(); + + requestHeaders.add(SECURITY_USERNAME, username); + requestHeaders.add(SECURITY_PASSWORD, String.valueOf(password)); + } } return execution.execute(request, body); @@ -167,58 +208,78 @@ ClientHttpRequestInterceptor securityAwareClientHttpRequestInterceptor() { } @Bean - @Order(Ordered.HIGHEST_PRECEDENCE) - public RestTemplateConfigurer securityAwareRestTemplateConfigurer(Authenticator authenticator) { + public RestTemplateConfigurer securityAwareRestTemplateConfigurer() { return restTemplate -> restTemplate.getInterceptors().add(securityAwareClientHttpRequestInterceptor()); } - private boolean isAuthenticationEnabled(String username, char[] password) { - return StringUtils.hasText(username) && password != null && password.length > 0; + private boolean isAuthenticationCredentialsSet(String username, char[] password) { + return StringUtils.hasText(username) && nullSafeCharArray(password).length > 0; + } + + private @NonNull char[] nullSafeCharArray(@Nullable char[] array) { + return array != null ? array : EMPTY_CHAR_ARRAY; } @Bean - public ClientCacheConfigurer authenticationCredentialsSettingClientCacheConfigurer(Environment environment) { - return (beanName, beanFactory) -> setAuthenticationCredentials(beanFactory.getProperties(), environment); + public ClientCacheConfigurer authenticationInitializingClientCacheConfigurer( + @Autowired(required = false) @Lazy Authentication authentication) { + + return (beanName, clientCacheFactoryBean) -> + initializeMemberAuthentication(clientCacheFactoryBean.getProperties(), authentication); } @Bean - public PeerCacheConfigurer authenticationCredentialsSettingPeerCacheConfigurer(Environment environment) { - return (beanName, beanFactory) -> setAuthenticationCredentials(beanFactory.getProperties(), environment); + public LocatorConfigurer authenticationInitializingLocatorConfigurer( + @Autowired(required = false) @Lazy Authentication authentication) { + + return (beanName, locatorFactoryBean) -> + initializeMemberAuthentication(locatorFactoryBean.getGemFireProperties(), authentication); } - private void setAuthenticationCredentials(Properties gemfireProperties, Environment environment) { + @Bean + public PeerCacheConfigurer authenticationInitializingPeerCacheConfigurer( + @Autowired(required = false) @Lazy Authentication authentication) { + + return (beanName, cacheFactoryBean) -> + initializeMemberAuthentication(cacheFactoryBean.getProperties(), authentication); + } + + private void initializeMemberAuthentication(Properties gemfireProperties, + @Nullable Authentication authentication) { Optional.ofNullable(gemfireProperties) - .filter(properties -> isMatch(environment)) + .filter(properties -> isAuthenticationRequested(authentication)) .ifPresent(properties -> { properties.setProperty(SECURITY_CLIENT_AUTH_INIT, AUTO_CONFIGURED_AUTH_INIT_STATIC_FACTORY_METHOD); properties.setProperty(SECURITY_PEER_AUTH_INIT, AUTO_CONFIGURED_AUTH_INIT_STATIC_FACTORY_METHOD); }); } - private static boolean isMatch(Environment environment) { - - return Optional.ofNullable(environment) - .map(env -> env.getProperty(AutoConfiguredAuthenticationInitializer.SDG_SECURITY_USERNAME_PROPERTY)) - .map(StringUtils::hasText) - .isPresent(); + private boolean isAuthenticationRequested(@Nullable Authentication authentication) { + return authentication != null && authentication.isRequested(); } - public static class AutoConfiguredAuthenticationCondition implements Condition { + public static class AuthenticationAutoConfigurationEnabledCondition implements ConfigurationCondition { + + public static final boolean DEFAULT_ENABLED = true; - public static final String SPRING_DATA_GEMFIRE_SECURITY_AUTH_ENABLED = - "spring.data.gemfire.security.auth.auto-configure.enabled"; + public static final String SECURITY_AUTH_AUTO_CONFIGURATION_ENABLED = + "spring.data.gemfire.security.auth.auto-configuration-enabled"; - private static boolean isEnabled(Environment environment) { - return environment.getProperty(SPRING_DATA_GEMFIRE_SECURITY_AUTH_ENABLED, Boolean.class, true); + private static boolean isEnabled(@NonNull Environment environment) { + return environment.getProperty(SECURITY_AUTH_AUTO_CONFIGURATION_ENABLED, Boolean.class, DEFAULT_ENABLED); } @Override - public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) { + public ConfigurationPhase getConfigurationPhase() { + return ConfigurationPhase.PARSE_CONFIGURATION; + } - Environment environment = conditionContext.getEnvironment(); + @Override + public boolean matches(@NonNull ConditionContext conditionContext, + @NonNull AnnotatedTypeMetadata annotatedTypeMetadata) { - return isEnabled(environment) && isMatch(environment); + return isEnabled(conditionContext.getEnvironment()); } } } diff --git a/spring-data-geode/src/main/java/org/springframework/data/gemfire/config/annotation/EnableSecurity.java b/spring-data-geode/src/main/java/org/springframework/data/gemfire/config/annotation/EnableSecurity.java index 5a1d18002..8534da354 100644 --- a/spring-data-geode/src/main/java/org/springframework/data/gemfire/config/annotation/EnableSecurity.java +++ b/spring-data-geode/src/main/java/org/springframework/data/gemfire/config/annotation/EnableSecurity.java @@ -40,6 +40,8 @@ * @see org.apache.geode.security.PostProcessor * @see org.springframework.context.annotation.Import * @see org.springframework.data.gemfire.config.annotation.ApacheShiroSecurityConfiguration + * @see org.springframework.data.gemfire.config.annotation.AuthenticationBeanConfiguration + * @see org.springframework.data.gemfire.config.annotation.AutoConfiguredAuthenticationConfiguration * @see org.springframework.data.gemfire.config.annotation.GeodeIntegratedSecurityConfiguration * @since 1.0.0 */ @@ -49,6 +51,7 @@ @Documented @Import({ ApacheShiroSecurityConfiguration.class, + AuthenticationBeanConfiguration.class, AutoConfiguredAuthenticationConfiguration.class, GeodeIntegratedSecurityConfiguration.class }) diff --git a/spring-data-geode/src/main/java/org/springframework/data/gemfire/config/annotation/GeodeIntegratedSecurityConfiguration.java b/spring-data-geode/src/main/java/org/springframework/data/gemfire/config/annotation/GeodeIntegratedSecurityConfiguration.java index 6551b0f0d..4eb8c8148 100644 --- a/spring-data-geode/src/main/java/org/springframework/data/gemfire/config/annotation/GeodeIntegratedSecurityConfiguration.java +++ b/spring-data-geode/src/main/java/org/springframework/data/gemfire/config/annotation/GeodeIntegratedSecurityConfiguration.java @@ -20,6 +20,7 @@ import java.util.Map; import java.util.Properties; +import org.springframework.data.gemfire.GemFireProperties; import org.springframework.data.gemfire.config.annotation.support.EmbeddedServiceConfigurationSupport; import org.springframework.data.gemfire.util.PropertiesBuilder; @@ -34,11 +35,11 @@ @SuppressWarnings("unused") public class GeodeIntegratedSecurityConfiguration extends EmbeddedServiceConfigurationSupport { - protected static final String SECURITY_CLIENT_AUTH_INIT = "security-client-auth-init"; - protected static final String SECURITY_MANAGER = "security-manager"; - protected static final String SECURITY_PEER_AUTH_INIT = "security-peer-auth-init"; - protected static final String SECURITY_POST_PROCESSOR = "security-post-processor"; - protected static final String SECURITY_SHIRO_INIT = "security-shiro-init"; + protected static final String SECURITY_CLIENT_AUTH_INIT = GemFireProperties.SECURITY_CLIENT_AUTH_INIT.getName(); + protected static final String SECURITY_MANAGER = GemFireProperties.SECURITY_MANAGER.getName(); + protected static final String SECURITY_PEER_AUTH_INIT = GemFireProperties.SECURITY_PEER_AUTH_INIT.getName(); + protected static final String SECURITY_POST_PROCESSOR = GemFireProperties.SECURITY_POST_PROCESSOR.getName(); + protected static final String SECURITY_SHIRO_INIT = GemFireProperties.SECURITY_SHIRO_INIT.getName(); /** * Returns the {@link EnableSecurity} {@link java.lang.annotation.Annotation} {@link Class} type. @@ -52,11 +53,10 @@ protected Class getAnnotationType() { } /** - * Determines whether Pivotal GemFire/Apache Geode's Apache Shiro Security Framework support is enabled - * or available. + * Determines whether Apache Geode's Apache Shiro Security Framework support is enabled or available. * - * @return a boolean value indicating whether Pivotal GemFire/Apache Geode's Apache Shiro Security Framework - * support is enabled or available. + * @return a boolean value indicating whether Apache Geode's Apache Shiro Security Framework support + * is enabled or available. * @see #isShiroSecurityNotConfigured() */ protected boolean isShiroSecurityConfigured() { @@ -71,11 +71,10 @@ protected boolean isShiroSecurityConfigured() { } /** - * Determines whether Pivotal GemFire/Apache Geode's Apache Shiro Security Framework support is enabled - * or available. + * Determines whether Apache Geode's Apache Shiro Security Framework support is enabled or available. * - * @return a boolean value indicating whether Pivotal GemFire/Apache Geode's Apache Shiro Security Framework - * support is enabled or available. + * @return a boolean value indicating whether Apache Geode's Apache Shiro Security Framework support + * is enabled or available. * @see #isShiroSecurityConfigured() */ protected boolean isShiroSecurityNotConfigured() { diff --git a/spring-data-geode/src/main/java/org/springframework/data/gemfire/config/annotation/support/AbstractAuthInitialize.java b/spring-data-geode/src/main/java/org/springframework/data/gemfire/config/annotation/support/AbstractAuthInitialize.java index 6577e0fd1..5ac069b8a 100644 --- a/spring-data-geode/src/main/java/org/springframework/data/gemfire/config/annotation/support/AbstractAuthInitialize.java +++ b/spring-data-geode/src/main/java/org/springframework/data/gemfire/config/annotation/support/AbstractAuthInitialize.java @@ -13,13 +13,13 @@ * 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.cache.Cache; import org.apache.geode.distributed.DistributedMember; import org.apache.geode.security.AuthInitialize; import org.apache.geode.security.AuthenticationFailedException; @@ -27,14 +27,16 @@ import org.springframework.context.EnvironmentAware; import org.springframework.core.env.Environment; import org.springframework.data.gemfire.support.WiringDeclarableSupport; +import org.springframework.lang.Nullable; /** - * 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. + * Abstract class and basic implementation of the {@link AuthInitialize} interface used to authenticate a client + * or peer with a secure Apache Geode cluster. * * @author John Blum * @see java.util.Properties + * @see org.apache.geode.cache.Cache + * @see org.apache.geode.distributed.DistributedMember * @see org.apache.geode.security.AuthInitialize * @see org.springframework.context.EnvironmentAware * @see org.springframework.core.env.Environment @@ -44,6 +46,7 @@ public abstract class AbstractAuthInitialize extends WiringDeclarableSupport implements AuthInitialize, EnvironmentAware { + @Nullable private Environment environment; /** @@ -54,28 +57,56 @@ public abstract class AbstractAuthInitialize extends WiringDeclarableSupport */ @Override @SuppressWarnings("all") - public void setEnvironment(Environment environment) { + public void setEnvironment(@Nullable Environment environment) { this.environment = environment; } /** - * Returns a reference to the configured Spring {@link Environment}. + * Get an {@link Optional} reference to the configured Spring {@link Environment}. * - * @return a reference to the configured Spring {@link Environment}. + * @return an {@link Optional} reference to the configured Spring {@link Environment}. * @see org.springframework.core.env.Environment + * @see java.util.Optional */ protected Optional getEnvironment() { return Optional.ofNullable(this.environment); } + /** + * Initializes this Apache Geode component by auto-wiring (configuring) any dependencies managed by + * the Spring container required during authentication. + * + * @param systemLogWriter {@link LogWriter} for system output. + * @param securityLogWriter {@link LogWriter} for security output. + * @throws AuthenticationFailedException if this Apache Geode node could not be authenticated with + * the Apache Geode distributed system (cluster). + * @see #initialize(Cache, Properties) + * @see #doInit() + */ @Override @SuppressWarnings("deprecation") - public final void init(LogWriter logWriter, LogWriter logWriter1) throws AuthenticationFailedException { + public final void init(LogWriter systemLogWriter, LogWriter securityLogWriter) throws AuthenticationFailedException { doInit(); } protected void doInit() { } + /** + * Gets the security credentials used to authenticate this Apache Geode node + * with the Apache Geode distributed system (cluster). + * + * @param properties Apache Geode {@link Properties} to configure with authentication credentials + * used during the authentication request. + * @param distributedMember {@link DistributedMember} representing this Apache Geode node. + * @param isPeer boolean value indicating whether this Apache Geode node is joining the cluster + * as a peer or a client. + * @return the given Apache Geode {@link Properties}. + * @throws AuthenticationFailedException if this Apache Geode node could not be authenticated with + * the Apache Geode distributed system (cluster). + * @see org.apache.geode.distributed.DistributedMember + * @see #doGetCredentials(Properties) + * @see java.util.Properties + */ @Override public final Properties getCredentials(Properties properties, DistributedMember distributedMember, boolean isPeer) throws AuthenticationFailedException { @@ -85,7 +116,4 @@ public final Properties getCredentials(Properties properties, DistributedMember protected abstract Properties doGetCredentials(Properties properties); - @Override - public void close() { } - } diff --git a/spring-data-geode/src/main/java/org/springframework/data/gemfire/config/annotation/support/Authentication.java b/spring-data-geode/src/main/java/org/springframework/data/gemfire/config/annotation/support/Authentication.java new file mode 100644 index 000000000..849dce817 --- /dev/null +++ b/spring-data-geode/src/main/java/org/springframework/data/gemfire/config/annotation/support/Authentication.java @@ -0,0 +1,76 @@ +/* + * Copyright 2022 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 + * + * https://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.Objects; + +/** + * Abstract Data Type (ADT) and {@link FunctionalInterface} defining a contract to model the details of + * a security {@literal authentication} request. + * + * This ADT is loosely modeled after Spring Security's {@code Authentication} interface. + * + * @author John Blum + * @param {@link Class type} modeling the {@literal principal} object. + * @param {@link Class type} modeling the {@literal credentials} object. + * @see java.lang.FunctionalInterface + * @since 3.0.0 + */ +@FunctionalInterface +@SuppressWarnings("unused") +public interface Authentication { + + /** + * Determines whether the {@literal principal} has been successfully authenticated. + * + * @return a boolean value indicating whether the {@literal principal} has been successfully authenticated. + */ + default boolean isAuthenticated() { + return false; + } + + /** + * Determines whether {@literal authentication} was actually requested. + * + * The default implementation determines whether {@literal authentication} was requested by + * the presence a {@link PRINCIPAL} and {@link CREDENTIALS}. However, even if {@literal authentication} + * was requested, it does not necessarily mean the {@link PRINCIPAL} successfully authenticated. + * + * @return a boolean valuing indicating whether {@literal authentication} was actually requested. + * @see #getCredentials() + * @see #getPrincipal() + */ + default boolean isRequested() { + return Objects.nonNull(getPrincipal()) && Objects.nonNull(getCredentials()); + } + + /** + * Returns an {@link Object} identifying the {@literal principal} being authenticated. + * + * @return an {@link Object} identifying the {@literal principal} being authenticated. + */ + PRINCIPAL getPrincipal(); + + /** + * Returns an {@link Object} with credentials that prove the {@literal principal} is correct + * and is who they say they are. + * + * @return Returns an {@link Object} with credentials that prove the {@literal principal} is correct. + */ + default CREDENTIALS getCredentials() { + return null; + } +} diff --git a/spring-data-geode/src/main/java/org/springframework/data/gemfire/config/annotation/support/AutoConfiguredAuthenticationInitializer.java b/spring-data-geode/src/main/java/org/springframework/data/gemfire/config/annotation/support/AutoConfiguredAuthenticationInitializer.java index c52ceb4d8..da5b18d54 100644 --- a/spring-data-geode/src/main/java/org/springframework/data/gemfire/config/annotation/support/AutoConfiguredAuthenticationInitializer.java +++ b/spring-data-geode/src/main/java/org/springframework/data/gemfire/config/annotation/support/AutoConfiguredAuthenticationInitializer.java @@ -15,33 +15,40 @@ */ package org.springframework.data.gemfire.config.annotation.support; +import java.util.Optional; import java.util.Properties; import org.apache.geode.security.AuthInitialize; -import org.springframework.util.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.gemfire.GemfireUtils; +import org.springframework.lang.NonNull; +import org.springframework.lang.Nullable; /** * The {@link AutoConfiguredAuthenticationInitializer} class is an {@link AuthInitialize} implementation, * which auto-configures security, and specifically authentication, for Apache Geode/Pivotal GemFire. * * @author John Blum + * @see java.util.Properties * @see org.apache.geode.security.AuthInitialize + * @see org.springframework.data.gemfire.config.annotation.support.Authentication * @since 2.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"; + public static final String SECURITY_USERNAME_PROPERTY = SECURITY_USERNAME; + public static final String SECURITY_PASSWORD_PROPERTY = SECURITY_PASSWORD; protected static final Properties NO_PARAMETERS = new Properties(); + private Authentication authentication; + /** - * Factory method used to construct a new instance of {@link AutoConfiguredAuthenticationInitializer}. + * Factory method used to construct a new instance of {@link AutoConfiguredAuthenticationInitializer} + * that will be auto-wired with a SDG {@link Authentication} providing Apache Geode Security and Auth + * were configured/requested. * * @return a new instance of {@link AutoConfiguredAuthenticationInitializer}. * @see org.springframework.data.gemfire.config.annotation.support.AutoConfiguredAuthenticationInitializer @@ -51,24 +58,28 @@ public static AutoConfiguredAuthenticationInitializer newAuthenticationInitializ AutoConfiguredAuthenticationInitializer authenticationInitializer = new AutoConfiguredAuthenticationInitializer(); - authenticationInitializer.init(NO_PARAMETERS); + authenticationInitializer.initialize(GemfireUtils.getCache(), NO_PARAMETERS); return authenticationInitializer; } - @Override - protected Properties doGetCredentials(Properties properties) { - - getEnvironment() - .filter(environment -> StringUtils.hasText(environment.getProperty(SDG_SECURITY_USERNAME_PROPERTY))) - .ifPresent(environment -> { + @Autowired(required = false) + public void setAuthentication(@Nullable Authentication authentication) { + this.authentication = authentication; + } - String securityUsername = environment.getProperty(SDG_SECURITY_USERNAME_PROPERTY); - String securityPassword = environment.getProperty(SDG_SECURITY_PASSWORD_PROPERTY); + protected Optional> getAuthentication() { + return Optional.ofNullable(this.authentication); + } - properties.setProperty(SECURITY_USERNAME_PROPERTY, securityUsername); - properties.setProperty(SECURITY_PASSWORD_PROPERTY, securityPassword); + @Override + protected @NonNull Properties doGetCredentials(@NonNull Properties properties) { + getAuthentication() + .filter(Authentication::isRequested) + .ifPresent(authentication -> { + properties.setProperty(SECURITY_USERNAME_PROPERTY, authentication.getPrincipal()); + properties.setProperty(SECURITY_PASSWORD_PROPERTY, authentication.getCredentials()); }); return properties; diff --git a/spring-data-geode/src/main/java/org/springframework/data/gemfire/support/DeclarableSupport.java b/spring-data-geode/src/main/java/org/springframework/data/gemfire/support/DeclarableSupport.java index fdec9d4da..571f8c020 100644 --- a/spring-data-geode/src/main/java/org/springframework/data/gemfire/support/DeclarableSupport.java +++ b/spring-data-geode/src/main/java/org/springframework/data/gemfire/support/DeclarableSupport.java @@ -25,19 +25,21 @@ import org.springframework.data.gemfire.PeerRegionFactoryBean; /** - * Convenience class for Spring aware, Apache Geode {@link Declarable} components. Provides subclasses with a reference - * to the current Spring {@link BeanFactory} in order to perform Spring bean lookups or resource loading. + * Abstract base class for implementing Spring aware, Apache Geode {@link Declarable} components. * - * Note, in most cases, the developer should just declare the same components as Spring beans in the Spring container, - * through {@link PeerRegionFactoryBean}, which gives access to the full Spring container capabilities and does not - * enforce the {@link Declarable} interface to be implemented. + * Provides subclasses with a reference to the current Spring {@link BeanFactory} in order to + * perform Spring bean lookups or resource loading. + * + * Note, in most cases, the developer should just declare the same Apache Geode components as Spring beans + * in the Spring container through the {@link PeerRegionFactoryBean}, which gives full access to the Spring container + * capabilities and does not enforce the {@link Declarable} interface to be implemented. * * @author Costin Leau * @author John Blum - * @see org.springframework.beans.factory.BeanFactory - * @see org.springframework.data.gemfire.support.GemfireBeanFactoryLocator * @see org.apache.geode.cache.CacheCallback * @see org.apache.geode.cache.Declarable + * @see org.springframework.beans.factory.BeanFactory + * @see org.springframework.data.gemfire.support.GemfireBeanFactoryLocator */ @SuppressWarnings("unused") public abstract class DeclarableSupport implements CacheCallback, Declarable { @@ -98,9 +100,6 @@ protected BeanFactory locateBeanFactory(String beanFactoryKey) { return newBeanFactoryLocator().useBeanFactory(beanFactoryKey); } - /** - * @inheritDoc - */ @Override public void close() { } diff --git a/spring-data-geode/src/main/java/org/springframework/data/gemfire/support/LazyWiringDeclarableSupport.java b/spring-data-geode/src/main/java/org/springframework/data/gemfire/support/LazyWiringDeclarableSupport.java index 128b78595..479301680 100644 --- a/spring-data-geode/src/main/java/org/springframework/data/gemfire/support/LazyWiringDeclarableSupport.java +++ b/spring-data-geode/src/main/java/org/springframework/data/gemfire/support/LazyWiringDeclarableSupport.java @@ -19,6 +19,7 @@ import java.util.Properties; import java.util.concurrent.atomic.AtomicReference; +import org.apache.geode.cache.Cache; import org.apache.geode.cache.CacheCallback; import org.apache.geode.cache.CacheLoader; import org.apache.geode.cache.Declarable; @@ -31,20 +32,22 @@ import org.springframework.context.ApplicationListener; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.event.ContextRefreshedEvent; +import org.springframework.data.gemfire.util.SpringExtensions; +import org.springframework.lang.NonNull; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** - * The {@link LazyWiringDeclarableSupport} class is an implementation of GemFire's {@link Declarable} interface - * that enables support for wiring GemFire components with Spring bean dependencies defined in - * a Spring {@link ApplicationContext}. + * Implementation of Apache Geode's {@link Declarable} interface that enables support for wiring Apache Geode components + * with Spring bean dependencies defined in a Spring {@link ApplicationContext}. * * @author John Blum * @see java.util.Properties + * @see org.apache.geode.cache.Cache * @see org.apache.geode.cache.CacheCallback * @see org.apache.geode.cache.Declarable * @see org.springframework.beans.factory.BeanFactory * @see org.springframework.beans.factory.DisposableBean - * @see org.springframework.beans.factory.config.ConfigurableListableBeanFactory * @see org.springframework.context.ApplicationContext * @see org.springframework.context.ApplicationListener * @see org.springframework.context.event.ContextRefreshedEvent @@ -56,8 +59,8 @@ public abstract class LazyWiringDeclarableSupport extends WiringDeclarableSupport implements ApplicationListener, DisposableBean { - // atomic reference to the parameters passed by GemFire when this Declarable object - // was constructed, configured and its init method called + // Atomic reference to the parameters passed by Apache Geode when this Declarable object + // was constructed, configured and its initialize(..) method called private final AtomicReference parametersReference = new AtomicReference<>(); // condition to determine the initialized state of this Declarable object @@ -155,16 +158,14 @@ protected boolean isNotInitialized() { * @see java.util.Properties */ @Override - public final void init(Properties parameters) { + public final void initialize(@Nullable Cache cache, @NonNull Properties parameters) { + // Set a reference to the Apache Geode (configuration) Properties setParameters(parameters); - try { - doInit(locateBeanFactory(), nullSafeGetParameters()); - } - catch (IllegalStateException ignore) { - // BeanFactory does not exist, has been closed or the GemfireBeanFactoryLocator is not in use - } + // A Throwable maybe thrown iff the BeanFactory does not exist, has been closed + // or the GemfireBeanFactoryLocator is not in use. + SpringExtensions.safeDoOperation(() -> doInit(locateBeanFactory(), nullSafeGetParameters())); } /** @@ -182,7 +183,7 @@ public final void init(Properties parameters) { * @see #doPostInit(java.util.Properties) * @see java.util.Properties */ - synchronized void doInit(BeanFactory beanFactory, Properties parameters) { + synchronized void doInit(@NonNull BeanFactory beanFactory, @NonNull Properties parameters) { this.initialized = isInitialized() || configureThis(beanFactory, parameters.getProperty(TEMPLATE_BEAN_NAME_PROPERTY)); @@ -200,7 +201,7 @@ synchronized void doInit(BeanFactory beanFactory, Properties parameters) { * @see #doInit(BeanFactory, Properties) * @see java.util.Properties */ - protected void doPostInit(Properties parameters) { } + protected void doPostInit(@NonNull Properties parameters) { } /** * Null-safe operation to return the parameters passed to this {@link Declarable} object when created by GemFire @@ -210,7 +211,7 @@ protected void doPostInit(Properties parameters) { } * (e.g. {@literal cache.xml}) and passed to this {@link Declarable} object. * @see java.util.Properties */ - protected Properties nullSafeGetParameters() { + protected @NonNull Properties nullSafeGetParameters() { Properties parameters = this.parametersReference.get(); @@ -224,7 +225,7 @@ protected Properties nullSafeGetParameters() { * configuration meta-data (e.g. {@literal cache.xml}) and passed to this {@link Declarable} object. * @see java.util.Properties */ - protected void setParameters(Properties parameters) { + protected void setParameters(@Nullable Properties parameters) { this.parametersReference.set(parameters); } @@ -240,7 +241,7 @@ protected void setParameters(Properties parameters) { */ @Override @SuppressWarnings("all") - public final void onApplicationEvent(ContextRefreshedEvent event) { + public final void onApplicationEvent(@NonNull ContextRefreshedEvent event) { ApplicationContext applicationContext = event.getApplicationContext(); diff --git a/spring-data-geode/src/main/java/org/springframework/data/gemfire/support/WiringDeclarableSupport.java b/spring-data-geode/src/main/java/org/springframework/data/gemfire/support/WiringDeclarableSupport.java index a2fc53dd8..8e7a3c4b6 100644 --- a/spring-data-geode/src/main/java/org/springframework/data/gemfire/support/WiringDeclarableSupport.java +++ b/spring-data-geode/src/main/java/org/springframework/data/gemfire/support/WiringDeclarableSupport.java @@ -18,11 +18,14 @@ import java.util.Properties; +import org.apache.geode.cache.Cache; import org.apache.geode.cache.Declarable; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.wiring.BeanConfigurerSupport; import org.springframework.beans.factory.wiring.BeanWiringInfo; +import org.springframework.lang.NonNull; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.StringUtils; @@ -47,44 +50,41 @@ public abstract class WiringDeclarableSupport extends DeclarableSupport { protected static final String TEMPLATE_BEAN_NAME_PROPERTY = "bean-name"; - /** - * @inheritDoc - */ @Override - public void init(Properties parameters) { + public void initialize(@Nullable Cache cache, @NonNull Properties parameters) { configureThis(parameters.getProperty(TEMPLATE_BEAN_NAME_PROPERTY)); } /** - * Configures this {@link Declarable} object using the bean defined and identified in the Spring {@link BeanFactory} - * with the given {@code name} used as a template for auto-wiring purposes. + * Configures this {@link Declarable} object using a Spring bean defined and identified in the Spring + * {@link BeanFactory} with the given {@link String name} used as a template for the auto-wiring function. * - * @param templateBeanName {@link String} containing the name of the Spring bean used as a template - * for auto-wiring purposes. + * @param templateBeanName {@link String} containing the {@literal name} of the Spring bean used as a template + * for the auto-wiring function. * @return a boolean value indicating whether this {@link Declarable} object was successfully configured * and initialized by the Spring container. * @see org.springframework.beans.factory.wiring.BeanConfigurerSupport * @see #configureThis(BeanFactory, String) * @see #locateBeanFactory() */ - protected boolean configureThis(String templateBeanName) { + protected boolean configureThis(@Nullable String templateBeanName) { return configureThis(locateBeanFactory(), templateBeanName); } /** - * Configures this {@link Declarable} object using the bean defined and identified in the given - * Spring {@link BeanFactory} with the given {@code name} used as a template for auto-wiring purposes. + * Configures this {@link Declarable} object using a Spring bean defined and identified in the given Spring + * {@link BeanFactory} with the given {@link String name} used as a template for the auto-wiring function. * - * @param beanFactory Spring {@link BeanFactory} used to configure, auto-wire - * and initialize this {@link Declarable} object. - * @param templateBeanName {@link String} containing the name of the Spring bean used as a template - * for auto-wiring purposes. + * @param beanFactory Spring {@link BeanFactory} used to auto-wire, configure and initialize + * this {@link Declarable} object; must not be {@literal null} + * @param templateBeanName {@link String} containing the {@literal name} of the Spring bean + * used as a template for the auto-wiring function. * @return a boolean value indicating whether this {@link Declarable} object was successfully configured * and initialized by the Spring container. * @see org.springframework.beans.factory.wiring.BeanConfigurerSupport * @see #newBeanConfigurer(BeanFactory, String) */ - protected boolean configureThis(BeanFactory beanFactory, String templateBeanName) { + protected boolean configureThis(@NonNull BeanFactory beanFactory, @Nullable String templateBeanName) { BeanConfigurerSupport beanConfigurer = newBeanConfigurer(beanFactory, templateBeanName); @@ -95,34 +95,32 @@ protected boolean configureThis(BeanFactory beanFactory, String templateBeanName } /** - * Constructs a new, initialized instance of {@link BeanConfigurerSupport} configured with - * the given Spring {@link BeanFactory}. + * Constructs a new instance of {@link BeanConfigurerSupport} configured with the given Spring {@link BeanFactory}. * - * @param beanFactory reference to the Spring {@link BeanFactory}. - * @return a new, initialized instance of {@link BeanConfigurerSupport} configured with - * the given Spring {@link BeanFactory}. + * @param beanFactory reference to the Spring {@link BeanFactory}; must not be {@literal null}. + * @return a new {@link BeanConfigurerSupport} configured with the given Spring {@link BeanFactory}. * @see org.springframework.beans.factory.wiring.BeanConfigurerSupport * @see org.springframework.beans.factory.BeanFactory * @see #newBeanConfigurer(BeanFactory, String) */ - protected BeanConfigurerSupport newBeanConfigurer(BeanFactory beanFactory) { + protected @NonNull BeanConfigurerSupport newBeanConfigurer(@NonNull BeanFactory beanFactory) { return newBeanConfigurer(beanFactory, null); } /** - * Constructs a new, initialized instance of {@link BeanConfigurerSupport} configured with - * the given Spring {@link BeanFactory} and name of a Spring bean defined in the Spring {@link BeanFactory} - * used as a template to wire this {@link Declarable} object. + * Constructs a new instance of {@link BeanConfigurerSupport} configured with the given Spring {@link BeanFactory} + * and {@link String name} of a Spring bean defined in the Spring {@link BeanFactory} used as a template + * to auto-wire this {@link Declarable} object. * - * @param beanFactory reference to the Spring {@link BeanFactory}. - * @param templateBeanName {@link String} containing the name of a Spring bean in the Spring {@link BeanFactory} - * used as a template to wire this {@link Declarable} object. - * @return a new, initialized instance of {@link BeanConfigurerSupport} configured with - * the given Spring {@link BeanFactory}. + * @param beanFactory reference to the Spring {@link BeanFactory}; must not be {@literal null}. + * @param templateBeanName {@link String} containing the {@literal name} of a Spring bean declared in + * the Spring {@link BeanFactory} used as a template to auto-wire this {@link Declarable} object. + * @return a new {@link BeanConfigurerSupport} configured with the given Spring {@link BeanFactory}. * @see org.springframework.beans.factory.wiring.BeanConfigurerSupport * @see org.springframework.beans.factory.BeanFactory */ - protected BeanConfigurerSupport newBeanConfigurer(BeanFactory beanFactory, String templateBeanName) { + protected @NonNull BeanConfigurerSupport newBeanConfigurer(@NonNull BeanFactory beanFactory, + @Nullable String templateBeanName) { BeanConfigurerSupport beanConfigurer = new BeanConfigurerSupport(); diff --git a/spring-data-geode/src/test/java/org/springframework/data/gemfire/config/annotation/AbstractGeodeSecurityIntegrationTests.java b/spring-data-geode/src/test/java/org/springframework/data/gemfire/config/annotation/AbstractGeodeSecurityIntegrationTests.java index 9f284b234..c9aeae6e9 100644 --- a/spring-data-geode/src/test/java/org/springframework/data/gemfire/config/annotation/AbstractGeodeSecurityIntegrationTests.java +++ b/spring-data-geode/src/test/java/org/springframework/data/gemfire/config/annotation/AbstractGeodeSecurityIntegrationTests.java @@ -64,10 +64,12 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import lombok.AccessLevel; import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.NonNull; import lombok.RequiredArgsConstructor; +import lombok.Setter; /** * Abstract base test class for implementing Apache Geode Integrated Security Integration Tests. @@ -177,7 +179,7 @@ protected Properties doGetCredentials(Properties securityProperties) { User user = getUser(); - return new PropertiesBuilder() + return PropertiesBuilder.create() .setProperty(SECURITY_USERNAME_PROPERTY, user.getName()) .setProperty(SECURITY_PASSWORD_PROPERTY, user.getCredentials()) .build(); @@ -211,7 +213,6 @@ ClientRegionFactoryBean echoRegion(GemFireCache gemfireCache) { ClientRegionFactoryBean echoRegion = new ClientRegionFactoryBean<>(); echoRegion.setCache(gemfireCache); - echoRegion.setClose(false); echoRegion.setShortcut(ClientRegionShortcut.PROXY); return echoRegion; @@ -277,8 +278,10 @@ public static class User implements Iterable, Principal, Serializable { private final Set roles = new HashSet<>(); - @NonNull + @lombok.NonNull private final String name; + + @Setter(AccessLevel.PROTECTED) private String credentials; public boolean hasPermission(ResourcePermission permission) { @@ -296,33 +299,23 @@ public boolean hasRole(Role role) { return this.roles.contains(role); } - /** - * @inheritDoc - */ @Override public Iterator iterator() { - return Collections.unmodifiableSet(this.roles).iterator(); + return Collections.unmodifiableSet(getRoles()).iterator(); } - /** - * @inheritDoc - */ @Override public String toString() { return getName(); } public User with(String credentials) { - - this.credentials = credentials; - + setCredentials(credentials); return this; } public User with(Role... roles) { - - Collections.addAll(this.roles, roles); - + Collections.addAll(getRoles(), roles); return this; } } diff --git a/spring-data-geode/src/test/java/org/springframework/data/gemfire/config/annotation/AutoConfiguredAuthenticationConfigurationIntegrationTests.java b/spring-data-geode/src/test/java/org/springframework/data/gemfire/config/annotation/AutoConfiguredAuthenticationConfigurationIntegrationTests.java index 66b4f4677..841bf3962 100644 --- a/spring-data-geode/src/test/java/org/springframework/data/gemfire/config/annotation/AutoConfiguredAuthenticationConfigurationIntegrationTests.java +++ b/spring-data-geode/src/test/java/org/springframework/data/gemfire/config/annotation/AutoConfiguredAuthenticationConfigurationIntegrationTests.java @@ -19,91 +19,65 @@ import static org.springframework.data.gemfire.config.annotation.TestSecurityManager.SECURITY_PASSWORD; import static org.springframework.data.gemfire.config.annotation.TestSecurityManager.SECURITY_USERNAME; -import org.junit.After; import org.junit.BeforeClass; import org.junit.Test; +import org.junit.runner.RunWith; import org.apache.geode.cache.CacheLoader; import org.apache.geode.cache.CacheLoaderException; import org.apache.geode.cache.GemFireCache; import org.apache.geode.cache.LoaderHelper; -import org.apache.geode.cache.Region; import org.apache.geode.cache.client.ClientRegionShortcut; -import org.springframework.context.ConfigurableApplicationContext; -import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; -import org.springframework.core.env.MutablePropertySources; -import org.springframework.core.env.PropertySource; +import org.springframework.data.gemfire.GemfireTemplate; +import org.springframework.data.gemfire.GemfireUtils; import org.springframework.data.gemfire.LocalRegionFactoryBean; import org.springframework.data.gemfire.client.ClientRegionFactoryBean; import org.springframework.data.gemfire.tests.integration.ForkingClientServerIntegrationTestsSupport; -import org.springframework.mock.env.MockPropertySource; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringRunner; /** - * Integration Tests for auto-configured authentication configuration. + * Integration Tests for {@link AutoConfiguredAuthenticationConfiguration}. * * @author John Blum * @see org.junit.Test * @see org.apache.geode.cache.GemFireCache - * @see org.apache.geode.cache.Region + * @see org.springframework.data.gemfire.GemfireTemplate + * @see org.springframework.data.gemfire.config.annotation.AutoConfiguredAuthenticationConfiguration * @see org.springframework.data.gemfire.tests.integration.ForkingClientServerIntegrationTestsSupport + * @see org.springframework.test.context.ContextConfiguration + * @see org.springframework.test.context.junit4.SpringRunner * @since 1.9.0 */ +@RunWith(SpringRunner.class) +@ContextConfiguration( + classes = AutoConfiguredAuthenticationConfigurationIntegrationTests.TestGemFireClientConfiguration.class +) @SuppressWarnings("unused") public class AutoConfiguredAuthenticationConfigurationIntegrationTests extends ForkingClientServerIntegrationTestsSupport { - private ConfigurableApplicationContext applicationContext; - @BeforeClass public static void setupGemFireServer() throws Exception { startGemFireServer(TestGemFireServerConfiguration.class); } - @After - public void tearDown() { - closeApplicationContext(this.applicationContext); - } - - private ConfigurableApplicationContext newApplicationContext(PropertySource testPropertySource, - Class... annotatedClasses) { - - AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(); - - MutablePropertySources propertySources = applicationContext.getEnvironment().getPropertySources(); - - propertySources.addFirst(testPropertySource); - - applicationContext.registerShutdownHook(); - applicationContext.register(annotatedClasses); - applicationContext.refresh(); - - return applicationContext; - } + @Autowired + private GemfireTemplate echoTemplate; @Test - @SuppressWarnings("unchecked") public void clientAuthenticatesWithServer() { - MockPropertySource testPropertySource = new MockPropertySource() - .withProperty("spring.data.gemfire.security.username", SECURITY_USERNAME) - .withProperty("spring.data.gemfire.security.password", SECURITY_PASSWORD); - - this.applicationContext = newApplicationContext(testPropertySource, TestGemFireClientConfiguration.class); - - assertThat(this.applicationContext).isNotNull(); - assertThat(this.applicationContext.containsBean("Echo")).isTrue(); - - Region echo = this.applicationContext.getBean("Echo", Region.class); - - assertThat(echo.get("Hello")).isEqualTo("Hello"); - assertThat(echo.get("TEST")).isEqualTo("TEST"); - assertThat(echo.get("Good-Bye")).isEqualTo("Good-Bye"); + assertThat(this.echoTemplate.get("Hello")).isEqualTo("Hello"); + assertThat(this.echoTemplate.get("TEST")).isEqualTo("TEST"); + assertThat(this.echoTemplate.get("Good-Bye")).isEqualTo("Good-Bye"); } @ClientCacheApplication - @EnableSecurity + @EnableSecurity(securityUsername = SECURITY_USERNAME, securityPassword = SECURITY_PASSWORD) static class TestGemFireClientConfiguration { @Bean("Echo") @@ -112,15 +86,19 @@ ClientRegionFactoryBean echoRegion(GemFireCache gemfireCache) { ClientRegionFactoryBean echoRegion = new ClientRegionFactoryBean<>(); echoRegion.setCache(gemfireCache); - echoRegion.setClose(false); echoRegion.setShortcut(ClientRegionShortcut.PROXY); return echoRegion; } + + @Bean + GemfireTemplate echoTemplate(GemFireCache cache) { + return new GemfireTemplate(cache.getRegion(GemfireUtils.toRegionPath("Echo"))); + } } @CacheServerApplication - @EnableSecurity(securityManagerClassName = "org.springframework.data.gemfire.config.annotation.TestSecurityManager") + @EnableSecurity(securityManagerClass = TestSecurityManager.class) static class TestGemFireServerConfiguration { public static void main(String[] args) { @@ -134,7 +112,6 @@ LocalRegionFactoryBean echoRegion(GemFireCache gemfireCache) { echoRegion.setCache(gemfireCache); echoRegion.setCacheLoader(newEchoCacheLoader()); - echoRegion.setClose(false); echoRegion.setPersistent(false); return echoRegion; @@ -150,8 +127,8 @@ public Object load(LoaderHelper loaderHelper) throws CacheLoader } @Override - public void close() { - } + public void close() { } + }; } } diff --git a/spring-data-geode/src/test/java/org/springframework/data/gemfire/config/annotation/GeodeIntegratedSecurityConfigurationUnitTests.java b/spring-data-geode/src/test/java/org/springframework/data/gemfire/config/annotation/GeodeIntegratedSecurityConfigurationUnitTests.java new file mode 100644 index 000000000..332cd05b1 --- /dev/null +++ b/spring-data-geode/src/test/java/org/springframework/data/gemfire/config/annotation/GeodeIntegratedSecurityConfigurationUnitTests.java @@ -0,0 +1,75 @@ +/* + * Copyright 2022 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 + * + * https://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 static org.assertj.core.api.Assertions.assertThat; + +import java.util.Map; +import java.util.Properties; + +import org.junit.Test; + +import org.springframework.data.gemfire.test.support.MapBuilder; + +/** + * Unit Tests for {@link GeodeIntegratedSecurityConfiguration}. + * + * @author John Blum + * @see java.util.Properties + * @see org.junit.Test + * @see org.springframework.data.gemfire.config.annotation.GeodeIntegratedSecurityConfiguration + * @since 1.0.0 + */ +public class GeodeIntegratedSecurityConfigurationUnitTests { + + @Test + public void toGemFirePropertiesIsCorrect() { + + Map annotationAttributes = MapBuilder.newMapBuilder() + .put("clientAuthenticationInitializer", "example.TestSecurityClientAuthenticationInitialization") + .put("securityManagerClass", TestSecurityManager.class) + .put("securityManagerClassName", " ") + .put("peerAuthenticationInitializer", "example.TestSecurityPeerAuthenticationInitializer") + .put("securityPostProcessorClass", TestSecurityPostProcessor.class) + .put("securityPostProcessorClassName", "") + .build(); + + GeodeIntegratedSecurityConfiguration configuration = new GeodeIntegratedSecurityConfiguration(); + + Properties gemfireProperties = configuration.toGemFireProperties(annotationAttributes); + + assertThat(gemfireProperties).isNotNull(); + assertThat(gemfireProperties).isNotEmpty(); + assertThat(gemfireProperties.getProperty(GeodeIntegratedSecurityConfiguration.SECURITY_CLIENT_AUTH_INIT)) + .isEqualTo("example.TestSecurityClientAuthenticationInitialization"); + assertThat(gemfireProperties.getProperty(GeodeIntegratedSecurityConfiguration.SECURITY_MANAGER)) + .isEqualTo(TestSecurityManager.class.getName()); + assertThat(gemfireProperties).doesNotContainKey(GeodeIntegratedSecurityConfiguration.SECURITY_SHIRO_INIT); + assertThat(gemfireProperties.getProperty(GeodeIntegratedSecurityConfiguration.SECURITY_PEER_AUTH_INIT)) + .isEqualTo("example.TestSecurityPeerAuthenticationInitializer"); + assertThat(gemfireProperties.getProperty(GeodeIntegratedSecurityConfiguration.SECURITY_POST_PROCESSOR)) + .isEqualTo(TestSecurityPostProcessor.class.getName()); + + } + + private static class TestSecurityPostProcessor implements org.apache.geode.security.PostProcessor { + + @Override + public Object processRegionValue(Object principal, String regionName, Object key, Object value) { + return value; + } + } +} diff --git a/spring-data-geode/src/test/java/org/springframework/data/gemfire/config/annotation/LocatorApplicationIntegrationTests.java b/spring-data-geode/src/test/java/org/springframework/data/gemfire/config/annotation/LocatorApplicationIntegrationTests.java index f3c40cb5b..a76ad667d 100644 --- a/spring-data-geode/src/test/java/org/springframework/data/gemfire/config/annotation/LocatorApplicationIntegrationTests.java +++ b/spring-data-geode/src/test/java/org/springframework/data/gemfire/config/annotation/LocatorApplicationIntegrationTests.java @@ -29,6 +29,7 @@ import org.apache.geode.distributed.Locator; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.gemfire.GemFireProperties; import org.springframework.data.gemfire.GemfireUtils; import org.springframework.data.gemfire.tests.integration.IntegrationTestsSupport; import org.springframework.test.context.ContextConfiguration; @@ -84,14 +85,15 @@ public void gemfireCacheCanConnectToLocator() { try { peerCache = new CacheFactory() - .set("name", LocatorApplicationIntegrationTests.class.getSimpleName()) - .set("bind-address", distributedSystemProperties.getProperty("bind-address")) - .set("cache-xml-file", distributedSystemProperties.getProperty("cache-xml-file")) - .set("jmx-manager", distributedSystemProperties.getProperty("jmx-manager")) - .set("locators", distributedSystemProperties.getProperty("locators")) + .set(GemFireProperties.NAME.getName(), LocatorApplicationIntegrationTests.class.getSimpleName()) + .set(GemFireProperties.BIND_ADDRESS.getName(), distributedSystemProperties.getProperty(GemFireProperties.BIND_ADDRESS.getName())) + .set(GemFireProperties.CACHE_XML_FILE.getName(), distributedSystemProperties.getProperty(GemFireProperties.CACHE_XML_FILE.getName())) + .set(GemFireProperties.JMX_MANAGER.getName(), distributedSystemProperties.getProperty(GemFireProperties.JMX_MANAGER.getName())) + .set(GemFireProperties.LOCATORS.getName(), distributedSystemProperties.getProperty(GemFireProperties.LOCATORS.getName())) //.set("locators", "localhost[0]") // This locators configuration setting causes the test to fail - .set("log-file", distributedSystemProperties.getProperty("log-file")) - .set("log-level", distributedSystemProperties.getProperty("log-level")) + .set(GemFireProperties.LOG_FILE.getName(), distributedSystemProperties.getProperty(GemFireProperties.LOG_FILE.getName())) + .set(GemFireProperties.LOG_LEVEL.getName(), distributedSystemProperties.getProperty(GemFireProperties.LOG_LEVEL.getName())) + .set(GemFireProperties.USE_CLUSTER_CONFIGURATION.getName(), distributedSystemProperties.getProperty(GemFireProperties.USE_CLUSTER_CONFIGURATION.getName())) .create(); assertThat(peerCache).isNotNull(); diff --git a/spring-data-geode/src/test/java/org/springframework/data/gemfire/config/annotation/SecureLocatorApplicationIntegrationTests.java b/spring-data-geode/src/test/java/org/springframework/data/gemfire/config/annotation/SecureLocatorApplicationIntegrationTests.java index defb53299..bbfa974cc 100644 --- a/spring-data-geode/src/test/java/org/springframework/data/gemfire/config/annotation/SecureLocatorApplicationIntegrationTests.java +++ b/spring-data-geode/src/test/java/org/springframework/data/gemfire/config/annotation/SecureLocatorApplicationIntegrationTests.java @@ -84,8 +84,8 @@ public void locatorIsSecure() { } @LocatorApplication(port = 0) - //@EnableSecurity(securityManagerClass = TestSecurityManager.class) - @EnableSecurity(securityManagerClassName = "org.springframework.data.gemfire.config.annotation.TestSecurityManager") + @EnableSecurity(securityManagerClass = TestSecurityManager.class) + //@EnableSecurity(securityManagerClassName = "org.springframework.data.gemfire.config.annotation.TestSecurityManager") static class TestConfiguration { } static final class MockSecurityManager implements org.apache.geode.security.SecurityManager { diff --git a/spring-data-geode/src/test/java/org/springframework/data/gemfire/config/annotation/SecurityManagerSecuredLocatorToLocatorApplicationIntegrationTests.java b/spring-data-geode/src/test/java/org/springframework/data/gemfire/config/annotation/SecurityManagerSecuredLocatorToLocatorApplicationIntegrationTests.java new file mode 100644 index 000000000..d1bf7fe6c --- /dev/null +++ b/spring-data-geode/src/test/java/org/springframework/data/gemfire/config/annotation/SecurityManagerSecuredLocatorToLocatorApplicationIntegrationTests.java @@ -0,0 +1,117 @@ +/* + * Copyright 2022 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 + * + * https://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 static org.assertj.core.api.Assertions.assertThat; + +import java.io.IOException; + +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.apache.geode.distributed.DistributedSystem; +import org.apache.geode.distributed.Locator; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Profile; +import org.springframework.data.gemfire.tests.integration.ForkingClientServerIntegrationTestsSupport; +import org.springframework.data.gemfire.tests.process.ProcessWrapper; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringRunner; + +/** + * Apache Geode Security Integration Tests testing Apache Geode Locator to Locator (application) authentication. + * + * @author John Blum + * @see org.junit.Test + * @see org.apache.geode.distributed.DistributedSystem + * @see org.apache.geode.distributed.Locator + * @see org.springframework.context.annotation.Profile + * @see org.springframework.data.gemfire.LocatorFactoryBean + * @see org.springframework.data.gemfire.config.annotation.EnableSecurity + * @see org.springframework.data.gemfire.config.annotation.LocatorApplication + * @see org.springframework.data.gemfire.tests.integration.ForkingClientServerIntegrationTestsSupport + * @see org.springframework.test.context.ActiveProfiles + * @see org.springframework.test.context.ContextConfiguration + * @see org.springframework.test.context.junit4.SpringRunner + * @since 1.0.0 + */ +@ActiveProfiles("locator-auth-client") +@ContextConfiguration(classes = SecurityManagerSecuredLocatorToLocatorApplicationIntegrationTests.LocatorAuthClient.class) +@RunWith(SpringRunner.class) +@SuppressWarnings("unused") +public class SecurityManagerSecuredLocatorToLocatorApplicationIntegrationTests + extends ForkingClientServerIntegrationTestsSupport { + + private static ProcessWrapper locatorProcess; + + @BeforeClass + public static void startGeodeLocator() throws IOException { + + int locatorPort = findAndReserveAvailablePort(); + + locatorProcess= run(LocatorAuthServer.class, + "-Dspring.profiles.active=locator-auth-server", + String.format("-Dspring.data.gemfire.locator.port=%d", locatorPort)); + + waitForServerToStart("localhost", locatorPort); + + System.setProperty("spring.data.gemfire.locators", String.format("localhost[%d]", locatorPort)); + } + + @AfterClass + public static void stopGeodeLocator() { + stop(locatorProcess); + System.clearProperty("spring.data.gemfire.locators"); + } + + @Autowired + private Locator locator; + + @Test + public void locatorIsRunning() { + + assertThat(this.locator).isNotNull(); + + DistributedSystem distributedSystem = this.locator.getDistributedSystem(); + + assertThat(distributedSystem).isNotNull(); + assertThat(distributedSystem.isConnected()).isTrue(); + assertThat(distributedSystem.getName()).isEqualTo("LocatorAuthClient"); + assertThat(distributedSystem.getDistributedMember().getName()).isEqualTo("LocatorAuthClient"); + assertThat(distributedSystem.getAllOtherMembers()).hasSize(1); + } + + @LocatorApplication(name = "LocatorAuthServer") + @EnableSecurity(securityManagerClass = TestSecurityManager.class) + @Profile("locator-auth-server") + static class LocatorAuthServer { + + public static void main(String[] args) { + runSpringApplication(LocatorAuthServer.class); + block(); + } + } + + @LocatorApplication(name = "LocatorAuthClient", port = 0) + @EnableSecurity(securityUsername = TestSecurityManager.SECURITY_USERNAME, securityPassword = TestSecurityManager.SECURITY_PASSWORD) + @Profile("locator-auth-client") + static class LocatorAuthClient { } + +} diff --git a/spring-data-geode/src/test/java/org/springframework/data/gemfire/config/annotation/ShiroSecuredClusteredLocatorApplicationIntegrationTests.java b/spring-data-geode/src/test/java/org/springframework/data/gemfire/config/annotation/ShiroSecuredClusteredLocatorApplicationIntegrationTests.java new file mode 100644 index 000000000..ced180bd7 --- /dev/null +++ b/spring-data-geode/src/test/java/org/springframework/data/gemfire/config/annotation/ShiroSecuredClusteredLocatorApplicationIntegrationTests.java @@ -0,0 +1,221 @@ +/* + * Copyright 2022 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 + * + * https://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 static org.assertj.core.api.Assertions.assertThat; + +import java.io.IOException; + +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.apache.geode.cache.GemFireCache; +import org.apache.geode.cache.RegionShortcut; +import org.apache.geode.internal.security.shiro.GeodePermissionResolver; + +import org.apache.shiro.realm.text.PropertiesRealm; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.FilterType; +import org.springframework.context.annotation.Import; +import org.springframework.context.annotation.Profile; +import org.springframework.data.annotation.Id; +import org.springframework.data.gemfire.GemfireTemplate; +import org.springframework.data.gemfire.GemfireUtils; +import org.springframework.data.gemfire.mapping.annotation.Region; +import org.springframework.data.gemfire.tests.integration.ForkingClientServerIntegrationTestsSupport; +import org.springframework.data.gemfire.tests.process.ProcessWrapper; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringRunner; + +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import lombok.ToString; + +/** + * Integration Tests for {@link LocatorApplication} and {@link LocatorApplicationConfiguration} + * with {@link EnableSecurity} using Apache Shiro. + * + * @author John Blum + * @see org.junit.Test + * @see org.apache.geode.cache.GemFireCache + * @see org.apache.geode.distributed.Locator + * @see org.springframework.context.annotation.Bean + * @see org.springframework.context.annotation.Configuration + * @see org.springframework.context.annotation.Import + * @see org.springframework.data.gemfire.tests.integration.ForkingClientServerIntegrationTestsSupport + * @see org.springframework.test.context.ContextConfiguration + * @see org.springframework.test.context.junit4.SpringRunner + * @since 1.0.0 + */ +@SuppressWarnings("unused") +@RunWith(SpringRunner.class) +@ContextConfiguration(classes = ShiroSecuredClusteredLocatorApplicationIntegrationTests.TestClientConfiguration.class) +public class ShiroSecuredClusteredLocatorApplicationIntegrationTests + extends ForkingClientServerIntegrationTestsSupport { + + private static ProcessWrapper locatorProcessOne; + private static ProcessWrapper locatorProcessTwo; + + private static final String CLUSTER_SECURITY_USERNAME = "root"; + private static final String CLUSTER_SECURITY_PASSWORD = "s3c3rt!"; + + @BeforeClass + public static void assertApacheShiroSecurityEnabled() { + + String propertyName = ApacheShiroSecurityConfiguration.ApacheShiroPresentCondition + .SPRING_DATA_GEMFIRE_SECURITY_SHIRO_ENABLED; + + String apacheShiroEnabledValue = System.getProperty(propertyName, Boolean.TRUE.toString()); + + boolean apacheShiroEnabled = Boolean.parseBoolean(apacheShiroEnabledValue); + + assertThat(apacheShiroEnabled).isTrue(); + } + + @BeforeClass + public static void startApacheGeodeCluster() throws IOException { + + int locatorPort = findAndReserveAvailablePort(); + + String locatorBaseName = ShiroSecuredClusteredLocatorApplicationIntegrationTests.class.getSimpleName().concat("%s"); + String locatorOneName = String.format(locatorBaseName, "LocatorOne"); + String locatorTwoName = String.format(locatorBaseName, "LocatorTwo"); + + locatorProcessOne = run(createDirectory(locatorOneName), TestLocatorApplication.class, + "-Dspring.profiles.active=auth-server", + String.format("-Dspring.data.gemfire.locator.name=%s", locatorOneName), + String.format("-Dspring.data.gemfire.locator.port=%d", locatorPort)); + + waitForServerToStart("localhost", locatorPort); + + locatorProcessTwo = run(createDirectory(locatorTwoName), TestLocatorApplication.class, + //String.format("-Dspring.data.gemfire.security.username=%s", CLUSTER_SECURITY_USERNAME), + //String.format("-Dspring.data.gemfire.security.password=%s", CLUSTER_SECURITY_PASSWORD), + String.format("-Dspring.data.gemfire.locator.name=%s", locatorTwoName), + String.format("-Dspring.data.gemfire.locators=localhost[%d]", locatorPort)); + + startGemFireServer(TestServerApplication.class, + //String.format("-Dspring.data.gemfire.security.username=%s", CLUSTER_SECURITY_USERNAME), + //String.format("-Dspring.data.gemfire.security.password=%s", CLUSTER_SECURITY_PASSWORD), + //String.format("-Dspring.data.gemfire.security.username=%s", "guest"), + //String.format("-Dspring.data.gemfire.security.password=%s", "guest"), + String.format("-Dspring.data.gemfire.locators=localhost[%d]", locatorPort)); + } + + @AfterClass + public static void shutdownApacheGeodeCluster() { + + // NOTE: The Apache Geode CacheServer process will be stopped automatically by the STDG framework + // on test class (suite) teardown! + stop(locatorProcessOne); + stop(locatorProcessTwo); + } + + @Autowired + private GemfireTemplate customersTemplate; + + @Test + public void secureClientCacheCustomersRegionPutAndGetOperationsAreSuccess() { + + Customer jonDoe = Customer.as("Jon Doe"); + + this.customersTemplate.put(jonDoe.getName(), jonDoe); + + Customer jonDoeLoaded = this.customersTemplate.get(jonDoe.getName()); + + assertThat(jonDoeLoaded).isNotNull(); + assertThat(jonDoeLoaded).isNotSameAs(jonDoe); + assertThat(jonDoeLoaded).isEqualTo(jonDoe); + } + + @Configuration + @EnableEntityDefinedRegions( + basePackageClasses = Customer.class, + serverRegionShortcut = RegionShortcut.LOCAL, + includeFilters = @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = Customer.class) + ) + @EnablePdx(includeDomainTypes = Customer.class) + static class TestApplicationConfiguration { } + + @Configuration + @EnableSecurity(securityUsername = CLUSTER_SECURITY_USERNAME, securityPassword = CLUSTER_SECURITY_PASSWORD) + static class TestSecurityConfiguration { + + @Bean + @Profile("auth-server") + public PropertiesRealm shiroRealm() { + + PropertiesRealm propertiesRealm = new PropertiesRealm(); + + propertiesRealm.setResourcePath("classpath:shiro.properties"); + propertiesRealm.setPermissionResolver(new GeodePermissionResolver()); + + return propertiesRealm; + } + } + + @ClientCacheApplication(name = "ShiroSecuredLocatorApplicationIntegrationTestsClientCache") + @EnableSecurity(securityUsername = "scientist", securityPassword = "w0rk!ng4u") + @Import(TestApplicationConfiguration.class) + static class TestClientConfiguration { + + @Bean + GemfireTemplate customersTemplate(GemFireCache cache) { + return new GemfireTemplate(cache.getRegion(GemfireUtils.toRegionPath("Customers"))); + } + } + + @LocatorApplication(name = "ShiroSecuredLocatorApplicationIntegrationTestsLocator", port = 0) + @Import(TestSecurityConfiguration.class) + static class TestLocatorApplication { + + public static void main(String[] args) { + assertApacheShiroSecurityEnabled(); + runSpringApplication(TestLocatorApplication.class, args); + block(); + } + } + + @CacheServerApplication(name = "ShiroSecuredLocatorApplicationIntegrationTestsCacheServer") + @Import({ TestApplicationConfiguration.class, TestSecurityConfiguration.class }) + static class TestServerApplication { + + public static void main(String[] args) { + assertApacheShiroSecurityEnabled(); + runSpringApplication(TestServerApplication.class, args); + } + } + + @Getter + @EqualsAndHashCode + @ToString(of = "name") + @Region("Customers") + @RequiredArgsConstructor(staticName = "as") + @SuppressWarnings("all") + static class Customer { + + @Id @lombok.NonNull + private final String name; + + } +} diff --git a/spring-data-geode/src/test/java/org/springframework/data/gemfire/config/annotation/TestSecurityManager.java b/spring-data-geode/src/test/java/org/springframework/data/gemfire/config/annotation/TestSecurityManager.java index ecdbc87d1..6bd924c0c 100644 --- a/spring-data-geode/src/test/java/org/springframework/data/gemfire/config/annotation/TestSecurityManager.java +++ b/spring-data-geode/src/test/java/org/springframework/data/gemfire/config/annotation/TestSecurityManager.java @@ -15,7 +15,6 @@ */ package org.springframework.data.gemfire.config.annotation; -import static org.springframework.data.gemfire.config.annotation.TestSecurityManager.TestPrincipal.newPrincipal; import static org.springframework.data.gemfire.util.RuntimeExceptionFactory.newIllegalArgumentException; import java.security.Principal; @@ -27,6 +26,7 @@ import java.util.concurrent.ConcurrentMap; import org.apache.geode.security.AuthenticationFailedException; +import org.apache.geode.security.SecurityManager; import org.springframework.util.StringUtils; @@ -46,8 +46,8 @@ public final class TestSecurityManager implements org.apache.geode.security.Secu public static final String SECURITY_USERNAME = "testUser"; public static final String SECURITY_PASSWORD = "&t35t9@55w0rd!"; - public static final String SECURITY_USERNAME_PROPERTY = "security-username"; - public static final String SECURITY_PASSWORD_PROPERTY = "security-password"; + public static final String SECURITY_USERNAME_PROPERTY = SecurityManager.USER_NAME; + public static final String SECURITY_PASSWORD_PROPERTY = SecurityManager.PASSWORD; private final ConcurrentMap authorizedUsers; @@ -56,7 +56,7 @@ public TestSecurityManager() { this.authorizedUsers.putIfAbsent(SECURITY_USERNAME, SECURITY_PASSWORD); } - protected Map getAuthorizedUsers() { + private Map getAuthorizedUsers() { return Collections.unmodifiableMap(this.authorizedUsers); } @@ -71,7 +71,7 @@ public Object authenticate(Properties credentials) throws AuthenticationFailedEx } private Principal identify(String username, String password) { - return isIdentified(username, password) ? newPrincipal(username) : null; + return isIdentified(username, password) ? TestPrincipal.newPrincipal(username) : null; } private boolean isIdentified(String username, String password) { @@ -93,7 +93,8 @@ public static TestPrincipal newPrincipal(String username) { } public TestPrincipal(String name) { - this.name = Optional.ofNullable(name).filter(StringUtils::hasText) + this.name = Optional.ofNullable(name) + .filter(StringUtils::hasText) .orElseThrow(() -> newIllegalArgumentException("Name is required")); } diff --git a/spring-data-geode/src/test/java/org/springframework/data/gemfire/config/annotation/UsingAnnotationConfigWithBeanDefinitionOverridingDisabledIntegrationTests.java b/spring-data-geode/src/test/java/org/springframework/data/gemfire/config/annotation/UsingAnnotationConfigWithBeanDefinitionOverridingDisabledIntegrationTests.java index 4ae83916b..ae4b5c869 100644 --- a/spring-data-geode/src/test/java/org/springframework/data/gemfire/config/annotation/UsingAnnotationConfigWithBeanDefinitionOverridingDisabledIntegrationTests.java +++ b/spring-data-geode/src/test/java/org/springframework/data/gemfire/config/annotation/UsingAnnotationConfigWithBeanDefinitionOverridingDisabledIntegrationTests.java @@ -109,7 +109,7 @@ public void gemfireCacheSecurityAndSslConfigurationIsCorrect() { assertThat(gemfireProperties).isNotEmpty(); assertThat(gemfireProperties.getProperty(GemFireProperties.SECURITY_MANAGER.getName())) - .isEqualTo(String.valueOf(TestSecurityManager.class)); + .isEqualTo(String.valueOf(TestSecurityManager.class.getName())); assertThat(gemfireProperties.getProperty(GemFireProperties.SSL_KEYSTORE.getName())) .isEqualTo("/path/to/test/keystore.jks"); diff --git a/spring-data-geode/src/test/java/org/springframework/data/gemfire/support/LazyWiringDeclarableSupportIntegrationTests.java b/spring-data-geode/src/test/java/org/springframework/data/gemfire/support/LazyWiringDeclarableSupportIntegrationTests.java index 3394022b7..3c9b42a0f 100644 --- a/spring-data-geode/src/test/java/org/springframework/data/gemfire/support/LazyWiringDeclarableSupportIntegrationTests.java +++ b/spring-data-geode/src/test/java/org/springframework/data/gemfire/support/LazyWiringDeclarableSupportIntegrationTests.java @@ -27,11 +27,14 @@ import org.junit.Test; import org.junit.runner.RunWith; +import org.apache.geode.cache.Cache; + import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; import org.springframework.context.event.ContextRefreshedEvent; import org.springframework.data.gemfire.repository.sample.User; import org.springframework.data.gemfire.tests.integration.IntegrationTestsSupport; +import org.springframework.data.gemfire.tests.mock.CacheMockObjects; import org.springframework.data.gemfire.tests.support.DataSourceAdapter; import org.springframework.data.gemfire.util.PropertiesBuilder; import org.springframework.test.context.ContextConfiguration; @@ -42,9 +45,12 @@ * Integration Tests for {@link LazyWiringDeclarableSupport}. * * @author John Blum + * @see java.util.Properties + * @see javax.sql.DataSource * @see org.junit.Test * @see org.springframework.context.ApplicationContext * @see org.springframework.data.gemfire.tests.integration.IntegrationTestsSupport + * @see org.springframework.data.gemfire.tests.mock.CacheMockObjects * @see org.springframework.test.context.ContextConfiguration * @see org.springframework.test.context.junit4.SpringRunner * @since 1.3.4 @@ -66,12 +72,15 @@ public static void tearDown() { @Autowired private ApplicationContext applicationContext; + private final Cache mockCache = CacheMockObjects + .mockPeerCache("MockCache", null, null); + @Test public void autoWiringSuccessful() { TestDeclarable declarable = new TestDeclarable(); - declarable.init(createParameters("testParam", "testValue")); + declarable.initialize(this.mockCache, createParameters("testParam", "testValue")); declarable.onApplicationEvent(new ContextRefreshedEvent(applicationContext)); declarable.assertInitialized(); @@ -85,7 +94,7 @@ public void autoWiringWithBeanTemplateSuccessful() { TestDeclarable declarable = new TestDeclarable(); - declarable.init(createParameters(TEMPLATE_BEAN_NAME_PROPERTY, "declarableTemplateBean")); + declarable.initialize(this.mockCache, createParameters(TEMPLATE_BEAN_NAME_PROPERTY, "declarableTemplateBean")); declarable.onApplicationEvent(new ContextRefreshedEvent(applicationContext)); declarable.assertInitialized(); @@ -101,7 +110,7 @@ public void autoWiringWithNonExistingBeanTemplateThrowsIllegalArgumentException( TestDeclarable declarable = new TestDeclarable(); - declarable.init(createParameters(TEMPLATE_BEAN_NAME_PROPERTY, "nonExistingBeanTemplate")); + declarable.initialize(this.mockCache, createParameters(TEMPLATE_BEAN_NAME_PROPERTY, "nonExistingBeanTemplate")); declarable.onApplicationEvent(new ContextRefreshedEvent(applicationContext)); } catch (IllegalStateException expected) { diff --git a/spring-data-geode/src/test/java/org/springframework/data/gemfire/support/LazyWiringDeclarableSupportUnitTests.java b/spring-data-geode/src/test/java/org/springframework/data/gemfire/support/LazyWiringDeclarableSupportUnitTests.java index 4a6fd13c7..3aee92a5a 100644 --- a/spring-data-geode/src/test/java/org/springframework/data/gemfire/support/LazyWiringDeclarableSupportUnitTests.java +++ b/spring-data-geode/src/test/java/org/springframework/data/gemfire/support/LazyWiringDeclarableSupportUnitTests.java @@ -17,10 +17,15 @@ package org.springframework.data.gemfire.support; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatIllegalStateException; import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoInteractions; +import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.when; import static org.springframework.data.gemfire.support.GemfireBeanFactoryLocator.newBeanFactoryLocator; @@ -30,6 +35,11 @@ import org.junit.After; import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; + +import org.apache.geode.cache.Cache; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; @@ -42,14 +52,16 @@ * Unit Tests for {@link LazyWiringDeclarableSupport}. * * @author John Blum - * @see org.junit.Rule + * @see java.util.Properties * @see org.junit.Test * @see org.mockito.Mockito + * @see org.mockito.junit.MockitoJUnitRunner * @see org.springframework.beans.factory.BeanFactory * @see org.springframework.data.gemfire.support.GemfireBeanFactoryLocator * @see org.springframework.data.gemfire.support.LazyWiringDeclarableSupport * @since 1.3.4 */ +@RunWith(MockitoJUnitRunner.class) public class LazyWiringDeclarableSupportUnitTests { private static void assertParameters(Properties parameters, String expectedKey, String expectedValue) { @@ -63,56 +75,54 @@ private static Properties createParameters(String parameter, String value) { return PropertiesBuilder.create().setProperty(parameter, value).build(); } + @Mock + private Cache mockCache; + @After public void tearDown() { SpringContextBootstrappingInitializer.destroy(); + verifyNoInteractions(this.mockCache); } @Test public void assertInitialized() { - LazyWiringDeclarableSupport declarable = new TestLazyWiringDeclarableSupport() { + LazyWiringDeclarableSupport declarable = spy(new TestLazyWiringDeclarableSupport()); - @Override - protected boolean isInitialized() { - return true; - } - }; + doReturn(true).when(declarable).isInitialized(); try { declarable.assertInitialized(); } finally { SpringContextBootstrappingInitializer.unregister(declarable); + + verify(declarable, times(1)).assertInitialized(); + verify(declarable, times(1)).isInitialized(); + verifyNoMoreInteractions(declarable); } } - @Test(expected = IllegalStateException.class) + @Test public void assertInitializedWhenUninitialized() { - LazyWiringDeclarableSupport declarable = new TestLazyWiringDeclarableSupport() { + LazyWiringDeclarableSupport declarable = spy(new TestLazyWiringDeclarableSupport()); - @Override - protected boolean isInitialized() { - return false; - } - }; + doReturn(false).when(declarable).isInitialized(); try { - declarable.assertInitialized(); - } - catch (IllegalStateException expected) { - - assertThat(expected) - .hasMessage("This Declarable object [%s] has not been properly configured and initialized", - declarable.getClass().getName()); - - assertThat(expected).hasNoCause(); - - throw expected; + assertThatIllegalStateException() + .isThrownBy(() -> declarable.assertInitialized()) + .withMessage("This Declarable object [%s] has not been properly configured and initialized", + declarable.getClass().getName()) + .withNoCause(); } finally { SpringContextBootstrappingInitializer.unregister(declarable); + + verify(declarable, times(1)).assertInitialized(); + verify(declarable, times(1)).isInitialized(); + verifyNoMoreInteractions(declarable); } } @@ -129,48 +139,43 @@ public void assertUninitialized() { } } - @Test(expected = IllegalStateException.class) + @Test public void assertUninitializedWhenInitialized() { - LazyWiringDeclarableSupport declarable = new TestLazyWiringDeclarableSupport() { + LazyWiringDeclarableSupport declarable = spy(new TestLazyWiringDeclarableSupport()); - @Override - protected boolean isInitialized() { - return true; - } - }; + doReturn(true).when(declarable).isInitialized(); try { - declarable.assertUninitialized(); - } - catch (IllegalStateException expected) { - - assertThat(expected) - .hasMessage("This Declarable object [%s] has already been configured and initialized", - declarable.getClass().getName()); - - assertThat(expected).hasNoCause(); - - throw expected; + assertThatIllegalStateException() + .isThrownBy(() -> declarable.assertUninitialized()) + .withMessage("This Declarable object [%s] has already been configured and initialized", + declarable.getClass().getName()) + .withNoCause(); } finally { SpringContextBootstrappingInitializer.unregister(declarable); + + verify(declarable, times(1)).assertUninitialized(); + verify(declarable, times(1)).isNotInitialized(); + verify(declarable, times(1)).isInitialized(); + verifyNoMoreInteractions(declarable); } } @Test - public void init() { + public void initialize() { LazyWiringDeclarableSupport declarable = new TestLazyWiringDeclarableSupport(); try { assertThat(declarable.isInitialized()).isFalse(); - declarable.init(createParameters("param", "value")); + declarable.initialize(this.mockCache, createParameters("param", "value")); assertParameters(declarable.nullSafeGetParameters(), "param", "value"); - declarable.init(createParameters("newParam", "newValue")); + declarable.initialize(this.mockCache, createParameters("newParam", "newValue")); assertParameters(declarable.nullSafeGetParameters(), "newParam", "newValue"); assertThat(declarable.isInitialized()).isFalse(); @@ -216,7 +221,7 @@ public void nullSafeGetParametersWithNullReference() { LazyWiringDeclarableSupport declarable = new TestLazyWiringDeclarableSupport(); try { - declarable.init(null); + declarable.initialize(this.mockCache, null); Properties parameters = declarable.nullSafeGetParameters(); @@ -252,7 +257,7 @@ protected void doPostInit(final Properties parameters) { Properties parameters = createParameters("param", "value"); try { - declarable.init(parameters); + declarable.initialize(this.mockCache, parameters); declarable.onApplicationEvent(new ContextRefreshedEvent(mockApplicationContext)); declarable.assertBeanFactory(mockBeanFactory); declarable.assertParameters(parameters); @@ -323,7 +328,7 @@ protected void doPostInit(final Properties parameters) { Properties parameters = createParameters("param", "value"); try { - declarable.init(parameters); + declarable.initialize(this.mockCache, parameters); assertThat(declarable.isInitialized()).isFalse(); assertThat(declarable.nullSafeGetParameters()).isSameAs(parameters); @@ -357,7 +362,7 @@ protected void doPostInit(final Properties parameters) { } @Test - public void initThenOnApplicationEventThenInitWhenInitialized() { + public void initializeThenOnApplicationEventThenInitializedWhenAlreadyInitialized() { BeanFactory mockBeanFactory = mock(BeanFactory.class); @@ -395,7 +400,7 @@ protected void doPostInit(final Properties parameters) { assertThat(declarable.nullSafeGetParameters()).isNotSameAs(parameters); assertThat(doPostInitCalled.get()).isFalse(); - declarable.init(parameters); + declarable.initialize(this.mockCache, parameters); declarable.assertBeanFactory(mockBeanFactory); declarable.assertParameters(parameters); @@ -417,7 +422,7 @@ protected void doPostInit(final Properties parameters) { expectedValue.set("mockValue"); parameters = createParameters("mockKey", "mockValue"); - declarable.init(parameters); + declarable.initialize(this.mockCache, parameters); declarable.assertBeanFactory(mockBeanFactory); declarable.assertParameters(parameters); diff --git a/spring-data-geode/src/test/resources/shiro.properties b/spring-data-geode/src/test/resources/shiro.properties index 15b582c3b..097cc75c2 100644 --- a/spring-data-geode/src/test/resources/shiro.properties +++ b/spring-data-geode/src/test/resources/shiro.properties @@ -17,6 +17,7 @@ # Apache Geode System Users and assigned Roles user.root = s3c3rt!, ADMIN, DBA +user.dba = g01dD!gg3r4$, DBA user.scientist = w0rk!ng4u, DATA_SCIENTIST user.analyst = p@55w0rd, DATA_ANALYST user.guest = guest, GUEST