diff --git a/spring-geode-autoconfigure/src/main/java/org/springframework/geode/boot/autoconfigure/ClientSecurityAutoConfiguration.java b/spring-geode-autoconfigure/src/main/java/org/springframework/geode/boot/autoconfigure/ClientSecurityAutoConfiguration.java index 6a07965e..19119480 100644 --- a/spring-geode-autoconfigure/src/main/java/org/springframework/geode/boot/autoconfigure/ClientSecurityAutoConfiguration.java +++ b/spring-geode-autoconfigure/src/main/java/org/springframework/geode/boot/autoconfigure/ClientSecurityAutoConfiguration.java @@ -36,6 +36,7 @@ import org.springframework.context.annotation.Configuration; import org.springframework.core.env.ConfigurableEnvironment; import org.springframework.core.env.Environment; import org.springframework.core.env.PropertiesPropertySource; +import org.springframework.core.env.PropertySource; import org.springframework.data.gemfire.client.ClientCacheFactoryBean; import org.springframework.data.gemfire.config.annotation.EnableSecurity; import org.springframework.data.gemfire.config.annotation.support.AutoConfiguredAuthenticationInitializer; @@ -77,8 +78,8 @@ import org.springframework.geode.core.env.support.Service; @SuppressWarnings("unused") public class ClientSecurityAutoConfiguration { - public static final String SECURITY_CLOUD_ENVIRONMENT_POST_PROCESSOR_DISABLED_PROPERTY = - "spring.boot.data.gemfire.security.auth.environment.post-processor.disabled"; + public static final String SECURITY_CLOUD_ENVIRONMENT_POST_PROCESSOR_ENABLED_PROPERTY = + "spring.boot.data.gemfire.security.auth.environment.post-processor.enabled"; private static final String CLOUD_CACHE_PROPERTY_SOURCE_NAME = "cloudcache-configuration"; @@ -96,7 +97,7 @@ public class ClientSecurityAutoConfiguration { private static final String VCAP_PROPERTY_SOURCE_NAME = "vcap"; - static class AutoConfiguredCloudSecurityEnvironmentPostProcessor implements EnvironmentPostProcessor { + public static class AutoConfiguredCloudSecurityEnvironmentPostProcessor implements EnvironmentPostProcessor { @Override public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) { @@ -104,33 +105,16 @@ public class ClientSecurityAutoConfiguration { Optional.of(environment) .filter(this::isEnabled) .filter(this::isCloudFoundryEnvironment) - .ifPresent(env -> { - - VcapPropertySource propertySource = VcapPropertySource.from(env); - - Properties cloudCacheProperties = new Properties(); - - CloudCacheService cloudCache = propertySource.findFirstCloudCacheService(); - - configureAuthentication(env, cloudCacheProperties, propertySource, cloudCache); - configureLocators(env, cloudCacheProperties, propertySource, cloudCache); - configureManagementRestApiAccess(env, cloudCacheProperties, propertySource, cloudCache); - - environment.getPropertySources() - .addFirst(new PropertiesPropertySource(CLOUD_CACHE_PROPERTY_SOURCE_NAME, cloudCacheProperties)); - }); + .ifPresent(this::configureSecurityContext); } private boolean isCloudFoundryEnvironment(Environment environment) { return Optional.ofNullable(environment).filter(CloudPlatform.CLOUD_FOUNDRY::isActive).isPresent(); } - private boolean isDisabled(Environment environment) { - return Boolean.getBoolean(SECURITY_CLOUD_ENVIRONMENT_POST_PROCESSOR_DISABLED_PROPERTY); - } - private boolean isEnabled(Environment environment) { - return !isDisabled(environment); + return environment.getProperty(SECURITY_CLOUD_ENVIRONMENT_POST_PROCESSOR_ENABLED_PROPERTY, + Boolean.class, true); } private boolean isSecurityPropertiesSet(Environment environment) { @@ -170,6 +154,26 @@ public class ClientSecurityAutoConfiguration { cloudCacheProperties.setProperty(MANAGEMENT_HTTP_PORT_PROPERTY, String.valueOf(url.getPort())); }); } + + public void configureSecurityContext(ConfigurableEnvironment environment) { + + VcapPropertySource propertySource = VcapPropertySource.from(environment); + + Properties cloudCacheProperties = new Properties(); + + CloudCacheService cloudCache = propertySource.findFirstCloudCacheService(); + + configureAuthentication(environment, cloudCacheProperties, propertySource, cloudCache); + configureLocators(environment, cloudCacheProperties, propertySource, cloudCache); + configureManagementRestApiAccess(environment, cloudCacheProperties, propertySource, cloudCache); + + environment.getPropertySources() + .addFirst(newPropertySource(CLOUD_CACHE_PROPERTY_SOURCE_NAME, cloudCacheProperties)); + } + + private PropertySource newPropertySource(String name, Properties properties) { + return new PropertiesPropertySource(name, properties); + } } static class EnableSecurityCondition extends AnyNestedCondition { diff --git a/spring-geode-autoconfigure/src/test/java/org/springframework/geode/boot/autoconfigure/security/auth/ClientSecurityAutoConfigurationUnitTests.java b/spring-geode-autoconfigure/src/test/java/org/springframework/geode/boot/autoconfigure/security/auth/ClientSecurityAutoConfigurationUnitTests.java new file mode 100644 index 00000000..d6360d7e --- /dev/null +++ b/spring-geode-autoconfigure/src/test/java/org/springframework/geode/boot/autoconfigure/security/auth/ClientSecurityAutoConfigurationUnitTests.java @@ -0,0 +1,155 @@ +/* + * Copyright 2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package org.springframework.geode.boot.autoconfigure.security.auth; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import org.junit.Test; +import org.springframework.core.env.ConfigurableEnvironment; +import org.springframework.core.env.StandardEnvironment; +import org.springframework.geode.boot.autoconfigure.ClientSecurityAutoConfiguration; +import org.springframework.geode.boot.autoconfigure.ClientSecurityAutoConfiguration.AutoConfiguredCloudSecurityEnvironmentPostProcessor; + +/** + * Unit Tests for {@link ClientSecurityAutoConfiguration}. + * + * @author John Blum + * @see org.junit.Test + * @see org.mockito.Mockito + * @see org.springframework.core.env.ConfigurableEnvironment + * @see org.springframework.geode.boot.autoconfigure.ClientSecurityAutoConfiguration + * @since 1.0.0 + */ +public class ClientSecurityAutoConfigurationUnitTests { + + @Test + public void clientSecurityIsEnabledWhenEnablePropertyIsTrueAndCloudFoundryIsActive() { + + AutoConfiguredCloudSecurityEnvironmentPostProcessor environmentPostProcessor = + spy(new AutoConfiguredCloudSecurityEnvironmentPostProcessor()); + + doNothing().when(environmentPostProcessor).configureSecurityContext(any(ConfigurableEnvironment.class)); + + ConfigurableEnvironment mockEnvironment = mock(ConfigurableEnvironment.class); + + when(mockEnvironment.getProperty(eq(ClientSecurityAutoConfiguration.SECURITY_CLOUD_ENVIRONMENT_POST_PROCESSOR_ENABLED_PROPERTY), + eq(Boolean.class), eq(true))).thenReturn(true); + + when(mockEnvironment.containsProperty(eq("VCAP_APPLICATION"))).thenReturn(true); + + environmentPostProcessor.postProcessEnvironment(mockEnvironment, null); + + verify(mockEnvironment, times(1)) + .getProperty(eq(ClientSecurityAutoConfiguration.SECURITY_CLOUD_ENVIRONMENT_POST_PROCESSOR_ENABLED_PROPERTY), + eq(Boolean.class), eq(true)); + + verify(mockEnvironment, times(1)).containsProperty(eq("VCAP_APPLICATION")); + + verify(mockEnvironment, never()).containsProperty(eq("VCAP_SERVICES")); + + verify(environmentPostProcessor, times(1)) + .configureSecurityContext(eq(mockEnvironment)); + } + + @Test + public void clientSecurityIsEnabledWhenEnablePropertyIsUnsetAndCloudFoundryIsActive() { + + AutoConfiguredCloudSecurityEnvironmentPostProcessor environmentPostProcessor = + spy(new AutoConfiguredCloudSecurityEnvironmentPostProcessor()); + + doNothing().when(environmentPostProcessor).configureSecurityContext(any(ConfigurableEnvironment.class)); + + ConfigurableEnvironment environment = spy(new StandardEnvironment()); + + doReturn(true).when(environment).containsProperty(eq("VCAP_SERVICES")); + + environmentPostProcessor.postProcessEnvironment(environment, null); + + verify(environment, times(1)) + .getProperty(eq(ClientSecurityAutoConfiguration.SECURITY_CLOUD_ENVIRONMENT_POST_PROCESSOR_ENABLED_PROPERTY), + eq(Boolean.class), eq(true)); + + verify(environment, times(1)).containsProperty(eq("VCAP_APPLICATION")); + verify(environment, times(1)).containsProperty(eq("VCAP_SERVICES")); + + verify(environmentPostProcessor, times(1)) + .configureSecurityContext(eq(environment)); + } + + @Test + public void clientSecurityIsDisabledWhenEnablePropertyIsFalseAndCloudFoundryIsActive() { + + AutoConfiguredCloudSecurityEnvironmentPostProcessor environmentPostProcessor = + spy(new AutoConfiguredCloudSecurityEnvironmentPostProcessor()); + + doNothing().when(environmentPostProcessor).configureSecurityContext(any(ConfigurableEnvironment.class)); + + ConfigurableEnvironment mockEnvironment = mock(ConfigurableEnvironment.class); + + when(mockEnvironment.getProperty(eq(ClientSecurityAutoConfiguration.SECURITY_CLOUD_ENVIRONMENT_POST_PROCESSOR_ENABLED_PROPERTY), + eq(Boolean.class), eq(true))).thenReturn(false); + + when(mockEnvironment.containsProperty(eq("VCAP_APPLICATION"))).thenReturn(true); + when(mockEnvironment.containsProperty(eq("VCAP_SERVICES"))).thenReturn(true); + + environmentPostProcessor.postProcessEnvironment(mockEnvironment, null); + + verify(mockEnvironment, times(1)) + .getProperty(eq(ClientSecurityAutoConfiguration.SECURITY_CLOUD_ENVIRONMENT_POST_PROCESSOR_ENABLED_PROPERTY), + eq(Boolean.class), eq(true)); + + verify(mockEnvironment, never()).containsProperty(eq("VCAP_APPLICATION")); + verify(mockEnvironment, never()).containsProperty(eq("VCAP_SERVICES")); + verify(environmentPostProcessor, never()).configureSecurityContext(eq(mockEnvironment)); + } + + @Test + public void clientSecurityIsDisabledWhenEnablePropertyIsTrueAndCloudFoundryIsInactive() { + + AutoConfiguredCloudSecurityEnvironmentPostProcessor environmentPostProcessor = + spy(new AutoConfiguredCloudSecurityEnvironmentPostProcessor()); + + doNothing().when(environmentPostProcessor).configureSecurityContext(any(ConfigurableEnvironment.class)); + + ConfigurableEnvironment mockEnvironment = mock(ConfigurableEnvironment.class); + + when(mockEnvironment.getProperty(eq(ClientSecurityAutoConfiguration.SECURITY_CLOUD_ENVIRONMENT_POST_PROCESSOR_ENABLED_PROPERTY), + eq(Boolean.class), eq(true))).thenReturn(true); + + when(mockEnvironment.containsProperty(eq("VCAP_APPLICATION"))).thenReturn(false); + when(mockEnvironment.containsProperty(eq("VCAP_SERVICES"))).thenReturn(false); + + environmentPostProcessor.postProcessEnvironment(mockEnvironment, null); + + verify(mockEnvironment, times(1)) + .getProperty(eq(ClientSecurityAutoConfiguration.SECURITY_CLOUD_ENVIRONMENT_POST_PROCESSOR_ENABLED_PROPERTY), + eq(Boolean.class), eq(true)); + + verify(mockEnvironment, times(1)).containsProperty(eq("VCAP_APPLICATION")); + verify(mockEnvironment, times(1)).containsProperty(eq("VCAP_SERVICES")); + verify(environmentPostProcessor, never()).configureSecurityContext(eq(mockEnvironment)); + } +}