DATAGEODE-24 - Enhance @EnableSecurity to provide a default implementation of the Geode AuthInitialize interface.
This commit is contained in:
@@ -0,0 +1,172 @@
|
||||
/*
|
||||
* Copyright 2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.data.gemfire.config.annotation;
|
||||
|
||||
import 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 java.util.Optional;
|
||||
|
||||
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.junit.After;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.core.env.MutablePropertySources;
|
||||
import org.springframework.core.env.PropertySource;
|
||||
import org.springframework.data.gemfire.LocalRegionFactoryBean;
|
||||
import org.springframework.data.gemfire.client.ClientRegionFactoryBean;
|
||||
import org.springframework.data.gemfire.process.ProcessWrapper;
|
||||
import org.springframework.data.gemfire.test.support.ClientServerIntegrationTestsSupport;
|
||||
import org.springframework.mock.env.MockPropertySource;
|
||||
|
||||
/**
|
||||
* The AutoConfiguredAuthenticationConfigurationIntegrationTests class...
|
||||
*
|
||||
* @author John Blum
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class AutoConfiguredAuthenticationConfigurationIntegrationTests extends ClientServerIntegrationTestsSupport {
|
||||
|
||||
private static final int PORT = 42124;
|
||||
|
||||
private static ProcessWrapper gemfireServerProcess;
|
||||
|
||||
private ConfigurableApplicationContext applicationContext;
|
||||
|
||||
@BeforeClass
|
||||
public static void setupGemFireServer() throws Exception {
|
||||
|
||||
gemfireServerProcess = run(TestGemFireServerConfiguration.class, String.format("-Dgemfire.name=%1$s",
|
||||
asApplicationName(AutoConfiguredAuthenticationConfigurationIntegrationTests.class)));
|
||||
|
||||
waitForServerToStart("localhost", PORT);
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void tearDownGemFireServer() {
|
||||
stop(gemfireServerProcess);
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
Optional.ofNullable(this.applicationContext).ifPresent(ConfigurableApplicationContext::close);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore
|
||||
@SuppressWarnings("unchecked")
|
||||
public void clientAuthenticatedWithServer() {
|
||||
|
||||
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("TEST")).isEqualTo("TEST");
|
||||
}
|
||||
|
||||
@EnableSecurity
|
||||
@ClientCacheApplication(servers = @ClientCacheApplication.Server(port = PORT))
|
||||
static class TestGemFireClientConfiguration {
|
||||
|
||||
@Bean("Echo")
|
||||
ClientRegionFactoryBean<Object, Object> echoRegion(GemFireCache gemfireCache) {
|
||||
|
||||
ClientRegionFactoryBean<Object, Object> echoRegion = new ClientRegionFactoryBean<>();
|
||||
|
||||
echoRegion.setCache(gemfireCache);
|
||||
echoRegion.setClose(false);
|
||||
echoRegion.setShortcut(ClientRegionShortcut.PROXY);
|
||||
|
||||
return echoRegion;
|
||||
}
|
||||
}
|
||||
|
||||
@CacheServerApplication(port = PORT)
|
||||
@EnableSecurity(securityManagerClassName = "org.springframework.data.gemfire.config.annotation.TestSecurityManager")
|
||||
static class TestGemFireServerConfiguration {
|
||||
|
||||
public static void main(String[] args) {
|
||||
|
||||
ConfigurableApplicationContext applicationContext =
|
||||
new AnnotationConfigApplicationContext(TestGemFireServerConfiguration.class);
|
||||
|
||||
applicationContext.registerShutdownHook();
|
||||
}
|
||||
|
||||
@Bean("Echo")
|
||||
LocalRegionFactoryBean<Object, Object> echoRegion(GemFireCache gemfireCache) {
|
||||
|
||||
LocalRegionFactoryBean<Object, Object> echoRegion = new LocalRegionFactoryBean<>();
|
||||
|
||||
echoRegion.setCache(gemfireCache);
|
||||
echoRegion.setCacheLoader(newEchoCacheLoader());
|
||||
echoRegion.setClose(false);
|
||||
echoRegion.setPersistent(false);
|
||||
|
||||
return echoRegion;
|
||||
}
|
||||
|
||||
private CacheLoader<Object, Object> newEchoCacheLoader() {
|
||||
|
||||
return new CacheLoader<Object, Object>() {
|
||||
|
||||
@Override
|
||||
public Object load(LoaderHelper<Object, Object> loaderHelper) throws CacheLoaderException {
|
||||
return loaderHelper.getKey();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright 2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.data.gemfire.config.annotation;
|
||||
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import java.security.Principal;
|
||||
import java.util.Properties;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
|
||||
import org.apache.geode.security.AuthenticationFailedException;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
* The {@link TestSecurityManager} class is an Apache Geode / Pivotal GemFire
|
||||
* {@link org.apache.geode.security.SecurityManager} implementation used for testing purposes.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see java.security.Principal
|
||||
* @see java.util.Properties
|
||||
* @see org.apache.geode.security.SecurityManager
|
||||
* @since 2.0.0
|
||||
*/
|
||||
public final class TestSecurityManager implements org.apache.geode.security.SecurityManager {
|
||||
|
||||
public static final String SECURITY_USERNAME_PROPERTY = "security-username";
|
||||
public static final String SECURITY_PASSWORD_PROPERTY = "security-password";
|
||||
|
||||
public static final String SECURITY_USERNAME = "testUser";
|
||||
public static final String SECURITY_PASSWORD = "testP@55w0rd";
|
||||
|
||||
private final ConcurrentMap<String, String> authorizedUsers;
|
||||
|
||||
public TestSecurityManager() {
|
||||
this.authorizedUsers = new ConcurrentHashMap<>();
|
||||
this.authorizedUsers.putIfAbsent(SECURITY_USERNAME, SECURITY_PASSWORD);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object authenticate(Properties properties) throws AuthenticationFailedException {
|
||||
|
||||
String username = properties.getProperty(SECURITY_USERNAME_PROPERTY);
|
||||
String password = properties.getProperty(SECURITY_PASSWORD_PROPERTY);
|
||||
|
||||
return validateIdentified(isIdentified(username, password) ? newPrincipal(username) : null, username);
|
||||
}
|
||||
|
||||
private boolean isIdentified(String username, String password) {
|
||||
return ObjectUtils.nullSafeEquals(this.authorizedUsers.get(String.valueOf(username)), password);
|
||||
}
|
||||
|
||||
private Principal newPrincipal(String username) {
|
||||
|
||||
Principal mockPrincipal = mock(Principal.class, username);
|
||||
|
||||
when(mockPrincipal.getName()).thenReturn(username);
|
||||
|
||||
return mockPrincipal;
|
||||
}
|
||||
|
||||
private Principal validateIdentified(Principal principal, String username) {
|
||||
|
||||
if (principal == null) {
|
||||
throw new AuthenticationFailedException(String.format("User [%s] is not valid", username));
|
||||
}
|
||||
|
||||
return principal;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user