SEC-1536: added JAAS API Integration, updated doc, updated jaas sample

This commit is contained in:
rwinch 2010-09-13 13:12:45 -05:00
parent 0217e98bdb
commit de819378fc
19 changed files with 476 additions and 6 deletions

View File

@ -17,6 +17,7 @@ import org.springframework.security.web.access.intercept.FilterSecurityIntercept
import org.springframework.security.web.authentication.AnonymousAuthenticationFilter;
import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.jaas.JaasApiIntegrationFilter;
import org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
import org.springframework.security.web.context.SecurityContextPersistenceFilter;
@ -52,6 +53,7 @@ public class DefaultFilterChainValidator implements FilterChainProxy.FilterChain
checkForDuplicates(SessionManagementFilter.class, filters);
checkForDuplicates(BasicAuthenticationFilter.class, filters);
checkForDuplicates(SecurityContextHolderAwareRequestFilter.class, filters);
checkForDuplicates(JaasApiIntegrationFilter.class, filters);
checkForDuplicates(ExceptionTranslationFilter.class, filters);
checkForDuplicates(FilterSecurityInterceptor.class, filters);
}

View File

@ -4,7 +4,6 @@ import static org.springframework.security.config.http.HttpSecurityBeanDefinitio
import static org.springframework.security.config.http.SecurityFilters.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.springframework.beans.factory.config.BeanDefinition;
@ -35,6 +34,7 @@ import org.springframework.security.web.access.expression.WebExpressionVoter;
import org.springframework.security.web.access.intercept.DefaultFilterInvocationSecurityMetadataSource;
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;
import org.springframework.security.web.authentication.jaas.JaasApiIntegrationFilter;
import org.springframework.security.web.authentication.session.ConcurrentSessionControlStrategy;
import org.springframework.security.web.authentication.session.SessionFixationProtectionStrategy;
import org.springframework.security.web.context.HttpSessionSecurityContextRepository;
@ -90,6 +90,7 @@ class HttpConfigurationBuilder {
private BeanReference sessionStrategyRef;
private RootBeanDefinition sfpf;
private BeanDefinition servApiFilter;
private BeanDefinition jaasApiFilter;
private final String portMapperName;
private BeanReference fsi;
private BeanReference requestCache;
@ -123,6 +124,7 @@ class HttpConfigurationBuilder {
createSessionManagementFilters();
createRequestCacheFilter();
createServletApiFilter();
createJaasApiFilter();
createChannelProcessingFilter();
createFilterSecurityInterceptor(authenticationManager);
}
@ -337,7 +339,22 @@ class HttpConfigurationBuilder {
servApiFilter = new RootBeanDefinition(SecurityContextHolderAwareRequestFilter.class);
}
}
// Adds the jaas-api integration filter if required
private void createJaasApiFilter() {
final String ATT_JAAS_API_PROVISION = "jaas-api-provision";
final String DEF_JAAS_API_PROVISION = "false";
String provideJaasApi = httpElt.getAttribute(ATT_JAAS_API_PROVISION);
if (!StringUtils.hasText(provideJaasApi)) {
provideJaasApi = DEF_JAAS_API_PROVISION;
}
if ("true".equals(provideJaasApi)) {
jaasApiFilter = new RootBeanDefinition(JaasApiIntegrationFilter.class);
}
}
private void createChannelProcessingFilter() {
ManagedMap<BeanDefinition,BeanDefinition> channelRequestMap = parseInterceptUrlsForChannelSecurity();
@ -514,6 +531,10 @@ class HttpConfigurationBuilder {
filters.add(new OrderDecorator(servApiFilter, SERVLET_API_SUPPORT_FILTER));
}
if (jaasApiFilter != null) {
filters.add(new OrderDecorator(jaasApiFilter, JAAS_API_SUPPORT_FILTER));
}
if (sfpf != null) {
filters.add(new OrderDecorator(sfpf, SESSION_MANAGEMENT_FILTER));
}

View File

@ -23,6 +23,7 @@ enum SecurityFilters {
BASIC_AUTH_FILTER,
REQUEST_CACHE_FILTER,
SERVLET_API_SUPPORT_FILTER,
JAAS_API_SUPPORT_FILTER,
REMEMBER_ME_FILTER,
ANONYMOUS_FILTER,
SESSION_MANAGEMENT_FILTER,

View File

@ -289,6 +289,9 @@ http.attlist &=
http.attlist &=
## Provides versions of HttpServletRequest security methods such as isUserInRole() and getPrincipal() which are implemented by accessing the Spring SecurityContext. Defaults to "true".
attribute servlet-api-provision {boolean}?
http.attlist &=
## If available, runs the request as the Subject acquired from the JaasAuthenticationToken. Defaults to "false".
attribute jaas-api-provision {boolean}?
http.attlist &=
## Optional attribute specifying the ID of the AccessDecisionManager implementation which should be used for authorizing HTTP requests.
attribute access-decision-manager-ref {xsd:token}?

View File

@ -759,6 +759,11 @@
<xs:documentation>Provides versions of HttpServletRequest security methods such as isUserInRole() and getPrincipal() which are implemented by accessing the Spring SecurityContext. Defaults to "true".</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="jaas-api-provision" type="security:boolean">
<xs:annotation>
<xs:documentation>If available, runs the request as the Subject acquired from the JaasAuthenticationToken. Defaults to "false".</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="access-decision-manager-ref" type="xs:token">
<xs:annotation>
<xs:documentation>Optional attribute specifying the ID of the AccessDecisionManager implementation which should be used for authorizing HTTP requests.</xs:documentation>

View File

@ -30,6 +30,7 @@ import org.springframework.security.web.access.intercept.FilterSecurityIntercept
import org.springframework.security.web.authentication.AnonymousAuthenticationFilter
import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter
import org.springframework.security.web.authentication.jaas.JaasApiIntegrationFilter
import org.springframework.security.web.authentication.logout.LogoutFilter
import org.springframework.security.web.authentication.logout.SimpleUrlLogoutSuccessHandler
import org.springframework.security.web.authentication.preauth.x509.X509AuthenticationFilter
@ -568,6 +569,14 @@ class MiscHttpConfigTests extends AbstractHttpConfigTests {
getFilter(BasicAuthenticationFilter).authenticationDetailsSource == adsr
getFilter(X509AuthenticationFilter).authenticationDetailsSource == adsr
}
def includeJaasApiIntegrationFilter() {
xml.http(['auto-config':'true','jaas-api-provision':'true'])
createAppContext()
expect:
getFilter(JaasApiIntegrationFilter.class) != null
}
}
class MockEntryPoint extends LoginUrlAuthenticationEntryPoint {

View File

@ -70,6 +70,13 @@
<classname>SecurityContextHolderAwareRequestFilter</classname> bean to the
stack. Defaults to "true".</para>
</section>
<section xml:id="nsa-jaas-api-provision">
<title><literal>jaas-api-provision</literal></title>
<para>If available, runs the request as the <literal>Subject</literal> acquired from
the <classname>JaasAuthenticationToken</classname> which is implemented by
adding a <classname>JaasApiIntegrationFilter</classname> bean to the stack.
Defaults to "false".</para>
</section>
<section xml:id="nsa-path-type">
<title><literal>request-matcher</literal></title>
<para> Defines the <interfacename>RequestMatcher</interfacename> strategy used in

View File

@ -213,4 +213,20 @@ JAASTest {
</bean>
]]></programlisting></para>
</section>
<section xml:id="jaas-apiprovision">
<info>
<title xml:id="jaas-api-provision">Running as a Subject</title>
</info>
<para>If configured, the <classname>JaasApiIntegrationFilter</classname> will attempt to
run as the <literal>Subject</literal> on the
<classname>JaasAuthenticationToken</classname>. This means that the
<literal>Subject</literal> can be accessed using:
<programlisting language="java"><![CDATA[
Subject subject = Subject.getSubject(AccessController.getContext());
]]></programlisting>
This integration can easily be configured using the
<link xlink:href="#nsa-jaas-api-provision">jaas-api-provision</link> attribute. This
feature is useful when integrating with legacy or external API's that rely on the
JAAS Subject being populated.</para>
</section>
</chapter>

View File

@ -691,6 +691,11 @@ List&lt;OpenIDAttribute> attributes = token.getAttributes();</programlisting>The
<entry><literal>SecurityContextHolderAwareFilter</literal></entry>
<entry><literal>http/@servlet-api-provision</literal></entry>
</row>
<row>
<entry>JAAS_API_SUPPORT_FILTER</entry>
<entry><literal>JaasApiIntegrationFilter</literal></entry>
<entry><literal>http/@jaas-api-provision</literal></entry>
</row>
<row>
<entry> REMEMBER_ME_FILTER </entry>
<entry><classname>RememberMeAuthenticationFilter</classname></entry>

View File

@ -133,7 +133,8 @@ Success! Your web filters appear to be properly configured!
<title>JAAS Sample</title>
<para>The JAAS sample is very simple example of how to use a JAAS LoginModule with Spring Security. The provided LoginModule will
successfully authenticate a user if the username equals the password otherwise a LoginException is thrown. The AuthorityGranter
used in this example always grants the role ROLE_USER.</para>
used in this example always grants the role ROLE_USER. The sample application also demonstrates how to run as the JAAS Subject
returned by the LoginModule by setting <link xlink:href="#nsa-jaas-api-provision">jaas-api-provision</link> equal to "true".</para>
</section>
<section xml:id="preauth-sample">
<title>Pre-Authentication Sample</title>

View File

@ -151,6 +151,13 @@
using it to install a Spring Security aware
<literal>HttpServletRequestWrapper</literal> into your servlet container</para>
</listitem>
<listitem>
<para>The <classname>JaasApiIntegrationFilter</classname>, if a
<classname>JaasAuthenticationToken</classname> is in the
<classname>SecurityContextHolder</classname> this will process the
<classname>FilterChain</classname> as the <classname>Subject</classname> in the
<classname>JaasAuthenticationToken</classname></para>
</listitem>
<listitem>
<para><classname>RememberMeAuthenticationFilter</classname>, so that if no earlier
authentication processing mechanism updated the

View File

@ -13,7 +13,6 @@ dependencies {
runtime project(':spring-security-web'),
project(':spring-security-config'),
project(':spring-security-taglibs'),
"org.springframework:spring-context-support:$springVersion",
"javax.servlet:jstl:$jstlVersion",
"org.slf4j:jcl-over-slf4j:$slf4jVersion",

View File

@ -67,7 +67,7 @@ public class UsernameEqualsPasswordLoginModule implements LoginModule {
}
public boolean login() throws LoginException {
if (username != null && !username.equals(password)) {
if (username == null || !username.equals(password)) {
throw new LoginException("username is not equal to password");
}
@ -75,6 +75,9 @@ public class UsernameEqualsPasswordLoginModule implements LoginModule {
public String getName() {
return username;
}
public String toString() {
return "Principal [name="+getName()+"]";
}
});
return true;
}

View File

@ -9,7 +9,7 @@
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd">
<sec:http auto-config="true" use-expressions="true">
<sec:http auto-config="true" use-expressions="true" jaas-api-provision="true">
<sec:intercept-url pattern="/secure/**" access="isAuthenticated()"/>
</sec:http>

View File

@ -1,3 +1,5 @@
<%@ page import="javax.security.auth.Subject" %>
<%@ page import="java.security.AccessController" %>
<%@ taglib prefix="sec" uri="http://www.springframework.org/security/tags" %>
<html>
<body>
@ -9,6 +11,9 @@ Anyone can view this page.
Your principal object is....: <%= request.getUserPrincipal() %>
</p>
<p>
Subject.getSubject(AccessController.getContext()) is....: <%= Subject.getSubject(AccessController.getContext()) %>
</p>
<p>
<sec:authorize url='/secure/index.jsp'>You can currently access "/secure" URLs.</sec:authorize>
</p>

View File

@ -1,3 +1,5 @@
<%@ page import="javax.security.auth.Subject" %>
<%@ page import="java.security.AccessController" %>
<%@ page import="org.springframework.security.core.context.SecurityContextHolder" %>
<%@ page import="org.springframework.security.core.Authentication" %>
<%@ page import="org.springframework.security.core.GrantedAuthority" %>
@ -10,6 +12,15 @@
<h3>Security Debug Information</h3>
<%
Subject subject = Subject.getSubject(AccessController.getContext());
if(subject != null) { %>
<p>
Subject.getSubject(AccessController.getContext()) is....: <%= subject %>
</p>
<%} %>
<%
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
if (auth != null) { %>

View File

@ -0,0 +1,163 @@
/*
* 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.web.authentication.jaas;
import java.io.IOException;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import javax.security.auth.Subject;
import javax.security.auth.login.LoginContext;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import org.springframework.security.authentication.jaas.JaasAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.filter.GenericFilterBean;
/**
* <p>
* A <code>Filter</code> which attempts to obtain a JAAS <code>Subject</code>
* and continue the <code>FilterChain</code> running as that
* <code>Subject</code>.
* </p>
* <p>
* By using this <code>Filter</code> in conjunction with Spring's
* <code>JaasAuthenticationProvider</code> both Spring's
* <code>SecurityContext</code> and a JAAS <code>Subject</code> can be populated
* simultaneously. This is useful when integrating with code that requires a
* JAAS <code>Subject</code> to be populated.
* </p>
*
* @author Rob Winch
* @see #doFilter(ServletRequest, ServletResponse, FilterChain)
* @see #obtainSubject(ServletRequest)
*/
public class JaasApiIntegrationFilter extends GenericFilterBean {
//~ Instance fields ================================================================================================
private boolean createEmptySubject;
//~ Methods ========================================================================================================
/**
* <p>
* Attempts to obtain and run as a JAAS <code>Subject</code> using
* {@link #obtainSubject(ServletRequest)}.
* </p>
*
* <p>
* If the <code>Subject</code> is <code>null</code> and
* <tt>createEmptySubject</tt> is <code>true</code>, an empty, writeable
* <code>Subject</code> is used. This allows for the <code>Subject</code> to
* be populated at the time of login. If the <code>Subject</code> is
* <code>null</code>, the <code>FilterChain</code> continues with no
* additional processing. If the <code>Subject</code> is not
* <code>null</code>, the <code>FilterChain</code> is ran with
* {@link Subject#doAs(Subject, PrivilegedExceptionAction)} in conjunction
* with the <code>Subject</code> obtained.
* </p>
*/
public final void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain chain)
throws ServletException, IOException {
Subject subject = obtainSubject(request);
if (subject == null && createEmptySubject) {
if (logger.isDebugEnabled()) {
logger.debug("Subject returned was null and createEmtpySubject is true; creating new empty subject to run as.");
}
subject = new Subject();
}
if (subject == null) {
if (logger.isDebugEnabled()) {
logger.debug("Subject is null continue running with no Subject.");
}
chain.doFilter(request, response);
return;
}
final PrivilegedExceptionAction<Object> continueChain = new PrivilegedExceptionAction<Object>() {
public Object run() throws IOException, ServletException {
chain.doFilter(request, response);
return null;
}
};
if (logger.isDebugEnabled()) {
logger.debug("Running as Subject " + subject);
}
try {
Subject.doAs(subject, continueChain);
} catch (PrivilegedActionException e) {
throw new ServletException(e.getMessage(), e);
}
}
/**
* <p>
* Obtains the <code>Subject</code> to run as or <code>null</code> if no
* <code>Subject</code> is available.
* </p>
* <p>
* The default implementation attempts to obtain the <code>Subject</code>
* from the <code>SecurityContext</code>'s <code>Authentication</code>. If
* it is of type <code>JaasAuthenticationToken</code> and is authenticated,
* the <code>Subject</code> is returned from it. Otherwise,
* <code>null</code> is returned.
* </p>
*
* @param request
* the current <code>ServletRequest</code>
* @return the Subject to run as or <code>null</code> if no
* <code>Subject</code> is available.
*/
protected Subject obtainSubject(ServletRequest request) {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (logger.isDebugEnabled()) {
logger.debug("Attempting to obtainSubject using authentication : " + authentication);
}
if (authentication == null) {
return null;
}
if (!authentication.isAuthenticated()) {
return null;
}
if (!(authentication instanceof JaasAuthenticationToken)) {
return null;
}
JaasAuthenticationToken token = (JaasAuthenticationToken) authentication;
LoginContext loginContext = token.getLoginContext();
if (loginContext == null) {
return null;
}
return loginContext.getSubject();
}
/**
* Sets <code>createEmptySubject</code>. If the value is <code>true</code>,
* and {@link #obtainSubject(ServletRequest)} returns <code>null</code>, an
* empty, writeable <code>Subject</code> is created instead. Otherwise no
* <code>Subject</code> is used. The default is <code>false</code>.
*
* @param createEmptySubject
* the new value
*/
public final void setCreateEmptySubject(boolean createEmptySubject) {
this.createEmptySubject = createEmptySubject;
}
}

View File

@ -0,0 +1,211 @@
/*
* 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.web.authentication.jaas;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import java.io.IOException;
import java.security.AccessController;
import java.security.Principal;
import java.util.HashMap;
import javax.security.auth.Subject;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.NameCallback;
import javax.security.auth.callback.PasswordCallback;
import javax.security.auth.callback.TextInputCallback;
import javax.security.auth.callback.UnsupportedCallbackException;
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.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.springframework.mock.web.MockFilterChain;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.security.authentication.TestingAuthenticationToken;
import org.springframework.security.authentication.jaas.JaasAuthenticationToken;
import org.springframework.security.authentication.jaas.TestLoginModule;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.context.SecurityContextHolder;
/**
* Tests the JaasApiIntegrationFilter.
*
* @author Rob Winch
*/
public class JaasApiIntegrationFilterTest {
//~ Instance fields ================================================================================================
private JaasApiIntegrationFilter filter;
private MockHttpServletRequest request;
private MockHttpServletResponse response;
private Authentication token;
private Subject authenticatedSubject;
private Configuration testConfiguration;
private CallbackHandler callbackHandler;
//~ Methods ========================================================================================================
@Before
public void onBeforeTests() throws Exception {
this.filter = new JaasApiIntegrationFilter();
this.request = new MockHttpServletRequest();
this.response = new MockHttpServletResponse();
authenticatedSubject = new Subject();
authenticatedSubject.getPrincipals().add(new Principal() {
public String getName() {
return "principal";
}
});
authenticatedSubject.getPrivateCredentials().add("password");
authenticatedSubject.getPublicCredentials().add("username");
callbackHandler = new CallbackHandler() {
@Override
public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
for (Callback callback : callbacks) {
if (callback instanceof NameCallback) {
((NameCallback) callback).setName("user");
} else if (callback instanceof PasswordCallback) {
((PasswordCallback) callback).setPassword("password".toCharArray());
} else if (callback instanceof TextInputCallback) {
// ignore
} else {
throw new UnsupportedCallbackException(callback, "Unrecognized Callback " + callback);
}
}
}
};
testConfiguration = new Configuration() {
public void refresh() {
}
public AppConfigurationEntry[] getAppConfigurationEntry(String name) {
return new AppConfigurationEntry[] { new AppConfigurationEntry(TestLoginModule.class.getName(),
LoginModuleControlFlag.REQUIRED, new HashMap<String, String>()) };
}
};
LoginContext ctx = new LoginContext("SubjectDoAsFilterTest", authenticatedSubject, callbackHandler,
testConfiguration);
ctx.login();
token = new JaasAuthenticationToken("username", "password", AuthorityUtils.createAuthorityList("ROLE_ADMIN"),
ctx);
// just in case someone forgot to clear the context
SecurityContextHolder.clearContext();
}
@After
public void onAfterTests() {
SecurityContextHolder.clearContext();
}
/**
* Ensure a Subject was not setup in some other manner.
*/
@Test
public void currentSubjectNull() {
assertNull(Subject.getSubject(AccessController.getContext()));
}
@Test
public void obtainSubjectNullAuthentication() {
assertNullSubject(filter.obtainSubject(request));
}
@Test
public void obtainSubjectNonJaasAuthentication() {
Authentication authentication = new TestingAuthenticationToken("un", "pwd");
authentication.setAuthenticated(true);
SecurityContextHolder.getContext().setAuthentication(authentication);
assertNullSubject(filter.obtainSubject(request));
}
@Test
public void obtainSubjectNullLoginContext() {
token = new JaasAuthenticationToken("un", "pwd", AuthorityUtils.createAuthorityList("ROLE_ADMIN"), null);
SecurityContextHolder.getContext().setAuthentication(token);
assertNullSubject(filter.obtainSubject(request));
}
@Test
public void obtainSubjectNullSubject() throws Exception {
LoginContext ctx = new LoginContext("obtainSubjectNullSubject", null, callbackHandler, testConfiguration);
assertNull(ctx.getSubject());
token = new JaasAuthenticationToken("un", "pwd", AuthorityUtils.createAuthorityList("ROLE_ADMIN"), ctx);
SecurityContextHolder.getContext().setAuthentication(token);
assertNullSubject(filter.obtainSubject(request));
}
@Test
public void obtainSubject() throws Exception {
SecurityContextHolder.getContext().setAuthentication(token);
assertEquals(authenticatedSubject, filter.obtainSubject(request));
}
@Test
public void doFilterCurrentSubjectPopulated() throws Exception {
SecurityContextHolder.getContext().setAuthentication(token);
assertJaasSubjectEquals(authenticatedSubject);
}
@Test
public void doFilterAuthenticationNotAuthenticated() throws Exception {
// Authentication is null, so no Subject is populated.
token.setAuthenticated(false);
SecurityContextHolder.getContext().setAuthentication(token);
assertJaasSubjectEquals(null);
filter.setCreateEmptySubject(true);
assertJaasSubjectEquals(new Subject());
}
@Test
public void doFilterAuthenticationNull() throws Exception {
assertJaasSubjectEquals(null);
filter.setCreateEmptySubject(true);
assertJaasSubjectEquals(new Subject());
}
//~ Helper Methods ====================================================================================================
private void assertJaasSubjectEquals(final Subject expectedValue) throws Exception {
MockFilterChain chain = new MockFilterChain() {
public void doFilter(ServletRequest request, ServletResponse response) {
// See if the subject was updated
Subject currentSubject = Subject.getSubject(AccessController.getContext());
assertEquals(expectedValue, currentSubject);
// run so we know the chain was executed
super.doFilter(request, response);
}
};
filter.doFilter(request, response, chain);
// ensure that the chain was actually invoked
assertNotNull(chain.getRequest());
}
private void assertNullSubject(Subject subject) {
assertNull("Subject is expected to be null, but is not. Got " + subject, subject);
}
}

View File

@ -13,7 +13,8 @@ dependencies {
provided 'javax.servlet:servlet-api:2.5'
testCompile 'commons-codec:commons-codec:1.3',
testCompile project(':spring-security-core').sourceSets.test.classes,
'commons-codec:commons-codec:1.3',
"org.springframework:spring-test:$springVersion"
testRuntime "hsqldb:hsqldb:$hsqlVersion"
}