Enable Locator applications bootstrapped with SDG to be configured with Security (Auth) using @EnableSecurity.
Closes #621.
This commit is contained in:
@@ -122,9 +122,17 @@ public class ApacheShiroSecurityConfiguration extends AbstractAnnotationConfigSu
|
||||
@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 @@ public class ApacheShiroSecurityConfiguration extends AbstractAnnotationConfigSu
|
||||
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);
|
||||
|
||||
@@ -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<? extends Annotation> 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<String, String> 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<String, String> {
|
||||
|
||||
public static @NonNull SpringDataGeodeAuthentication from(@NonNull Supplier<String> username,
|
||||
@NonNull Supplier<String> password) {
|
||||
|
||||
return new SpringDataGeodeAuthentication(username, password);
|
||||
}
|
||||
|
||||
private final Supplier<String> username;
|
||||
private final Supplier<String> password;
|
||||
|
||||
protected SpringDataGeodeAuthentication(@NonNull Supplier<String> username, @NonNull Supplier<String> password) {
|
||||
this.username = require(username, "Username [%s] is required", username);
|
||||
this.password = require(password, "Password [%s] is required", password);
|
||||
}
|
||||
|
||||
private <T> 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -22,113 +22,152 @@ import java.net.URI;
|
||||
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<String, String> authentication) {
|
||||
|
||||
Authenticator authenticator = new Authenticator() {
|
||||
return Optional.ofNullable(authentication)
|
||||
.filter(Authentication::isRequested)
|
||||
.map(this::newAuthenticator)
|
||||
.map(this::registerAuthenticator)
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
private @NonNull Authenticator newAuthenticator(@NonNull Authentication<String, String> authentication) {
|
||||
|
||||
Assert.notNull(authentication, "Authentication must not be null");
|
||||
Assert.state(authentication.isRequested(), "Authentication was not requested");
|
||||
|
||||
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 @@ public class AutoConfiguredAuthenticationConfiguration {
|
||||
}
|
||||
|
||||
@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 @@ public class AutoConfiguredAuthenticationConfiguration {
|
||||
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 @@ public class AutoConfiguredAuthenticationConfiguration {
|
||||
}
|
||||
|
||||
@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<String, String> 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<String, String> authentication) {
|
||||
|
||||
return (beanName, locatorFactoryBean) ->
|
||||
initializeMemberAuthentication(locatorFactoryBean.getGemFireProperties(), authentication);
|
||||
}
|
||||
|
||||
private void setAuthenticationCredentials(Properties gemfireProperties, Environment environment) {
|
||||
@Bean
|
||||
public PeerCacheConfigurer authenticationInitializingPeerCacheConfigurer(
|
||||
@Autowired(required = false) @Lazy Authentication<String, String> authentication) {
|
||||
|
||||
return (beanName, cacheFactoryBean) ->
|
||||
initializeMemberAuthentication(cacheFactoryBean.getProperties(), authentication);
|
||||
}
|
||||
|
||||
private void initializeMemberAuthentication(Properties gemfireProperties,
|
||||
@Nullable Authentication<String, String> 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 String SPRING_DATA_GEMFIRE_SECURITY_AUTH_ENABLED =
|
||||
"spring.data.gemfire.security.auth.auto-configure.enabled";
|
||||
public static final boolean DEFAULT_ENABLED = true;
|
||||
|
||||
private static boolean isEnabled(Environment environment) {
|
||||
return environment.getProperty(SPRING_DATA_GEMFIRE_SECURITY_AUTH_ENABLED, Boolean.class, true);
|
||||
public static final String SECURITY_AUTH_AUTO_CONFIGURATION_ENABLED =
|
||||
"spring.data.gemfire.security.auth.auto-configuration-enabled";
|
||||
|
||||
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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,6 +40,8 @@ import org.springframework.context.annotation.Import;
|
||||
* @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 @@ import org.springframework.context.annotation.Import;
|
||||
@Documented
|
||||
@Import({
|
||||
ApacheShiroSecurityConfiguration.class,
|
||||
AuthenticationBeanConfiguration.class,
|
||||
AutoConfiguredAuthenticationConfiguration.class,
|
||||
GeodeIntegratedSecurityConfiguration.class
|
||||
})
|
||||
|
||||
@@ -20,6 +20,7 @@ import java.lang.annotation.Annotation;
|
||||
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 @@ import org.springframework.data.gemfire.util.PropertiesBuilder;
|
||||
@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 @@ public class GeodeIntegratedSecurityConfiguration extends EmbeddedServiceConfigu
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 @@ public class GeodeIntegratedSecurityConfiguration extends EmbeddedServiceConfigu
|
||||
}
|
||||
|
||||
/**
|
||||
* 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() {
|
||||
|
||||
@@ -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.apache.geode.security.AuthenticationFailedException;
|
||||
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 @@ import org.springframework.data.gemfire.support.WiringDeclarableSupport;
|
||||
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<Environment> 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 abstract class AbstractAuthInitialize extends WiringDeclarableSupport
|
||||
|
||||
protected abstract Properties doGetCredentials(Properties properties);
|
||||
|
||||
@Override
|
||||
public void close() { }
|
||||
|
||||
}
|
||||
|
||||
@@ -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 <PRINCIPAL> {@link Class type} modeling the {@literal principal} object.
|
||||
* @param <CREDENTIALS> {@link Class type} modeling the {@literal credentials} object.
|
||||
* @see java.lang.FunctionalInterface
|
||||
* @since 3.0.0
|
||||
*/
|
||||
@FunctionalInterface
|
||||
@SuppressWarnings("unused")
|
||||
public interface Authentication<PRINCIPAL, CREDENTIALS> {
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
@@ -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<String, String> 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 class AutoConfiguredAuthenticationInitializer extends AbstractAuthInitial
|
||||
AutoConfiguredAuthenticationInitializer authenticationInitializer =
|
||||
new AutoConfiguredAuthenticationInitializer();
|
||||
|
||||
authenticationInitializer.init(NO_PARAMETERS);
|
||||
authenticationInitializer.initialize(GemfireUtils.getCache(), NO_PARAMETERS);
|
||||
|
||||
return authenticationInitializer;
|
||||
}
|
||||
|
||||
@Autowired(required = false)
|
||||
public void setAuthentication(@Nullable Authentication<String, String> authentication) {
|
||||
this.authentication = authentication;
|
||||
}
|
||||
|
||||
protected Optional<Authentication<String, String>> getAuthentication() {
|
||||
return Optional.ofNullable(this.authentication);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Properties doGetCredentials(Properties properties) {
|
||||
|
||||
getEnvironment()
|
||||
.filter(environment -> StringUtils.hasText(environment.getProperty(SDG_SECURITY_USERNAME_PROPERTY)))
|
||||
.ifPresent(environment -> {
|
||||
|
||||
String securityUsername = environment.getProperty(SDG_SECURITY_USERNAME_PROPERTY);
|
||||
String securityPassword = environment.getProperty(SDG_SECURITY_PASSWORD_PROPERTY);
|
||||
|
||||
properties.setProperty(SECURITY_USERNAME_PROPERTY, securityUsername);
|
||||
properties.setProperty(SECURITY_PASSWORD_PROPERTY, securityPassword);
|
||||
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;
|
||||
|
||||
@@ -25,19 +25,21 @@ import org.springframework.beans.factory.BeanFactory;
|
||||
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 @@ public abstract class DeclarableSupport implements CacheCallback, Declarable {
|
||||
return newBeanFactoryLocator().useBeanFactory(beanFactoryKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
@Override
|
||||
public void close() { }
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@ package org.springframework.data.gemfire.support;
|
||||
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.ApplicationContext;
|
||||
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 @@ import org.springframework.util.Assert;
|
||||
public abstract class LazyWiringDeclarableSupport extends WiringDeclarableSupport
|
||||
implements ApplicationListener<ContextRefreshedEvent>, 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<Properties> parametersReference = new AtomicReference<>();
|
||||
|
||||
// condition to determine the initialized state of this Declarable object
|
||||
@@ -155,16 +158,14 @@ public abstract class LazyWiringDeclarableSupport extends WiringDeclarableSuppor
|
||||
* @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 abstract class LazyWiringDeclarableSupport extends WiringDeclarableSuppor
|
||||
* @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 @@ public abstract class LazyWiringDeclarableSupport extends WiringDeclarableSuppor
|
||||
* @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 @@ public abstract class LazyWiringDeclarableSupport extends WiringDeclarableSuppor
|
||||
* (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 @@ public abstract class LazyWiringDeclarableSupport extends WiringDeclarableSuppor
|
||||
* 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 @@ public abstract class LazyWiringDeclarableSupport extends WiringDeclarableSuppor
|
||||
*/
|
||||
@Override
|
||||
@SuppressWarnings("all")
|
||||
public final void onApplicationEvent(ContextRefreshedEvent event) {
|
||||
public final void onApplicationEvent(@NonNull ContextRefreshedEvent event) {
|
||||
|
||||
ApplicationContext applicationContext = event.getApplicationContext();
|
||||
|
||||
|
||||
@@ -18,11 +18,14 @@ package org.springframework.data.gemfire.support;
|
||||
|
||||
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 @@ public abstract class WiringDeclarableSupport extends DeclarableSupport {
|
||||
}
|
||||
|
||||
/**
|
||||
* 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();
|
||||
|
||||
|
||||
@@ -64,10 +64,12 @@ import org.springframework.util.StringUtils;
|
||||
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 @@ public abstract class AbstractGeodeSecurityIntegrationTests extends ForkingClien
|
||||
|
||||
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 @@ public abstract class AbstractGeodeSecurityIntegrationTests extends ForkingClien
|
||||
ClientRegionFactoryBean<String, String> echoRegion = new ClientRegionFactoryBean<>();
|
||||
|
||||
echoRegion.setCache(gemfireCache);
|
||||
echoRegion.setClose(false);
|
||||
echoRegion.setShortcut(ClientRegionShortcut.PROXY);
|
||||
|
||||
return echoRegion;
|
||||
@@ -277,8 +278,10 @@ public abstract class AbstractGeodeSecurityIntegrationTests extends ForkingClien
|
||||
|
||||
private final Set<Role> 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 abstract class AbstractGeodeSecurityIntegrationTests extends ForkingClien
|
||||
return this.roles.contains(role);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
@Override
|
||||
public Iterator<Role> 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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,91 +19,65 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
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<Object, Object> 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.<String, String>get("Hello")).isEqualTo("Hello");
|
||||
assertThat(this.echoTemplate.<String, String>get("TEST")).isEqualTo("TEST");
|
||||
assertThat(this.echoTemplate.<String, String>get("Good-Bye")).isEqualTo("Good-Bye");
|
||||
}
|
||||
|
||||
@ClientCacheApplication
|
||||
@EnableSecurity
|
||||
@EnableSecurity(securityUsername = SECURITY_USERNAME, securityPassword = SECURITY_PASSWORD)
|
||||
static class TestGemFireClientConfiguration {
|
||||
|
||||
@Bean("Echo")
|
||||
@@ -112,15 +86,19 @@ public class AutoConfiguredAuthenticationConfigurationIntegrationTests
|
||||
ClientRegionFactoryBean<Object, Object> 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 @@ public class AutoConfiguredAuthenticationConfigurationIntegrationTests
|
||||
|
||||
echoRegion.setCache(gemfireCache);
|
||||
echoRegion.setCacheLoader(newEchoCacheLoader());
|
||||
echoRegion.setClose(false);
|
||||
echoRegion.setPersistent(false);
|
||||
|
||||
return echoRegion;
|
||||
@@ -142,7 +119,7 @@ public class AutoConfiguredAuthenticationConfigurationIntegrationTests
|
||||
|
||||
private CacheLoader<Object, Object> newEchoCacheLoader() {
|
||||
|
||||
return new CacheLoader<Object, Object>() {
|
||||
return new CacheLoader<>() {
|
||||
|
||||
@Override
|
||||
public Object load(LoaderHelper<Object, Object> loaderHelper) throws CacheLoaderException {
|
||||
@@ -150,8 +127,8 @@ public class AutoConfiguredAuthenticationConfigurationIntegrationTests
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
}
|
||||
public void close() { }
|
||||
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<String, Object> annotationAttributes = MapBuilder.<String, Object>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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -29,6 +29,7 @@ import org.apache.geode.distributed.DistributedSystem;
|
||||
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 class LocatorApplicationIntegrationTests extends IntegrationTestsSupport
|
||||
|
||||
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();
|
||||
|
||||
@@ -84,8 +84,8 @@ public class SecureLocatorApplicationIntegrationTests extends IntegrationTestsSu
|
||||
}
|
||||
|
||||
@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 {
|
||||
|
||||
@@ -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 { }
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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.ConcurrentHashMap;
|
||||
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<String, String> authorizedUsers;
|
||||
|
||||
@@ -56,7 +56,7 @@ public final class TestSecurityManager implements org.apache.geode.security.Secu
|
||||
this.authorizedUsers.putIfAbsent(SECURITY_USERNAME, SECURITY_PASSWORD);
|
||||
}
|
||||
|
||||
protected Map<String, String> getAuthorizedUsers() {
|
||||
private Map<String, String> getAuthorizedUsers() {
|
||||
return Collections.unmodifiableMap(this.authorizedUsers);
|
||||
}
|
||||
|
||||
@@ -71,7 +71,7 @@ public final class TestSecurityManager implements org.apache.geode.security.Secu
|
||||
}
|
||||
|
||||
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 final class TestSecurityManager implements org.apache.geode.security.Secu
|
||||
}
|
||||
|
||||
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"));
|
||||
}
|
||||
|
||||
|
||||
@@ -109,7 +109,7 @@ public class UsingAnnotationConfigWithBeanDefinitionOverridingDisabledIntegratio
|
||||
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");
|
||||
|
||||
@@ -27,11 +27,14 @@ import org.junit.AfterClass;
|
||||
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 @@ import org.springframework.util.Assert;
|
||||
* 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 class LazyWiringDeclarableSupportIntegrationTests extends IntegrationTest
|
||||
@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 class LazyWiringDeclarableSupportIntegrationTests extends IntegrationTest
|
||||
|
||||
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 class LazyWiringDeclarableSupportIntegrationTests extends IntegrationTest
|
||||
|
||||
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) {
|
||||
|
||||
@@ -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 java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
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 @@ import org.springframework.data.gemfire.util.PropertiesBuilder;
|
||||
* 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 @@ public class LazyWiringDeclarableSupportUnitTests {
|
||||
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 class LazyWiringDeclarableSupportUnitTests {
|
||||
}
|
||||
}
|
||||
|
||||
@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 class LazyWiringDeclarableSupportUnitTests {
|
||||
LazyWiringDeclarableSupport declarable = new TestLazyWiringDeclarableSupport();
|
||||
|
||||
try {
|
||||
declarable.init(null);
|
||||
declarable.initialize(this.mockCache, null);
|
||||
|
||||
Properties parameters = declarable.nullSafeGetParameters();
|
||||
|
||||
@@ -252,7 +257,7 @@ public class LazyWiringDeclarableSupportUnitTests {
|
||||
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 @@ public class LazyWiringDeclarableSupportUnitTests {
|
||||
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 @@ public class LazyWiringDeclarableSupportUnitTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void initThenOnApplicationEventThenInitWhenInitialized() {
|
||||
public void initializeThenOnApplicationEventThenInitializedWhenAlreadyInitialized() {
|
||||
|
||||
BeanFactory mockBeanFactory = mock(BeanFactory.class);
|
||||
|
||||
@@ -395,7 +400,7 @@ public class LazyWiringDeclarableSupportUnitTests {
|
||||
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 @@ public class LazyWiringDeclarableSupportUnitTests {
|
||||
expectedValue.set("mockValue");
|
||||
parameters = createParameters("mockKey", "mockValue");
|
||||
|
||||
declarable.init(parameters);
|
||||
declarable.initialize(this.mockCache, parameters);
|
||||
declarable.assertBeanFactory(mockBeanFactory);
|
||||
declarable.assertParameters(parameters);
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user