SEC-1564: JAAS Configuration can now be injected into DefaultJaasAuthenticationProvider
This commit is contained in:
@@ -0,0 +1,273 @@
|
||||
/*
|
||||
* Copyright 2010 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.security.authentication.jaas;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.fail;
|
||||
import static org.mockito.Matchers.anyString;
|
||||
import static org.mockito.Matchers.argThat;
|
||||
import static org.mockito.Matchers.eq;
|
||||
import static org.mockito.Matchers.isA;
|
||||
import static org.mockito.Mockito.doThrow;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
import javax.security.auth.login.AppConfigurationEntry;
|
||||
import javax.security.auth.login.AppConfigurationEntry.LoginModuleControlFlag;
|
||||
import javax.security.auth.login.Configuration;
|
||||
import javax.security.auth.login.LoginContext;
|
||||
import javax.security.auth.login.LoginException;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.hamcrest.BaseMatcher;
|
||||
import org.hamcrest.Description;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.context.ApplicationEventPublisher;
|
||||
import org.springframework.context.support.ClassPathXmlApplicationContext;
|
||||
import org.springframework.security.authentication.BadCredentialsException;
|
||||
import org.springframework.security.authentication.TestingAuthenticationToken;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.authentication.jaas.DefaultJaasAuthenticationProvider;
|
||||
import org.springframework.security.authentication.jaas.event.JaasAuthenticationFailedEvent;
|
||||
import org.springframework.security.authentication.jaas.event.JaasAuthenticationSuccessEvent;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.security.core.context.SecurityContext;
|
||||
import org.springframework.security.core.session.SessionDestroyedEvent;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
|
||||
public class DefaultJaasAuthenticationProviderTests {
|
||||
private DefaultJaasAuthenticationProvider provider;
|
||||
private UsernamePasswordAuthenticationToken token;
|
||||
private ApplicationEventPublisher publisher;
|
||||
private Log log;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
Configuration configuration = mock(Configuration.class);
|
||||
publisher = mock(ApplicationEventPublisher.class);
|
||||
log = mock(Log.class);
|
||||
provider = new DefaultJaasAuthenticationProvider();
|
||||
provider.setConfiguration(configuration);
|
||||
provider.setApplicationEventPublisher(publisher);
|
||||
provider.setAuthorityGranters(new AuthorityGranter[] { new TestAuthorityGranter() });
|
||||
provider.afterPropertiesSet();
|
||||
AppConfigurationEntry[] aces = new AppConfigurationEntry[] { new AppConfigurationEntry(
|
||||
TestLoginModule.class.getName(), LoginModuleControlFlag.REQUIRED,
|
||||
Collections.<String, Object> emptyMap()) };
|
||||
when(configuration.getAppConfigurationEntry(provider.getLoginContextName())).thenReturn(aces);
|
||||
token = new UsernamePasswordAuthenticationToken("user", "password");
|
||||
ReflectionTestUtils.setField(provider, "log", log);
|
||||
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void afterPropertiesSetNullConfiguration() throws Exception {
|
||||
provider.setConfiguration(null);
|
||||
provider.afterPropertiesSet();
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void afterPropertiesSetNullAuthorityGranters() throws Exception {
|
||||
provider.setAuthorityGranters(null);
|
||||
provider.afterPropertiesSet();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void authenticateUnsupportedAuthentication() {
|
||||
assertEquals(null, provider.authenticate(new TestingAuthenticationToken("user", "password")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void authenticateSuccess() throws Exception {
|
||||
Authentication auth = provider.authenticate(token);
|
||||
assertEquals(token.getPrincipal(), auth.getPrincipal());
|
||||
assertEquals(token.getCredentials(), auth.getCredentials());
|
||||
assertEquals(true, auth.isAuthenticated());
|
||||
assertEquals(false, auth.getAuthorities().isEmpty());
|
||||
verify(publisher).publishEvent(isA(JaasAuthenticationSuccessEvent.class));
|
||||
verifyNoMoreInteractions(publisher);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void authenticateBadPassword() {
|
||||
try {
|
||||
provider.authenticate(new UsernamePasswordAuthenticationToken("user", "asdf"));
|
||||
fail("LoginException should have been thrown for the bad password");
|
||||
} catch (AuthenticationException success) {
|
||||
}
|
||||
|
||||
verifyFailedLogin();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void authenticateBadUser() {
|
||||
try {
|
||||
provider.authenticate(new UsernamePasswordAuthenticationToken("asdf", "password"));
|
||||
fail("LoginException should have been thrown for the bad user");
|
||||
} catch (AuthenticationException success) {
|
||||
}
|
||||
|
||||
verifyFailedLogin();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void logout() throws Exception {
|
||||
SessionDestroyedEvent event = mock(SessionDestroyedEvent.class);
|
||||
SecurityContext securityContext = mock(SecurityContext.class);
|
||||
JaasAuthenticationToken token = mock(JaasAuthenticationToken.class);
|
||||
LoginContext context = mock(LoginContext.class);
|
||||
|
||||
when(event.getSecurityContext()).thenReturn(securityContext);
|
||||
when(securityContext.getAuthentication()).thenReturn(token);
|
||||
when(token.getLoginContext()).thenReturn(context);
|
||||
|
||||
provider.onApplicationEvent(event);
|
||||
|
||||
verify(event).getSecurityContext();
|
||||
verify(securityContext).getAuthentication();
|
||||
verify(token).getLoginContext();
|
||||
verify(context).logout();
|
||||
verifyNoMoreInteractions(event, securityContext, token, context);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void logoutNullSession() {
|
||||
SessionDestroyedEvent event = mock(SessionDestroyedEvent.class);
|
||||
|
||||
provider.handleLogout(event);
|
||||
|
||||
verify(event).getSecurityContext();
|
||||
verify(log).debug(anyString());
|
||||
verifyNoMoreInteractions(event);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void logoutNullAuthentication() {
|
||||
SessionDestroyedEvent event = mock(SessionDestroyedEvent.class);
|
||||
SecurityContext securityContext = mock(SecurityContext.class);
|
||||
|
||||
when(event.getSecurityContext()).thenReturn(securityContext);
|
||||
|
||||
provider.handleLogout(event);
|
||||
|
||||
verify(event).getSecurityContext();
|
||||
verify(event).getSecurityContext();
|
||||
verify(securityContext).getAuthentication();
|
||||
verifyNoMoreInteractions(event, securityContext);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void logoutNonJaasAuthentication() {
|
||||
SessionDestroyedEvent event = mock(SessionDestroyedEvent.class);
|
||||
SecurityContext securityContext = mock(SecurityContext.class);
|
||||
|
||||
when(event.getSecurityContext()).thenReturn(securityContext);
|
||||
when(securityContext.getAuthentication()).thenReturn(token);
|
||||
|
||||
provider.handleLogout(event);
|
||||
|
||||
verify(event).getSecurityContext();
|
||||
verify(event).getSecurityContext();
|
||||
verify(securityContext).getAuthentication();
|
||||
verifyNoMoreInteractions(event, securityContext);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void logoutNullLoginContext() throws Exception {
|
||||
SessionDestroyedEvent event = mock(SessionDestroyedEvent.class);
|
||||
SecurityContext securityContext = mock(SecurityContext.class);
|
||||
JaasAuthenticationToken token = mock(JaasAuthenticationToken.class);
|
||||
|
||||
when(event.getSecurityContext()).thenReturn(securityContext);
|
||||
when(securityContext.getAuthentication()).thenReturn(token);
|
||||
|
||||
provider.onApplicationEvent(event);
|
||||
verify(event).getSecurityContext();
|
||||
verify(securityContext).getAuthentication();
|
||||
verify(token).getLoginContext();
|
||||
|
||||
verifyNoMoreInteractions(event, securityContext, token);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void logoutLoginException() throws Exception {
|
||||
SessionDestroyedEvent event = mock(SessionDestroyedEvent.class);
|
||||
SecurityContext securityContext = mock(SecurityContext.class);
|
||||
JaasAuthenticationToken token = mock(JaasAuthenticationToken.class);
|
||||
LoginContext context = mock(LoginContext.class);
|
||||
LoginException loginException = new LoginException("Failed Login");
|
||||
|
||||
when(event.getSecurityContext()).thenReturn(securityContext);
|
||||
when(securityContext.getAuthentication()).thenReturn(token);
|
||||
when(token.getLoginContext()).thenReturn(context);
|
||||
doThrow(loginException).when(context).logout();
|
||||
|
||||
provider.onApplicationEvent(event);
|
||||
|
||||
verify(event).getSecurityContext();
|
||||
verify(securityContext).getAuthentication();
|
||||
verify(token).getLoginContext();
|
||||
verify(context).logout();
|
||||
verify(log).warn(anyString(), eq(loginException));
|
||||
verifyNoMoreInteractions(event, securityContext, token, context);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void publishNullPublisher() {
|
||||
provider.setApplicationEventPublisher(null);
|
||||
AuthenticationException ae = new BadCredentialsException("Failed to login", token);
|
||||
|
||||
provider.publishFailureEvent(token, ae);
|
||||
provider.publishSuccessEvent(token);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void javadocExample() {
|
||||
String resName = "/" + getClass().getName().replace('.', '/') + ".xml";
|
||||
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(resName);
|
||||
context.registerShutdownHook();
|
||||
try {
|
||||
provider = context.getBean(DefaultJaasAuthenticationProvider.class);
|
||||
Authentication auth = provider.authenticate(token);
|
||||
assertEquals(true, auth.isAuthenticated());
|
||||
assertEquals(token.getPrincipal(), auth.getPrincipal());
|
||||
} finally {
|
||||
context.close();
|
||||
}
|
||||
}
|
||||
|
||||
private void verifyFailedLogin() {
|
||||
verify(publisher).publishEvent(argThat(new BaseMatcher<JaasAuthenticationFailedEvent>() {
|
||||
public void describeTo(Description desc) {
|
||||
desc.appendText("isA(org.springframework.security.authentication.jaas.event.JaasAuthenticationFailedEvent)");
|
||||
desc.appendText(" && event.getException() != null");
|
||||
}
|
||||
|
||||
public boolean matches(Object arg) {
|
||||
JaasAuthenticationFailedEvent e = (JaasAuthenticationFailedEvent) arg;
|
||||
return e.getException() != null;
|
||||
}
|
||||
|
||||
}));
|
||||
verifyNoMoreInteractions(publisher);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Copyright 2010 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.security.authentication.jaas.memory;
|
||||
|
||||
import static org.junit.Assert.assertArrayEquals;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNull;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.security.auth.login.AppConfigurationEntry;
|
||||
import javax.security.auth.login.AppConfigurationEntry.LoginModuleControlFlag;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.security.authentication.jaas.TestLoginModule;
|
||||
|
||||
/**
|
||||
* Tests {@link InMemoryConfiguration}.
|
||||
*
|
||||
* @author Rob Winch
|
||||
*/
|
||||
public class InMemoryConfigurationTests {
|
||||
|
||||
private AppConfigurationEntry[] defaultEntries;
|
||||
private Map<String, AppConfigurationEntry[]> mappedEntries;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
defaultEntries = new AppConfigurationEntry[] { new AppConfigurationEntry(TestLoginModule.class.getName(),
|
||||
LoginModuleControlFlag.REQUIRED, Collections.<String, Object> emptyMap()) };
|
||||
|
||||
mappedEntries = Collections.<String, AppConfigurationEntry[]> singletonMap("name",
|
||||
new AppConfigurationEntry[] { new AppConfigurationEntry(TestLoginModule.class.getName(),
|
||||
LoginModuleControlFlag.OPTIONAL, Collections.<String, Object> emptyMap()) });
|
||||
}
|
||||
|
||||
@Test
|
||||
public void constructorNullDefault() {
|
||||
assertNull(new InMemoryConfiguration((AppConfigurationEntry[]) null).getAppConfigurationEntry("name"));
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void constructorNullMapped() {
|
||||
new InMemoryConfiguration((Map<String, AppConfigurationEntry[]>) null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void constructorEmptyMap() {
|
||||
assertNull(new InMemoryConfiguration(Collections.<String, AppConfigurationEntry[]> emptyMap())
|
||||
.getAppConfigurationEntry("name"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void constructorEmptyMapNullDefault() {
|
||||
assertNull(new InMemoryConfiguration(Collections.<String, AppConfigurationEntry[]> emptyMap(), null)
|
||||
.getAppConfigurationEntry("name"));
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void constructorNullMapNullDefault() {
|
||||
new InMemoryConfiguration(null, null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nonnullDefault() {
|
||||
InMemoryConfiguration configuration = new InMemoryConfiguration(defaultEntries);
|
||||
assertArrayEquals(defaultEntries, configuration.getAppConfigurationEntry("name"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void mappedNonnullDefault() {
|
||||
InMemoryConfiguration configuration = new InMemoryConfiguration(mappedEntries, defaultEntries);
|
||||
assertArrayEquals(defaultEntries, configuration.getAppConfigurationEntry("missing"));
|
||||
assertArrayEquals(mappedEntries.get("name"), configuration.getAppConfigurationEntry("name"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void jdk5Compatable() throws Exception {
|
||||
Method method = InMemoryConfiguration.class.getDeclaredMethod("refresh");
|
||||
assertEquals(InMemoryConfiguration.class, method.getDeclaringClass());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:util="http://www.springframework.org/schema/util"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
|
||||
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd">
|
||||
|
||||
<bean id="jaasAuthProvider"
|
||||
class="org.springframework.security.authentication.jaas.DefaultJaasAuthenticationProvider">
|
||||
<property name="configuration">
|
||||
<bean
|
||||
class="org.springframework.security.authentication.jaas.memory.InMemoryConfiguration">
|
||||
<constructor-arg>
|
||||
<map>
|
||||
<entry key="SPRINGSECURITY">
|
||||
<array>
|
||||
<bean
|
||||
class="javax.security.auth.login.AppConfigurationEntry">
|
||||
<constructor-arg
|
||||
value="org.springframework.security.authentication.jaas.TestLoginModule" />
|
||||
<constructor-arg>
|
||||
<util:constant
|
||||
static-field="javax.security.auth.login.AppConfigurationEntry$LoginModuleControlFlag.REQUIRED" />
|
||||
</constructor-arg>
|
||||
<constructor-arg>
|
||||
<map></map>
|
||||
</constructor-arg>
|
||||
</bean>
|
||||
</array>
|
||||
</entry>
|
||||
</map>
|
||||
</constructor-arg>
|
||||
</bean>
|
||||
</property>
|
||||
<property name="authorityGranters">
|
||||
<list>
|
||||
<bean
|
||||
class="org.springframework.security.authentication.jaas.TestAuthorityGranter" />
|
||||
</list>
|
||||
</property>
|
||||
</bean>
|
||||
</beans>
|
||||
Reference in New Issue
Block a user