diff --git a/config/src/main/java/org/springframework/security/config/http/DefaultFilterChainValidator.java b/config/src/main/java/org/springframework/security/config/http/DefaultFilterChainValidator.java
index a1093692fa..02a7be95c4 100644
--- a/config/src/main/java/org/springframework/security/config/http/DefaultFilterChainValidator.java
+++ b/config/src/main/java/org/springframework/security/config/http/DefaultFilterChainValidator.java
@@ -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);
}
diff --git a/config/src/main/java/org/springframework/security/config/http/HttpConfigurationBuilder.java b/config/src/main/java/org/springframework/security/config/http/HttpConfigurationBuilder.java
index f3ac8d6a42..5b2ccfa8da 100644
--- a/config/src/main/java/org/springframework/security/config/http/HttpConfigurationBuilder.java
+++ b/config/src/main/java/org/springframework/security/config/http/HttpConfigurationBuilder.java
@@ -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 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));
}
diff --git a/config/src/main/java/org/springframework/security/config/http/SecurityFilters.java b/config/src/main/java/org/springframework/security/config/http/SecurityFilters.java
index af9ea1926c..0e7568bb9d 100644
--- a/config/src/main/java/org/springframework/security/config/http/SecurityFilters.java
+++ b/config/src/main/java/org/springframework/security/config/http/SecurityFilters.java
@@ -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,
diff --git a/config/src/main/resources/org/springframework/security/config/spring-security-3.1.rnc b/config/src/main/resources/org/springframework/security/config/spring-security-3.1.rnc
index 1ee992a4f2..b138557177 100644
--- a/config/src/main/resources/org/springframework/security/config/spring-security-3.1.rnc
+++ b/config/src/main/resources/org/springframework/security/config/spring-security-3.1.rnc
@@ -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}?
diff --git a/config/src/main/resources/org/springframework/security/config/spring-security-3.1.xsd b/config/src/main/resources/org/springframework/security/config/spring-security-3.1.xsd
index a5754eba1a..e950e484f0 100644
--- a/config/src/main/resources/org/springframework/security/config/spring-security-3.1.xsd
+++ b/config/src/main/resources/org/springframework/security/config/spring-security-3.1.xsd
@@ -759,6 +759,11 @@
Provides versions of HttpServletRequest security methods such as isUserInRole() and getPrincipal() which are implemented by accessing the Spring SecurityContext. Defaults to "true".
+
+
+ If available, runs the request as the Subject acquired from the JaasAuthenticationToken. Defaults to "false".
+
+ Optional attribute specifying the ID of the AccessDecisionManager implementation which should be used for authorizing HTTP requests.
diff --git a/config/src/test/groovy/org/springframework/security/config/http/MiscHttpConfigTests.groovy b/config/src/test/groovy/org/springframework/security/config/http/MiscHttpConfigTests.groovy
index c21e56c1df..919d2d386b 100644
--- a/config/src/test/groovy/org/springframework/security/config/http/MiscHttpConfigTests.groovy
+++ b/config/src/test/groovy/org/springframework/security/config/http/MiscHttpConfigTests.groovy
@@ -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 {
diff --git a/docs/manual/src/docbook/appendix-namespace.xml b/docs/manual/src/docbook/appendix-namespace.xml
index 773caead62..63f3573b8a 100644
--- a/docs/manual/src/docbook/appendix-namespace.xml
+++ b/docs/manual/src/docbook/appendix-namespace.xml
@@ -70,6 +70,13 @@
SecurityContextHolderAwareRequestFilter bean to the
stack. Defaults to "true".
+
+ jaas-api-provision
+ If available, runs the request as the Subject acquired from
+ the JaasAuthenticationToken which is implemented by
+ adding a JaasApiIntegrationFilter bean to the stack.
+ Defaults to "false".
+ request-matcher Defines the RequestMatcher strategy used in
diff --git a/docs/manual/src/docbook/jaas-auth-provider.xml b/docs/manual/src/docbook/jaas-auth-provider.xml
index 39f3a01b9e..e50652a69e 100644
--- a/docs/manual/src/docbook/jaas-auth-provider.xml
+++ b/docs/manual/src/docbook/jaas-auth-provider.xml
@@ -213,4 +213,20 @@ JAASTest {
]]>
+
+
+ Running as a Subject
+
+ If configured, the JaasApiIntegrationFilter will attempt to
+ run as the Subject on the
+ JaasAuthenticationToken. This means that the
+ Subject can be accessed using:
+
+ This integration can easily be configured using the
+ jaas-api-provision attribute. This
+ feature is useful when integrating with legacy or external API's that rely on the
+ JAAS Subject being populated.
+
\ No newline at end of file
diff --git a/docs/manual/src/docbook/namespace-config.xml b/docs/manual/src/docbook/namespace-config.xml
index 67d5df92ce..51a3baf3bd 100644
--- a/docs/manual/src/docbook/namespace-config.xml
+++ b/docs/manual/src/docbook/namespace-config.xml
@@ -691,6 +691,11 @@ List<OpenIDAttribute> attributes = token.getAttributes();The
SecurityContextHolderAwareFilterhttp/@servlet-api-provision
+
+ JAAS_API_SUPPORT_FILTER
+ JaasApiIntegrationFilter
+ http/@jaas-api-provision
+ REMEMBER_ME_FILTER RememberMeAuthenticationFilter
diff --git a/docs/manual/src/docbook/samples.xml b/docs/manual/src/docbook/samples.xml
index 0e21e81b22..227c6d2590 100644
--- a/docs/manual/src/docbook/samples.xml
+++ b/docs/manual/src/docbook/samples.xml
@@ -133,7 +133,8 @@ Success! Your web filters appear to be properly configured!
JAAS SampleThe 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.
+ 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 jaas-api-provision equal to "true".
Pre-Authentication Sample
diff --git a/docs/manual/src/docbook/security-filter-chain.xml b/docs/manual/src/docbook/security-filter-chain.xml
index 181af8763c..af192d7870 100644
--- a/docs/manual/src/docbook/security-filter-chain.xml
+++ b/docs/manual/src/docbook/security-filter-chain.xml
@@ -151,6 +151,13 @@
using it to install a Spring Security aware
HttpServletRequestWrapper into your servlet container
+
+ The JaasApiIntegrationFilter, if a
+ JaasAuthenticationToken is in the
+ SecurityContextHolder this will process the
+ FilterChain as the Subject in the
+ JaasAuthenticationToken
+ RememberMeAuthenticationFilter, so that if no earlier
authentication processing mechanism updated the
diff --git a/samples/jaas/jaas.gradle b/samples/jaas/jaas.gradle
index c6a6031108..0714ace274 100644
--- a/samples/jaas/jaas.gradle
+++ b/samples/jaas/jaas.gradle
@@ -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",
diff --git a/samples/jaas/src/main/java/samples/jaas/UsernameEqualsPasswordLoginModule.java b/samples/jaas/src/main/java/samples/jaas/UsernameEqualsPasswordLoginModule.java
index 213ed42b8b..2dca7dbeae 100644
--- a/samples/jaas/src/main/java/samples/jaas/UsernameEqualsPasswordLoginModule.java
+++ b/samples/jaas/src/main/java/samples/jaas/UsernameEqualsPasswordLoginModule.java
@@ -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;
}
diff --git a/samples/jaas/src/main/resources/applicationContext-security.xml b/samples/jaas/src/main/resources/applicationContext-security.xml
index d658938c7b..34b854e325 100644
--- a/samples/jaas/src/main/resources/applicationContext-security.xml
+++ b/samples/jaas/src/main/resources/applicationContext-security.xml
@@ -9,7 +9,7 @@
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd">
-
+
diff --git a/samples/jaas/src/main/webapp/index.jsp b/samples/jaas/src/main/webapp/index.jsp
index f0dfc20ac8..06e2b29ee6 100644
--- a/samples/jaas/src/main/webapp/index.jsp
+++ b/samples/jaas/src/main/webapp/index.jsp
@@ -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" %>
@@ -9,6 +11,9 @@ Anyone can view this page.
Your principal object is....: <%= request.getUserPrincipal() %>
+ <%} %>
+
<%
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
if (auth != null) { %>
diff --git a/web/src/main/java/org/springframework/security/web/authentication/jaas/JaasApiIntegrationFilter.java b/web/src/main/java/org/springframework/security/web/authentication/jaas/JaasApiIntegrationFilter.java
new file mode 100644
index 0000000000..b2bdba2ce1
--- /dev/null
+++ b/web/src/main/java/org/springframework/security/web/authentication/jaas/JaasApiIntegrationFilter.java
@@ -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;
+
+/**
+ *
+ * A Filter which attempts to obtain a JAAS Subject
+ * and continue the FilterChain running as that
+ * Subject.
+ *
+ *
+ * By using this Filter in conjunction with Spring's
+ * JaasAuthenticationProvider both Spring's
+ * SecurityContext and a JAAS Subject can be populated
+ * simultaneously. This is useful when integrating with code that requires a
+ * JAAS Subject to be populated.
+ *
+ * Attempts to obtain and run as a JAAS Subject using
+ * {@link #obtainSubject(ServletRequest)}.
+ *
+ *
+ *
+ * If the Subject is null and
+ * createEmptySubject is true, an empty, writeable
+ * Subject is used. This allows for the Subject to
+ * be populated at the time of login. If the Subject is
+ * null, the FilterChain continues with no
+ * additional processing. If the Subject is not
+ * null, the FilterChain is ran with
+ * {@link Subject#doAs(Subject, PrivilegedExceptionAction)} in conjunction
+ * with the Subject obtained.
+ *
+ */
+ 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