Compare commits
100 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b45f7b9585 | |||
| 3c178a339e | |||
| 70b3a330ef | |||
| 17bef05c3c | |||
| d8ed429370 | |||
| 4d282cbe0d | |||
| 7412fe0748 | |||
| d0c4e6ca72 | |||
| fba4fec84b | |||
| 7bc87cf13b | |||
| d89ace26ab | |||
| 743960d2d8 | |||
| d8727638ab | |||
| ebba8ac514 | |||
| 896339087f | |||
| d6524feb62 | |||
| 34893cd53a | |||
| 407b08956b | |||
| dd554e1842 | |||
| c0921b9ede | |||
| e469c93f9d | |||
| f594ed76db | |||
| 6ebb9abfb7 | |||
| 66357a2077 | |||
| 5eb5c91d86 | |||
| b014020955 | |||
| 9eb34fe51c | |||
| e8661913d1 | |||
| f8ed3791f9 | |||
| 2a86c72436 | |||
| 047448464b | |||
| 914ec45e43 | |||
| 83f1d76c16 | |||
| 0722c8c4eb | |||
| 960564ef50 | |||
| 3656dff720 | |||
| c02a1486c0 | |||
| 5f9dfb73be | |||
| 66d13642b7 | |||
| 6b81f97081 | |||
| 01ea39ce35 | |||
| 89c63fd752 | |||
| 036e0505b3 | |||
| d06eae9967 | |||
| 73ea8b5c05 | |||
| 7edb1089a8 | |||
| ebb82e1aa9 | |||
| 2e8a61660d | |||
| 22e333b9c6 | |||
| 9c4563285e | |||
| c8d45397fe | |||
| d04cf5ea68 | |||
| 1a650acbcc | |||
| 3437ef714a | |||
| 796de42105 | |||
| 70849aa8d2 | |||
| ece4a0f067 | |||
| 3fe7791266 | |||
| 5ba31dfd56 | |||
| 373fe3a9f1 | |||
| 6e47834d77 | |||
| eaf4843474 | |||
| d40ecba9e0 | |||
| 593e512558 | |||
| 1ed643ca1f | |||
| 1a7aaa85c4 | |||
| 51fd83060e | |||
| 30780baf24 | |||
| f61fab3509 | |||
| ea6b444770 | |||
| 4c50d1f5de | |||
| 091549779c | |||
| ace6b804f7 | |||
| c0dfb70ca0 | |||
| 78cbdd2c93 | |||
| 6cea2694dc | |||
| c2499c6143 | |||
| ac472d494a | |||
| c076f0f2e1 | |||
| f3b143f677 | |||
| 72aecaff05 | |||
| d3339a1e32 | |||
| f38df99730 | |||
| 4f741bc914 | |||
| 2c234b92ec | |||
| 9883c0e60b | |||
| 906da97594 | |||
| 8a54d597af | |||
| 9e35e4aab4 | |||
| 0a2fa03160 | |||
| c53fd99430 | |||
| 0e97e67083 | |||
| dbc88f3226 | |||
| abe5e4af48 | |||
| 191fc9c8be | |||
| 6af3e1958b | |||
| a45ec0df2b | |||
| c2def26c3e | |||
| 4fabe939d0 | |||
| 8c22b9be46 |
+186
@@ -0,0 +1,186 @@
|
||||
_Have something you'd like to contribute to the framework? We welcome pull requests, but ask that you carefully read this document first to understand how best to submit them; what kind of changes are likely to be accepted; and what to expect from the Spring Security team when evaluating your submission._
|
||||
|
||||
_Please refer back to this document as a checklist before issuing any pull request; this will save time for everyone!_
|
||||
|
||||
# Similar but different
|
||||
|
||||
Each Spring module is slightly different than another in terms of team size, number of issues, etc. Therefore each project is managed slightly different. You will notice that this document is very similar to the [Spring Framework Contributor guidelines](https://github.com/SpringSource/spring-framework/wiki/Contributor-guidelines). However, there are some subtle differences between the two documents, so please be sure to read this document thoroughly.
|
||||
|
||||
# Understand the basics
|
||||
Not sure what a pull request is, or how to submit one? Take a look at GitHub's excellent [help documentation first](https://help.github.com/articles/using-pull-requests).
|
||||
|
||||
# Search JIRA first; create an issue if necessary
|
||||
Is there already an issue that addresses your concern? Do a bit of searching in our [JIRA issue tracker](https://jira.springsource.org/browse/SEC) to see if you can find something similar. If not, please create a new issue before submitting a pull request unless the change is not a user facing issue.
|
||||
|
||||
# Discuss non-trivial contribution ideas with committers
|
||||
If you're considering anything more than correcting a typo or fixing a minor bug , please discuss it on the [Spring Security forums](http://forum.springsource.org/forumdisplay.php?33-Security) before submitting a pull request. We're happy to provide guidance but please spend an hour or two researching the subject on your own including searching the forums for prior discussions.
|
||||
|
||||
# Sign the Contributor License Agreement
|
||||
If you have not previously done so, please fill out and submit the SpringSource CLA form. You'll receive a token when this process is complete. Keep track of this, you may be asked for it later!
|
||||
|
||||
* For **Project** select _Spring Security_
|
||||
* For **Project Lead** enter _Rob Winch_
|
||||
* Note that emailing/postal mailing a signed copy is not necessary. Submission of the web form is all that is required.
|
||||
|
||||
When you've completed the web form, simply add the following in a comment on your pull request:
|
||||
|
||||
> I have signed and agree to the terms of the SpringSource Individual Contributor License Agreement.
|
||||
|
||||
You do not need to include your token/id. Please add the statement above to all future pull requests as well, simply so the Spring Security team knows immediately that this process is complete.
|
||||
|
||||
# Create your branch from master
|
||||
Create your topic branch to be submitted as a pull request from master. The Spring team will consider your pull request for backporting on a case-by-case basis; you don't need to worry about submitting anything for backporting.
|
||||
|
||||
# Use short branch names
|
||||
Branches used when submitting pull requests should preferably be named according to JIRA issues, e.g. 'SEC-1234'. Otherwise, use succinct, lower-case, dash (-) delimited names, such as 'fix-warnings', 'fix-typo', etc. This is important, because branch names show up in the merge commits that result from accepting pull requests, and should be as expressive and concise as possible.
|
||||
|
||||
#Keep commits focused
|
||||
|
||||
Remember each JIRA should be focused on a single item of interest since the JIRA tickets are used to produce the changelog. Since each commit should be tied to a JIRA, ensure that your commits are focused. For example, do not include an update to a transitive library in your commit unless the JIRA is to update the library. Reviewing your commits is essential before sending a pull request.
|
||||
|
||||
# Mind the whitespace
|
||||
Please carefully follow the whitespace and formatting conventions already present in the framework.
|
||||
|
||||
1. Spaces, not tabs
|
||||
1. Unix (LF), not dos (CRLF) line endings
|
||||
1. Eliminate all trailing whitespace
|
||||
1. Aim to wrap code at 120 characters, but favor readability over wrapping
|
||||
1. Preserve existing formatting; i.e. do not reformat code for its own sake
|
||||
1. Search the codebase using git grep and other tools to discover common naming conventions, etc.
|
||||
1. Latin-1 (ISO-8859-1) encoding for Java sources; use native2ascii to convert if necessary
|
||||
|
||||
Whitespace management tips
|
||||
|
||||
1. You can use the [AnyEdit Eclipse plugin](http://marketplace.eclipse.org/content/anyedit-tools) to ensure spaces are used and to clean up trailing whitespaces.
|
||||
1. Use git's pre-commit.sample hook to prevent invalid whitespace from being pushed out. You can enable it by moving ~/spring-security/.git/hooks/pre-commit.sample to ~/spring-security/.git/hooks/pre-commit and ensuring it is executable. For more information on hooks refer to [Pro Git's Pre-Commit Hook's section](http://git-scm.com/book/cs/ch7-3.html)
|
||||
|
||||
# Add Apache license header to all new classes
|
||||
|
||||
<pre>
|
||||
/*
|
||||
* Copyright 2002-2012 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 ...;
|
||||
</pre>
|
||||
# Update Apache license header to modified files as necessary
|
||||
Always check the date range in the license header. For example, if you've modified a file in 2012 whose header still reads
|
||||
<pre>
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
</pre>
|
||||
then be sure to update it to 2012 appropriately
|
||||
<pre>
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
</pre>
|
||||
# Use @since tags for newly-added public API types and methods
|
||||
e.g.
|
||||
<pre>
|
||||
/**
|
||||
* ...
|
||||
*
|
||||
* @author First Last
|
||||
* @since 3.2
|
||||
* @see ...
|
||||
*/
|
||||
</pre>
|
||||
|
||||
#Submit JUnit test cases for all behavior changes
|
||||
Search the codebase to find related unit tests and add additional `@Test` methods within.
|
||||
|
||||
1. Any new tests should end in the name Tests (note this is plural). For example, a valid name would be `FilterChainProxyTests`. An invalid name would be `FilterChainProxyTest`.
|
||||
2. New test methods should not start with test. This is an old JUnit3 convention and is not necessary since the method is annotated with @Test.
|
||||
|
||||
# Squash commits
|
||||
Use git rebase --interactive, git add --patch and other tools to "squash" multiple commits into atomic changes. In addition to the man pages for git, there are many resources online to help you understand how these tools work. Here is one: http://book.git-scm.com/4_interactive_rebasing.html.
|
||||
|
||||
# Use real name in git commits
|
||||
Please configure git to use your real first and last name for any commits you intend to submit as pull requests. For example, this is not acceptable:
|
||||
|
||||
<pre>
|
||||
Author: Nickname <user@mail.com>
|
||||
</pre>
|
||||
Rather, please include your first and last name, properly capitalized, as submitted against the SpringSource contributor license agreement:
|
||||
<pre>
|
||||
Author: First Last <user@mail.com>
|
||||
</pre>
|
||||
This helps ensure traceability against the CLA, and also goes a long way to ensuring useful output from tools like git shortlog and others.
|
||||
|
||||
You can configure this globally via the account admin area GitHub (useful for fork-and-edit cases); globally with
|
||||
|
||||
<pre>
|
||||
git config --global user.name "First Last"
|
||||
git config --global user.email user@mail.com
|
||||
</pre>
|
||||
|
||||
or locally for the spring-security repository only by omitting the '--global' flag:
|
||||
<pre>
|
||||
cd spring-security
|
||||
git config user.name "First Last"
|
||||
git config user.email user@mail.com
|
||||
</pre>
|
||||
|
||||
# Format commit messages
|
||||
|
||||
<pre>
|
||||
SEC-1234: Short (50 chars or less) summary of changes
|
||||
|
||||
More detailed explanatory text, if necessary. Wrap it to about 72
|
||||
characters or so. In some contexts, the first line is treated as the
|
||||
subject of an email and the rest of the text as the body. The blank
|
||||
line separating the summary from the body is critical (unless you omit
|
||||
the body entirely); tools like rebase can get confused if you run the
|
||||
two together.
|
||||
|
||||
Further paragraphs come after blank lines.
|
||||
|
||||
- Bullet points are okay, too
|
||||
|
||||
- Typically a hyphen or asterisk is used for the bullet, preceded by a
|
||||
single space, with blank lines in between, but conventions vary here
|
||||
</pre>
|
||||
|
||||
|
||||
1. The commit subject should start with the associated jira issue followed by a : as shown in the example above
|
||||
2. Keep the subject line to 50 characters or less if possible
|
||||
3. Do not end the subject line with a period
|
||||
4. In the body of the commit message, explain how things worked before this commit, what has changed, and how things work now
|
||||
|
||||
# Run all tests prior to submission
|
||||
|
||||
<pre>
|
||||
cd spring-security
|
||||
./gradlew clean build integrationTest
|
||||
</pre>
|
||||
|
||||
# Submit your pull request
|
||||
Subject line:
|
||||
|
||||
Follow the same conventions for pull request subject lines as mentioned above for commit message subject lines.
|
||||
|
||||
In the body:
|
||||
|
||||
1. Explain your use case. What led you to submit this change? Why were existing mechanisms in the framework insufficient? Make a case that this is a general-purpose problem and that yours is a general-purpose solution, etc
|
||||
2. Add any additional information and ask questions; start a conversation, or continue one from JIRA
|
||||
3. Mention the JIRA issue ID
|
||||
4. Also mention that you have submitted the CLA as described above
|
||||
Note that for pull requests containing a single commit, GitHub will default the subject line and body of the pull request to match the subject line and body of the commit message. This is fine, but please also include the items above in the body of the request.
|
||||
|
||||
# Mention your pull request on the associated JIRA issue
|
||||
Add a comment to the associated JIRA issue(s) linking to your new pull request.
|
||||
|
||||
# Expect discussion and rework
|
||||
The Spring team takes a very conservative approach to accepting contributions to the framework. This is to keep code quality and stability as high as possible, and to keep complexity at a minimum. Your changes, if accepted, may be heavily modified prior to merging. You will retain "Author:" attribution for your Git commits granted that the bulk of your changes remain intact. You may be asked to rework the submission for style (as explained above) and/or substance. Again, we strongly recommend discussing any serious submissions with the Spring Framework team prior to engaging in serious development work.
|
||||
|
||||
Note that you can always force push (git push -f) reworked / rebased commits against the branch used to submit your pull request. i.e. you do not need to issue a new pull request when asked to make changes.
|
||||
@@ -5,6 +5,7 @@ dependencies {
|
||||
'aopalliance:aopalliance:1.0',
|
||||
"net.sf.ehcache:ehcache:$ehcacheVersion",
|
||||
"org.springframework:spring-aop:$springVersion",
|
||||
"org.springframework:spring-beans:$springVersion",
|
||||
"org.springframework:spring-context:$springVersion",
|
||||
"org.springframework:spring-tx:$springVersion",
|
||||
"org.springframework:spring-jdbc:$springVersion"
|
||||
|
||||
+8
-4
@@ -31,10 +31,14 @@ import org.springframework.util.Assert;
|
||||
/**
|
||||
* Default implementation of {@link AclAuthorizationStrategy}.
|
||||
* <p>
|
||||
* Permission will be granted provided the current principal is either the owner (as defined by the ACL), has
|
||||
* {@link BasePermission#ADMINISTRATION} (as defined by the ACL and via a {@link Sid} retrieved for the current
|
||||
* principal via {@link #sidRetrievalStrategy}), or if the current principal holds the relevant system-wide
|
||||
* {@link GrantedAuthority} and injected into the constructor.
|
||||
* Permission will be granted if at least one of the following conditions is true for the current
|
||||
* principal.
|
||||
* <ul>
|
||||
* <li> is the owner (as defined by the ACL). </li>
|
||||
* <li> holds the relevant system-wide {@link GrantedAuthority} injected into the
|
||||
* constructor. </li>
|
||||
* <li> has {@link BasePermission#ADMINISTRATION} permission (as defined by the ACL). </li>
|
||||
* </ul>
|
||||
*
|
||||
* @author Ben Alex
|
||||
*/
|
||||
|
||||
+130
@@ -0,0 +1,130 @@
|
||||
/*
|
||||
* Copyright 2002-2013 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.acls.domain;
|
||||
|
||||
import org.springframework.cache.Cache;
|
||||
import org.springframework.security.acls.model.AclCache;
|
||||
import org.springframework.security.acls.model.MutableAcl;
|
||||
import org.springframework.security.acls.model.ObjectIdentity;
|
||||
import org.springframework.security.acls.model.PermissionGrantingStrategy;
|
||||
import org.springframework.security.util.FieldUtils;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
|
||||
/**
|
||||
* Simple implementation of {@link org.springframework.security.acls.model.AclCache} that delegates to {@link Cache} implementation.
|
||||
* <p>
|
||||
* Designed to handle the transient fields in {@link org.springframework.security.acls.domain.AclImpl}. Note that this implementation assumes all
|
||||
* {@link org.springframework.security.acls.domain.AclImpl} instances share the same {@link org.springframework.security.acls.model.PermissionGrantingStrategy} and {@link org.springframework.security.acls.domain.AclAuthorizationStrategy}
|
||||
* instances.
|
||||
*
|
||||
* @author Marten Deinum
|
||||
* @since 3.2
|
||||
*/
|
||||
public class SpringCacheBasedAclCache implements AclCache {
|
||||
//~ Instance fields ================================================================================================
|
||||
|
||||
private final Cache cache;
|
||||
private PermissionGrantingStrategy permissionGrantingStrategy;
|
||||
private AclAuthorizationStrategy aclAuthorizationStrategy;
|
||||
|
||||
//~ Constructors ===================================================================================================
|
||||
|
||||
public SpringCacheBasedAclCache(Cache cache, PermissionGrantingStrategy permissionGrantingStrategy,
|
||||
AclAuthorizationStrategy aclAuthorizationStrategy) {
|
||||
Assert.notNull(cache, "Cache required");
|
||||
Assert.notNull(permissionGrantingStrategy, "PermissionGrantingStrategy required");
|
||||
Assert.notNull(aclAuthorizationStrategy, "AclAuthorizationStrategy required");
|
||||
this.cache = cache;
|
||||
this.permissionGrantingStrategy = permissionGrantingStrategy;
|
||||
this.aclAuthorizationStrategy = aclAuthorizationStrategy;
|
||||
}
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
public void evictFromCache(Serializable pk) {
|
||||
Assert.notNull(pk, "Primary key (identifier) required");
|
||||
|
||||
MutableAcl acl = getFromCache(pk);
|
||||
|
||||
if (acl != null) {
|
||||
cache.evict(acl.getId());
|
||||
cache.evict(acl.getObjectIdentity());
|
||||
}
|
||||
}
|
||||
|
||||
public void evictFromCache(ObjectIdentity objectIdentity) {
|
||||
Assert.notNull(objectIdentity, "ObjectIdentity required");
|
||||
|
||||
MutableAcl acl = getFromCache(objectIdentity);
|
||||
|
||||
if (acl != null) {
|
||||
cache.evict(acl.getId());
|
||||
cache.evict(acl.getObjectIdentity());
|
||||
}
|
||||
}
|
||||
|
||||
public MutableAcl getFromCache(ObjectIdentity objectIdentity) {
|
||||
Assert.notNull(objectIdentity, "ObjectIdentity required");
|
||||
return getFromCache((Object)objectIdentity);
|
||||
}
|
||||
|
||||
public MutableAcl getFromCache(Serializable pk) {
|
||||
Assert.notNull(pk, "Primary key (identifier) required");
|
||||
return getFromCache((Object)pk);
|
||||
}
|
||||
|
||||
public void putInCache(MutableAcl acl) {
|
||||
Assert.notNull(acl, "Acl required");
|
||||
Assert.notNull(acl.getObjectIdentity(), "ObjectIdentity required");
|
||||
Assert.notNull(acl.getId(), "ID required");
|
||||
|
||||
if ((acl.getParentAcl() != null) && (acl.getParentAcl() instanceof MutableAcl)) {
|
||||
putInCache((MutableAcl) acl.getParentAcl());
|
||||
}
|
||||
|
||||
cache.put(acl.getObjectIdentity(), acl);
|
||||
cache.put(acl.getId(), acl);
|
||||
}
|
||||
|
||||
private MutableAcl getFromCache(Object key) {
|
||||
Cache.ValueWrapper element = cache.get(key);
|
||||
|
||||
if (element == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return initializeTransientFields((MutableAcl) element.get());
|
||||
}
|
||||
|
||||
private MutableAcl initializeTransientFields(MutableAcl value) {
|
||||
if (value instanceof AclImpl) {
|
||||
FieldUtils.setProtectedFieldValue("aclAuthorizationStrategy", value, this.aclAuthorizationStrategy);
|
||||
FieldUtils.setProtectedFieldValue("permissionGrantingStrategy", value, this.permissionGrantingStrategy);
|
||||
}
|
||||
|
||||
if (value.getParentAcl() != null) {
|
||||
initializeTransientFields((MutableAcl) value.getParentAcl());
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
public void clearCache() {
|
||||
cache.clear();
|
||||
}
|
||||
}
|
||||
+142
@@ -0,0 +1,142 @@
|
||||
package org.springframework.security.acls.jdbc;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import org.springframework.cache.Cache;
|
||||
import org.springframework.cache.CacheManager;
|
||||
import org.springframework.cache.concurrent.ConcurrentMapCacheManager;
|
||||
import org.springframework.security.acls.domain.*;
|
||||
import org.springframework.security.acls.model.MutableAcl;
|
||||
import org.springframework.security.acls.model.ObjectIdentity;
|
||||
import org.springframework.security.acls.model.PermissionGrantingStrategy;
|
||||
import org.springframework.security.authentication.TestingAuthenticationToken;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.util.FieldUtils;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* Tests {@link org.springframework.security.acls.domain.SpringCacheBasedAclCache}
|
||||
*
|
||||
* @author Marten Deinum
|
||||
*/
|
||||
public class SpringCacheBasedAclCacheTests {
|
||||
private static final String TARGET_CLASS = "org.springframework.security.acls.TargetObject";
|
||||
|
||||
private static CacheManager cacheManager;
|
||||
|
||||
@BeforeClass
|
||||
public static void initCacheManaer() {
|
||||
cacheManager = new ConcurrentMapCacheManager();
|
||||
// Use disk caching immediately (to test for serialization issue reported in SEC-527)
|
||||
cacheManager.getCache("springcasebasedacltests");
|
||||
}
|
||||
|
||||
@After
|
||||
public void clearContext() {
|
||||
SecurityContextHolder.clearContext();
|
||||
}
|
||||
|
||||
private Cache getCache() {
|
||||
Cache cache = cacheManager.getCache("springcasebasedacltests");
|
||||
cache.clear();
|
||||
return cache;
|
||||
}
|
||||
|
||||
@Test(expected=IllegalArgumentException.class)
|
||||
public void constructorRejectsNullParameters() throws Exception {
|
||||
new SpringCacheBasedAclCache(null, null, null);
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
@Test
|
||||
public void cacheOperationsAclWithoutParent() throws Exception {
|
||||
Cache cache = getCache();
|
||||
Map realCache = (Map) cache.getNativeCache();
|
||||
ObjectIdentity identity = new ObjectIdentityImpl(TARGET_CLASS, Long.valueOf(100));
|
||||
AclAuthorizationStrategy aclAuthorizationStrategy = new AclAuthorizationStrategyImpl(
|
||||
new SimpleGrantedAuthority("ROLE_OWNERSHIP"), new SimpleGrantedAuthority("ROLE_AUDITING"),
|
||||
new SimpleGrantedAuthority("ROLE_GENERAL"));
|
||||
AuditLogger auditLogger = new ConsoleAuditLogger();
|
||||
|
||||
PermissionGrantingStrategy permissionGrantingStrategy = new DefaultPermissionGrantingStrategy(auditLogger);
|
||||
SpringCacheBasedAclCache myCache = new SpringCacheBasedAclCache(cache, permissionGrantingStrategy, aclAuthorizationStrategy);
|
||||
MutableAcl acl = new AclImpl(identity, Long.valueOf(1), aclAuthorizationStrategy, auditLogger);
|
||||
|
||||
assertEquals(0, realCache.size());
|
||||
myCache.putInCache(acl);
|
||||
|
||||
// Check we can get from cache the same objects we put in
|
||||
assertEquals(myCache.getFromCache(Long.valueOf(1)), acl);
|
||||
assertEquals(myCache.getFromCache(identity), acl);
|
||||
|
||||
// Put another object in cache
|
||||
ObjectIdentity identity2 = new ObjectIdentityImpl(TARGET_CLASS, Long.valueOf(101));
|
||||
MutableAcl acl2 = new AclImpl(identity2, Long.valueOf(2), aclAuthorizationStrategy, new ConsoleAuditLogger());
|
||||
|
||||
myCache.putInCache(acl2);
|
||||
|
||||
// Try to evict an entry that doesn't exist
|
||||
myCache.evictFromCache(Long.valueOf(3));
|
||||
myCache.evictFromCache(new ObjectIdentityImpl(TARGET_CLASS, Long.valueOf(102)));
|
||||
assertEquals(realCache.size(), 4);
|
||||
|
||||
myCache.evictFromCache(Long.valueOf(1));
|
||||
assertEquals(realCache.size(), 2);
|
||||
|
||||
// Check the second object inserted
|
||||
assertEquals(myCache.getFromCache(Long.valueOf(2)), acl2);
|
||||
assertEquals(myCache.getFromCache(identity2), acl2);
|
||||
|
||||
myCache.evictFromCache(identity2);
|
||||
assertEquals(realCache.size(), 0);
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
@Test
|
||||
public void cacheOperationsAclWithParent() throws Exception {
|
||||
Cache cache = getCache();
|
||||
Map realCache = (Map) cache.getNativeCache();
|
||||
|
||||
Authentication auth = new TestingAuthenticationToken("user", "password", "ROLE_GENERAL");
|
||||
auth.setAuthenticated(true);
|
||||
SecurityContextHolder.getContext().setAuthentication(auth);
|
||||
|
||||
ObjectIdentity identity = new ObjectIdentityImpl(TARGET_CLASS, Long.valueOf(1));
|
||||
ObjectIdentity identityParent = new ObjectIdentityImpl(TARGET_CLASS, Long.valueOf(2));
|
||||
AclAuthorizationStrategy aclAuthorizationStrategy = new AclAuthorizationStrategyImpl(
|
||||
new SimpleGrantedAuthority("ROLE_OWNERSHIP"), new SimpleGrantedAuthority("ROLE_AUDITING"),
|
||||
new SimpleGrantedAuthority("ROLE_GENERAL"));
|
||||
AuditLogger auditLogger = new ConsoleAuditLogger();
|
||||
|
||||
PermissionGrantingStrategy permissionGrantingStrategy = new DefaultPermissionGrantingStrategy(auditLogger);
|
||||
SpringCacheBasedAclCache myCache = new SpringCacheBasedAclCache(cache, permissionGrantingStrategy, aclAuthorizationStrategy);
|
||||
|
||||
MutableAcl acl = new AclImpl(identity, Long.valueOf(1), aclAuthorizationStrategy, auditLogger);
|
||||
MutableAcl parentAcl = new AclImpl(identityParent, Long.valueOf(2), aclAuthorizationStrategy, auditLogger);
|
||||
|
||||
acl.setParent(parentAcl);
|
||||
|
||||
assertEquals(0, realCache.size());
|
||||
myCache.putInCache(acl);
|
||||
assertEquals(realCache.size(), 4);
|
||||
|
||||
// Check we can get from cache the same objects we put in
|
||||
AclImpl aclFromCache = (AclImpl) myCache.getFromCache(Long.valueOf(1));
|
||||
assertEquals(acl, aclFromCache);
|
||||
// SEC-951 check transient fields are set on parent
|
||||
assertNotNull(FieldUtils.getFieldValue(aclFromCache.getParentAcl(), "aclAuthorizationStrategy"));
|
||||
assertNotNull(FieldUtils.getFieldValue(aclFromCache.getParentAcl(), "permissionGrantingStrategy"));
|
||||
assertEquals(acl, myCache.getFromCache(identity));
|
||||
assertNotNull(FieldUtils.getFieldValue(aclFromCache, "aclAuthorizationStrategy"));
|
||||
AclImpl parentAclFromCache = (AclImpl) myCache.getFromCache(Long.valueOf(2));
|
||||
assertEquals(parentAcl, parentAclFromCache);
|
||||
assertNotNull(FieldUtils.getFieldValue(parentAclFromCache, "aclAuthorizationStrategy"));
|
||||
assertEquals(parentAcl, myCache.getFromCache(identityParent));
|
||||
}
|
||||
}
|
||||
@@ -11,6 +11,7 @@ Ignored-Existing-Headers:
|
||||
Import-Template:
|
||||
org.aopalliance.*;version="${aopAllianceRange}",
|
||||
org.apache.commons.logging.*;version="${cloggingRange}",
|
||||
org.springframework.cache.*;version="${springRange}";resolution:=optional,
|
||||
org.springframework.security.core.*;version="${secRange}",
|
||||
org.springframework.security.access.*;version="${secRange}",
|
||||
org.springframework.security.util.*;version="${secRange}",
|
||||
|
||||
+9
-2
@@ -9,8 +9,10 @@ allprojects {
|
||||
group = 'org.springframework.security'
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
maven { url "http://repo.springsource.org/libs-release" }
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
// Set up different subproject lists for individual configuration
|
||||
@@ -20,8 +22,13 @@ ext.itestProjects = subprojects.findAll { project -> project.name.startsWith('it
|
||||
ext.coreModuleProjects = javaProjects - sampleProjects - itestProjects
|
||||
ext.aspectjProjects = [project(':spring-security-aspects'), project(':spring-security-samples-aspectj')]
|
||||
|
||||
configure(subprojects - coreModuleProjects) {
|
||||
tasks.findByPath("artifactoryPublish")?.enabled = false
|
||||
}
|
||||
|
||||
configure(javaProjects) {
|
||||
apply from: "$rootDir/gradle/javaprojects.gradle"
|
||||
apply from: "$rootDir/gradle/release-checks.gradle"
|
||||
}
|
||||
|
||||
configure(coreModuleProjects) {
|
||||
@@ -75,5 +82,5 @@ artifacts {
|
||||
apply from: "$rootDir/gradle/ide-integration.gradle"
|
||||
|
||||
task wrapper(type: Wrapper) {
|
||||
gradleVersion = '1.0'
|
||||
gradleVersion = '1.3'
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
apply plugin: 'groovy'
|
||||
|
||||
repositories {
|
||||
mavenLocal()
|
||||
mavenCentral()
|
||||
maven {
|
||||
name = 'SpringSource Enterprise Release'
|
||||
@@ -50,6 +49,12 @@ dependencies {
|
||||
'com.springsource.bundlor:com.springsource.bundlor.blint:1.0.0.RELEASE'
|
||||
}
|
||||
|
||||
// Trang
|
||||
dependencies {
|
||||
compile 'com.thaiopensource:trang:20091111',
|
||||
'net.sourceforge.saxon:saxon:9.1.0.8'
|
||||
}
|
||||
|
||||
task ide(type: Copy) {
|
||||
from configurations.runtime
|
||||
into 'ide'
|
||||
|
||||
@@ -11,6 +11,7 @@ import org.gradle.api.GradleException
|
||||
|
||||
import org.gradle.plugins.ide.eclipse.GenerateEclipseProject
|
||||
import org.gradle.plugins.ide.eclipse.GenerateEclipseClasspath
|
||||
import org.gradle.plugins.ide.eclipse.EclipsePlugin
|
||||
import org.gradle.plugins.ide.eclipse.model.BuildCommand
|
||||
import org.gradle.plugins.ide.eclipse.model.ProjectDependency
|
||||
|
||||
@@ -63,8 +64,13 @@ class AspectJPlugin implements Plugin<Project> {
|
||||
project.tasks.withType(GenerateEclipseClasspath) {
|
||||
project.eclipse.classpath.file.whenMerged { classpath ->
|
||||
def entries = classpath.entries.findAll { it instanceof ProjectDependency}.findAll { entry ->
|
||||
def projectPath = entry.path.replaceAll('/',':')
|
||||
project.rootProject.findProject(projectPath).plugins.findPlugin(AspectJPlugin)
|
||||
def projectPath = entry.path.replaceAll('/','')
|
||||
project.rootProject.allprojects.find{ p->
|
||||
if(p.plugins.findPlugin(EclipsePlugin)) {
|
||||
return p.eclipse.project.name == projectPath && p.plugins.findPlugin(AspectJPlugin)
|
||||
}
|
||||
false
|
||||
}
|
||||
}
|
||||
entries.each { entry->
|
||||
entry.entryAttributes.put('org.eclipse.ajdt.aspectpath','org.eclipse.ajdt.aspectpath')
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
package trang;
|
||||
|
||||
import com.thaiopensource.relaxng.translate.Driver
|
||||
|
||||
import javax.xml.transform.Transformer
|
||||
import javax.xml.transform.TransformerFactory
|
||||
import javax.xml.transform.stream.StreamSource
|
||||
import javax.xml.transform.stream.StreamResult
|
||||
|
||||
import org.gradle.api.*;
|
||||
import org.gradle.api.tasks.*
|
||||
import org.gradle.api.file.FileCollection
|
||||
|
||||
/**
|
||||
* Used for converting .rnc files to .xsd files.
|
||||
* @author Rob Winch
|
||||
*/
|
||||
class TrangPlugin implements Plugin<Project> {
|
||||
public void apply(Project project) {
|
||||
Task rncToXsd = project.tasks.add('rncToXsd', RncToXsd.class)
|
||||
rncToXsd.description = 'Converts .rnc to .xsd'
|
||||
rncToXsd.group = 'Build'
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts .rnc files to .xsd files using trang and then applies an xsl file to cleanup the results.
|
||||
*/
|
||||
public class RncToXsd extends DefaultTask {
|
||||
@InputDirectory
|
||||
File rncDir
|
||||
|
||||
@InputFile
|
||||
File xslFile
|
||||
|
||||
@OutputDirectory
|
||||
File xsdDir
|
||||
|
||||
@TaskAction
|
||||
public final void transform() {
|
||||
String xslPath = xslFile.absolutePath
|
||||
rncDir.listFiles( { dir, file -> file.endsWith('.rnc')} as FilenameFilter).each { rncFile ->
|
||||
File xsdFile = new File(xsdDir, rncFile.name.replace('.rnc', '.xsd'))
|
||||
String xsdOutputPath = xsdFile.absolutePath
|
||||
new Driver().run([rncFile.absolutePath, xsdOutputPath] as String[]);
|
||||
|
||||
TransformerFactory tFactory = new net.sf.saxon.TransformerFactoryImpl()
|
||||
Transformer transformer =
|
||||
tFactory.newTransformer(new StreamSource(xslPath))
|
||||
File temp = File.createTempFile("gradle-trang-" + xsdFile.name, ".xsd")
|
||||
xsdFile.withInputStream { is ->
|
||||
temp << is
|
||||
}
|
||||
StreamSource xmlSource = new StreamSource(temp)
|
||||
transformer.transform(xmlSource, new StreamResult(xsdFile))
|
||||
temp.delete()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
implementation-class=trang.TrangPlugin
|
||||
+2
-2
@@ -8,5 +8,5 @@ dependencies {
|
||||
"org.jasig.cas.client:cas-client-core:3.1.12",
|
||||
"net.sf.ehcache:ehcache:$ehcacheVersion"
|
||||
|
||||
provided 'javax.servlet:servlet-api:2.5'
|
||||
}
|
||||
provided "org.apache.tomcat:tomcat-servlet-api:$servletApiVersion"
|
||||
}
|
||||
+80
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright 2002-2013 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.cas.authentication;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.cache.Cache;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
|
||||
/**
|
||||
* Caches tickets using a Spring IoC defined {@link Cache}.
|
||||
*
|
||||
* @author Marten Deinum
|
||||
* @since 3.2
|
||||
*
|
||||
*/
|
||||
public class SpringCacheBasedTicketCache implements StatelessTicketCache {
|
||||
//~ Static fields/initializers =====================================================================================
|
||||
|
||||
private static final Log logger = LogFactory.getLog(SpringCacheBasedTicketCache.class);
|
||||
|
||||
//~ Instance fields ================================================================================================
|
||||
|
||||
private final Cache cache;
|
||||
|
||||
//~ Constructors ===================================================================================================
|
||||
|
||||
public SpringCacheBasedTicketCache(Cache cache) throws Exception {
|
||||
Assert.notNull(cache, "cache mandatory");
|
||||
this.cache = cache;
|
||||
}
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
public CasAuthenticationToken getByTicketId(final String serviceTicket) {
|
||||
final Cache.ValueWrapper element = serviceTicket != null ? cache.get(serviceTicket) : null;
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Cache hit: " + (element != null) + "; service ticket: " + serviceTicket);
|
||||
}
|
||||
|
||||
return element == null ? null : (CasAuthenticationToken) element.get();
|
||||
}
|
||||
|
||||
public void putTicketInCache(final CasAuthenticationToken token) {
|
||||
String key = token.getCredentials().toString();
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Cache put: " + key);
|
||||
}
|
||||
|
||||
cache.put(key, token);
|
||||
}
|
||||
|
||||
public void removeTicketFromCache(final CasAuthenticationToken token) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Cache remove: " + token.getCredentials().toString());
|
||||
}
|
||||
|
||||
this.removeTicketFromCache(token.getCredentials().toString());
|
||||
}
|
||||
|
||||
public void removeTicketFromCache(final String serviceTicket) {
|
||||
cache.evict(serviceTicket);
|
||||
}
|
||||
}
|
||||
+66
@@ -0,0 +1,66 @@
|
||||
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
|
||||
*
|
||||
* 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.cas.authentication;
|
||||
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import org.springframework.cache.CacheManager;
|
||||
import org.springframework.cache.concurrent.ConcurrentMapCacheManager;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
|
||||
/**
|
||||
* Tests {@link org.springframework.security.cas.authentication.SpringCacheBasedTicketCache}.
|
||||
*
|
||||
* @author Marten Deinum
|
||||
* @since 3.2
|
||||
*/
|
||||
public class SpringCacheBasedTicketCacheTests extends AbstractStatelessTicketCacheTests {
|
||||
private static CacheManager cacheManager;
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
@BeforeClass
|
||||
public static void initCacheManaer() {
|
||||
cacheManager = new ConcurrentMapCacheManager();
|
||||
cacheManager.getCache("castickets");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCacheOperation() throws Exception {
|
||||
SpringCacheBasedTicketCache cache = new SpringCacheBasedTicketCache(cacheManager.getCache("castickets"));
|
||||
|
||||
final CasAuthenticationToken token = getToken();
|
||||
|
||||
// Check it gets stored in the cache
|
||||
cache.putTicketInCache(token);
|
||||
assertEquals(token, cache.getByTicketId("ST-0-ER94xMJmn6pha35CQRoZ"));
|
||||
|
||||
// Check it gets removed from the cache
|
||||
cache.removeTicketFromCache(getToken());
|
||||
assertNull(cache.getByTicketId("ST-0-ER94xMJmn6pha35CQRoZ"));
|
||||
|
||||
// Check it doesn't return values for null or unknown service tickets
|
||||
assertNull(cache.getByTicketId(null));
|
||||
assertNull(cache.getByTicketId("UNKNOWN_SERVICE_TICKET"));
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void testStartupDetectsMissingCache() throws Exception {
|
||||
new SpringCacheBasedTicketCache(null);
|
||||
}
|
||||
}
|
||||
@@ -15,6 +15,7 @@ Import-Template:
|
||||
org.springframework.security.authentication.*;version="${secRange}",
|
||||
org.springframework.security.web.*;version="${secRange}",
|
||||
org.springframework.beans.factory;version="${springRange}",
|
||||
org.springframework.cache.*;version="${springRange}";resolution:=optional,
|
||||
org.springframework.context.*;version="${springRange}",
|
||||
org.springframework.dao;version="${springRange}",
|
||||
org.springframework.util;version="${springRange}",
|
||||
|
||||
+28
-10
@@ -1,6 +1,7 @@
|
||||
// Config Module build file
|
||||
|
||||
apply plugin: 'groovy'
|
||||
apply plugin: 'trang'
|
||||
|
||||
compileTestJava.dependsOn(':spring-security-core:compileTestJava')
|
||||
|
||||
@@ -14,33 +15,42 @@ dependencies {
|
||||
// NB: Don't add other compile time dependencies to the config module as this breaks tooling
|
||||
compile project(':spring-security-core'),
|
||||
project(':spring-security-web'),
|
||||
project(':spring-security-openid'),
|
||||
project(':spring-security-ldap'),
|
||||
"org.aspectj:aspectjweaver:$aspectjVersion",
|
||||
'aopalliance:aopalliance:1.0',
|
||||
"org.springframework:spring-aop:$springVersion",
|
||||
"org.springframework:spring-context:$springVersion",
|
||||
"org.springframework:spring-web:$springVersion",
|
||||
"org.springframework:spring-beans:$springVersion"
|
||||
"org.springframework:spring-beans:$springVersion",
|
||||
"org.springframework:spring-jdbc:$springVersion",
|
||||
"org.springframework:spring-tx:$springVersion",
|
||||
"org.springframework.ldap:spring-ldap-core:$springLdapVersion"
|
||||
compile('org.openid4java:openid4java-nodeps:0.9.6') {
|
||||
exclude group: 'com.google.code.guice', module: 'guice'
|
||||
}
|
||||
compile 'com.google.inject:guice:2.0'
|
||||
compile apacheds_libs
|
||||
|
||||
provided "javax.servlet:servlet-api:2.5"
|
||||
provided "org.apache.tomcat:tomcat-servlet-api:$servletApiVersion"
|
||||
|
||||
groovy group: 'org.codehaus.groovy', name: 'groovy', version: '1.7.10'
|
||||
groovy 'org.codehaus.groovy:groovy:1.8.7'
|
||||
|
||||
testCompile project(':spring-security-ldap'),
|
||||
project(':spring-security-openid'),
|
||||
project(':spring-security-cas'),
|
||||
project(':spring-security-core').sourceSets.test.output,
|
||||
'javax.annotation:jsr250-api:1.0',
|
||||
"org.springframework.ldap:spring-ldap-core:$springLdapVersion",
|
||||
"org.springframework:spring-expression:$springVersion",
|
||||
"org.springframework:spring-jdbc:$springVersion",
|
||||
"org.springframework:spring-orm:$springVersion",
|
||||
"org.springframework:spring-tx:$springVersion",
|
||||
'org.spockframework:spock-core:0.5-groovy-1.7',
|
||||
'org.spockframework:spock-core:0.6-groovy-1.8',
|
||||
"org.slf4j:jcl-over-slf4j:$slf4jVersion",
|
||||
"org.powermock:powermock-core:$powerMockVersion",
|
||||
"org.powermock:powermock-api-support:$powerMockVersion",
|
||||
"org.powermock:powermock-module-junit4-common:$powerMockVersion",
|
||||
"org.powermock:powermock-module-junit4:$powerMockVersion",
|
||||
"org.powermock:powermock-api-mockito:$powerMockVersion",
|
||||
"org.powermock:powermock-reflect:$powerMockVersion"
|
||||
"org.hibernate.javax.persistence:hibernate-jpa-2.0-api:1.0.1.Final",
|
||||
"org.hibernate:hibernate-entitymanager:4.1.0.Final",
|
||||
powerMockDependencies
|
||||
testCompile('org.openid4java:openid4java-nodeps:0.9.6') {
|
||||
exclude group: 'com.google.code.guice', module: 'guice'
|
||||
}
|
||||
@@ -57,3 +67,11 @@ test {
|
||||
integrationTest {
|
||||
systemProperties['apacheDSWorkDir'] = "${buildDir}/apacheDSWork"
|
||||
}
|
||||
|
||||
rncToXsd {
|
||||
rncDir = file('src/main/resources/org/springframework/security/config/')
|
||||
xsdDir = rncDir
|
||||
xslFile = new File(rncDir, 'spring-security.xsl')
|
||||
}
|
||||
|
||||
build.dependsOn rncToXsd
|
||||
@@ -1,11 +0,0 @@
|
||||
#! /bin/sh
|
||||
|
||||
pushd src/main/resources/org/springframework/security/config/
|
||||
|
||||
echo "Converting rnc file to xsd ..."
|
||||
java -jar ~/bin/trang.jar spring-security-3.1.rnc spring-security-3.1.xsd
|
||||
|
||||
echo "Applying XSL transformation to xsd ..."
|
||||
xsltproc --output spring-security-3.1.xsd spring-security.xsl spring-security-3.1.xsd
|
||||
|
||||
popd
|
||||
+177
@@ -0,0 +1,177 @@
|
||||
/*
|
||||
* Copyright 2002-2013 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.config.annotation.authentication.ldap
|
||||
|
||||
import org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory;
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
import org.springframework.context.annotation.Bean
|
||||
import org.springframework.context.annotation.Configuration
|
||||
import org.springframework.ldap.core.ContextSource;
|
||||
import org.springframework.ldap.core.support.BaseLdapPathContextSource;
|
||||
import org.springframework.security.authentication.AuthenticationManager
|
||||
import org.springframework.security.authentication.AuthenticationProvider
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken
|
||||
import org.springframework.security.config.annotation.BaseSpringSpec
|
||||
import org.springframework.security.config.annotation.SecurityBuilder;
|
||||
import org.springframework.security.config.annotation.authentication.AuthenticationManagerBuilder
|
||||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
||||
import org.springframework.security.ldap.DefaultSpringSecurityContextSource;
|
||||
import org.springframework.security.ldap.authentication.LdapAuthenticationProvider;
|
||||
import org.springframework.security.ldap.server.ApacheDSContainer;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Rob Winch
|
||||
*
|
||||
*/
|
||||
class LdapAuthenticationProviderBuilderSecurityBuilderTests extends BaseSpringSpec {
|
||||
def "default configuration"() {
|
||||
when:
|
||||
loadConfig(DefaultLdapConfig)
|
||||
LdapAuthenticationProvider provider = ldapProvider()
|
||||
then:
|
||||
provider.authoritiesPopulator.groupRoleAttribute == "cn"
|
||||
provider.authoritiesPopulator.groupSearchBase == ""
|
||||
provider.authoritiesPopulator.groupSearchFilter == "(uniqueMember={0})"
|
||||
ReflectionTestUtils.getField(provider,"authoritiesMapper").prefix == "ROLE_"
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class DefaultLdapConfig extends BaseLdapProviderConfig {
|
||||
protected void registerAuthentication(
|
||||
AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth
|
||||
.ldapAuthentication()
|
||||
.contextSource(contextSource())
|
||||
}
|
||||
}
|
||||
|
||||
def "group roles custom"() {
|
||||
when:
|
||||
loadConfig(GroupRolesConfig)
|
||||
LdapAuthenticationProvider provider = ldapProvider()
|
||||
then:
|
||||
provider.authoritiesPopulator.groupRoleAttribute == "group"
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class GroupRolesConfig extends BaseLdapProviderConfig {
|
||||
protected void registerAuthentication(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth
|
||||
.ldapAuthentication()
|
||||
.contextSource(contextSource())
|
||||
.groupRoleAttribute("group")
|
||||
}
|
||||
}
|
||||
|
||||
def "group search custom"() {
|
||||
when:
|
||||
loadConfig(GroupSearchConfig)
|
||||
LdapAuthenticationProvider provider = ldapProvider()
|
||||
then:
|
||||
provider.authoritiesPopulator.groupSearchFilter == "ou=groupName"
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class GroupSearchConfig extends BaseLdapProviderConfig {
|
||||
protected void registerAuthentication(
|
||||
AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth
|
||||
.ldapAuthentication()
|
||||
.contextSource(contextSource())
|
||||
.groupSearchFilter("ou=groupName");
|
||||
}
|
||||
}
|
||||
|
||||
def "role prefix custom"() {
|
||||
when:
|
||||
loadConfig(RolePrefixConfig)
|
||||
LdapAuthenticationProvider provider = ldapProvider()
|
||||
then:
|
||||
ReflectionTestUtils.getField(provider,"authoritiesMapper").prefix == "role_"
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class RolePrefixConfig extends BaseLdapProviderConfig {
|
||||
protected void registerAuthentication(
|
||||
AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth
|
||||
.ldapAuthentication()
|
||||
.contextSource(contextSource())
|
||||
.rolePrefix("role_")
|
||||
}
|
||||
}
|
||||
|
||||
def "bind authentication"() {
|
||||
when:
|
||||
loadConfig(BindAuthenticationConfig)
|
||||
AuthenticationManager auth = context.getBean(AuthenticationManager)
|
||||
then:
|
||||
auth
|
||||
auth.authenticate(new UsernamePasswordAuthenticationToken("admin","password")).authorities.collect { it.authority }.sort() == ["ROLE_ADMIN","ROLE_USER"]
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class BindAuthenticationConfig extends BaseLdapServerConfig {
|
||||
protected void registerAuthentication(
|
||||
AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth
|
||||
.ldapAuthentication()
|
||||
.contextSource(contextSource())
|
||||
.groupSearchBase("ou=groups")
|
||||
.userDnPatterns("uid={0},ou=people");
|
||||
}
|
||||
}
|
||||
|
||||
def ldapProvider() {
|
||||
context.getBean(AuthenticationManager).providers[0]
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static abstract class BaseLdapServerConfig extends BaseLdapProviderConfig {
|
||||
@Bean
|
||||
public ApacheDSContainer ldapServer() throws Exception {
|
||||
ApacheDSContainer apacheDSContainer = new ApacheDSContainer("dc=springframework,dc=org", "classpath:/users.ldif");
|
||||
apacheDSContainer.setPort(33389);
|
||||
return apacheDSContainer;
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static abstract class BaseLdapProviderConfig {
|
||||
@Bean
|
||||
public AuthenticationManager authenticationManager() {
|
||||
AuthenticationManagerBuilder registry = new AuthenticationManagerBuilder();
|
||||
registerAuthentication(registry);
|
||||
return registry.build();
|
||||
}
|
||||
|
||||
protected abstract void registerAuthentication(
|
||||
AuthenticationManagerBuilder auth) throws Exception;
|
||||
|
||||
@Bean
|
||||
public BaseLdapPathContextSource contextSource() throws Exception {
|
||||
DefaultSpringSecurityContextSource contextSource = new DefaultSpringSecurityContextSource(
|
||||
"ldap://127.0.0.1:33389/dc=springframework,dc=org")
|
||||
contextSource.userDn = "uid=admin,ou=system"
|
||||
contextSource.password = "secret"
|
||||
contextSource.afterPropertiesSet();
|
||||
return contextSource;
|
||||
}
|
||||
}
|
||||
}
|
||||
+68
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright 2002-2013 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.config.annotation.authentication.ldap
|
||||
|
||||
import static org.springframework.security.config.annotation.authentication.ldap.NamespaceLdapAuthenticationProviderTestsConfigs.*
|
||||
|
||||
import org.springframework.ldap.core.support.BaseLdapPathContextSource
|
||||
import org.springframework.security.authentication.AuthenticationManager
|
||||
import org.springframework.security.authentication.AuthenticationProvider
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken
|
||||
import org.springframework.security.config.annotation.BaseSpringSpec
|
||||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
||||
import org.springframework.security.config.annotation.authentication.ldap.NamespaceLdapAuthenticationProviderTestsConfigs.LdapAuthenticationProviderConfig;
|
||||
import org.springframework.security.ldap.authentication.LdapAuthenticationProvider;
|
||||
import org.springframework.security.ldap.authentication.PasswordComparisonAuthenticator;
|
||||
import org.springframework.security.ldap.userdetails.PersonContextMapper;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Rob Winch
|
||||
*
|
||||
*/
|
||||
class NamespaceLdapAuthenticationProviderTests extends BaseSpringSpec {
|
||||
def "ldap-authentication-provider"() {
|
||||
when:
|
||||
loadConfig(LdapAuthenticationProviderConfig)
|
||||
then:
|
||||
authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("user","password")).authorities*.authority.sort() == ['ROLE_USER']
|
||||
}
|
||||
|
||||
def "ldap-authentication-provider custom"() {
|
||||
when:
|
||||
loadConfig(CustomLdapAuthenticationProviderConfig)
|
||||
LdapAuthenticationProvider provider = findAuthenticationProvider(LdapAuthenticationProvider)
|
||||
then:
|
||||
provider.authoritiesPopulator.groupRoleAttribute == "cn"
|
||||
provider.authoritiesPopulator.groupSearchBase == "ou=groups"
|
||||
provider.authoritiesPopulator.groupSearchFilter == "(member={0})"
|
||||
ReflectionTestUtils.getField(provider,"authoritiesMapper").prefix == "PREFIX_"
|
||||
provider.userDetailsContextMapper instanceof PersonContextMapper
|
||||
provider.authenticator.getUserDns("user") == ["uid=user,ou=people"]
|
||||
provider.authenticator.userSearch.searchBase == "ou=users"
|
||||
provider.authenticator.userSearch.searchFilter == "(uid={0})"
|
||||
}
|
||||
|
||||
def "ldap-authentication-provider password compare"() {
|
||||
when:
|
||||
loadConfig(PasswordCompareLdapConfig)
|
||||
LdapAuthenticationProvider provider = findAuthenticationProvider(LdapAuthenticationProvider)
|
||||
then:
|
||||
provider.authenticator instanceof PasswordComparisonAuthenticator
|
||||
authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("user","password")).authorities*.authority.sort() == ['ROLE_USER']
|
||||
}
|
||||
}
|
||||
+84
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Copyright 2002-2013 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.config.annotation.authentication.ldap;
|
||||
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.authentication.encoding.PlaintextPasswordEncoder;
|
||||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
import org.springframework.security.ldap.userdetails.PersonContextMapper;
|
||||
|
||||
/**
|
||||
* @author Rob Winch
|
||||
*
|
||||
*/
|
||||
public class NamespaceLdapAuthenticationProviderTestsConfigs {
|
||||
|
||||
@Configuration
|
||||
@EnableWebSecurity
|
||||
static class LdapAuthenticationProviderConfig extends WebSecurityConfigurerAdapter {
|
||||
protected void registerAuthentication(
|
||||
AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth
|
||||
.ldapAuthentication()
|
||||
.groupSearchBase("ou=groups")
|
||||
.userDnPatterns("uid={0},ou=people"); // ldap-server@user-dn-pattern
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableWebSecurity
|
||||
static class CustomLdapAuthenticationProviderConfig extends WebSecurityConfigurerAdapter {
|
||||
protected void registerAuthentication(
|
||||
AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth
|
||||
.ldapAuthentication()
|
||||
.groupRoleAttribute("cn") // ldap-authentication-provider@group-role-attribute
|
||||
.groupSearchBase("ou=groups") // ldap-authentication-provider@group-search-base
|
||||
.groupSearchFilter("(member={0})") // ldap-authentication-provider@group-search-filter
|
||||
.rolePrefix("PREFIX_") // ldap-authentication-provider@group-search-filter
|
||||
.userDetailsContextMapper(new PersonContextMapper()) // ldap-authentication-provider@user-context-mapper-ref / ldap-authentication-provider@user-details-class
|
||||
.userDnPatterns("uid={0},ou=people") // ldap-authentication-provider@user-dn-pattern
|
||||
.userSearchBase("ou=users") // ldap-authentication-provider@user-dn-pattern
|
||||
.userSearchFilter("(uid={0})") // ldap-authentication-provider@user-search-filter
|
||||
// .contextSource(contextSource) // ldap-authentication-provider@server-ref
|
||||
.contextSource()
|
||||
.ldif("classpath:user.ldif") // ldap-server@ldif
|
||||
.managerDn("uid=admin,ou=system") // ldap-server@manager-dn
|
||||
.managerPassword("secret") // ldap-server@manager-password
|
||||
.port(33399) // ldap-server@port
|
||||
.root("dc=springframework,dc=org") // ldap-server@root
|
||||
// .url("ldap://localhost:33389/dc-springframework,dc=org") this overrides root and port and is used for external
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableWebSecurity
|
||||
static class PasswordCompareLdapConfig extends WebSecurityConfigurerAdapter {
|
||||
protected void registerAuthentication(
|
||||
AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth
|
||||
.ldapAuthentication()
|
||||
.groupSearchBase("ou=groups")
|
||||
.userSearchFilter("(uid={0})")
|
||||
.passwordCompare()
|
||||
.passwordEncoder(new PlaintextPasswordEncoder()) // ldap-authentication-provider/password-compare/password-encoder@ref
|
||||
.passwordAttribute("userPassword"); // ldap-authentication-provider/password-compare@password-attribute
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
dn: ou=groups,dc=springframework,dc=org
|
||||
objectclass: top
|
||||
objectclass: organizationalUnit
|
||||
ou: groups
|
||||
|
||||
dn: ou=people,dc=springframework,dc=org
|
||||
objectclass: top
|
||||
objectclass: organizationalUnit
|
||||
ou: people
|
||||
|
||||
dn: uid=admin,ou=people,dc=springframework,dc=org
|
||||
objectclass: top
|
||||
objectclass: person
|
||||
objectclass: organizationalPerson
|
||||
objectclass: inetOrgPerson
|
||||
cn: Rod Johnson
|
||||
sn: Johnson
|
||||
uid: admin
|
||||
userPassword: password
|
||||
|
||||
dn: uid=user,ou=people,dc=springframework,dc=org
|
||||
objectclass: top
|
||||
objectclass: person
|
||||
objectclass: organizationalPerson
|
||||
objectclass: inetOrgPerson
|
||||
cn: Dianne Emu
|
||||
sn: Emu
|
||||
uid: user
|
||||
userPassword: password
|
||||
|
||||
dn: cn=user,ou=groups,dc=springframework,dc=org
|
||||
objectclass: top
|
||||
objectclass: groupOfNames
|
||||
cn: user
|
||||
uniqueMember: uid=admin,ou=people,dc=springframework,dc=org
|
||||
uniqueMember: uid=user,ou=people,dc=springframework,dc=org
|
||||
|
||||
dn: cn=admin,ou=groups,dc=springframework,dc=org
|
||||
objectclass: top
|
||||
objectclass: groupOfNames
|
||||
cn: admin
|
||||
uniqueMember: uid=admin,ou=people,dc=springframework,dc=org
|
||||
+21
-5
@@ -1,5 +1,23 @@
|
||||
/*
|
||||
* Copyright 2009-2013 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.config;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
@@ -28,8 +46,6 @@ import org.springframework.util.ClassUtils;
|
||||
import org.w3c.dom.Element;
|
||||
import org.w3c.dom.Node;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Parses elements from the "security" namespace (http://www.springframework.org/schema/security).
|
||||
*
|
||||
@@ -65,8 +81,8 @@ public final class SecurityNamespaceHandler implements NamespaceHandler {
|
||||
|
||||
public BeanDefinition parse(Element element, ParserContext pc) {
|
||||
if (!namespaceMatchesVersion(element)) {
|
||||
pc.getReaderContext().fatal("You cannot use a spring-security-2.0.xsd or spring-security-3.0.xsd schema " +
|
||||
"with Spring Security 3.1. Please update your schema declarations to the 3.1 schema.", element);
|
||||
pc.getReaderContext().fatal("You cannot use a spring-security-2.0.xsd or spring-security-3.0.xsd or spring-security-3.1.xsd schema " +
|
||||
"with Spring Security 3.2. Please update your schema declarations to the 3.2 schema.", element);
|
||||
}
|
||||
String name = pc.getDelegate().getLocalName(element);
|
||||
BeanDefinitionParser parser = parsers.get(name);
|
||||
@@ -180,7 +196,7 @@ public final class SecurityNamespaceHandler implements NamespaceHandler {
|
||||
|
||||
private boolean matchesVersionInternal(Element element) {
|
||||
String schemaLocation = element.getAttributeNS("http://www.w3.org/2001/XMLSchema-instance", "schemaLocation");
|
||||
return schemaLocation.matches("(?m).*spring-security-3\\.1.*.xsd.*")
|
||||
return schemaLocation.matches("(?m).*spring-security-3\\.2.*.xsd.*")
|
||||
|| schemaLocation.matches("(?m).*spring-security.xsd.*")
|
||||
|| !schemaLocation.matches("(?m).*spring-security.*");
|
||||
}
|
||||
|
||||
+432
@@ -0,0 +1,432 @@
|
||||
/*
|
||||
* Copyright 2002-2013 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.config.annotation;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.security.config.annotation.web.builders.WebSecurity;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.web.filter.DelegatingFilterProxy;
|
||||
|
||||
import com.google.inject.internal.ImmutableList.Builder;
|
||||
|
||||
/**
|
||||
* <p>A base {@link SecurityBuilder} that allows {@link SecurityConfigurer} to be
|
||||
* applied to it. This makes modifying the {@link SecurityBuilder} a strategy
|
||||
* that can be customized and broken up into a number of
|
||||
* {@link SecurityConfigurer} objects that have more specific goals than that
|
||||
* of the {@link SecurityBuilder}.</p>
|
||||
*
|
||||
* <p>For example, a {@link SecurityBuilder} may build an
|
||||
* {@link DelegatingFilterProxy}, but a {@link SecurityConfigurer} might
|
||||
* populate the {@link SecurityBuilder} with the filters necessary for session
|
||||
* management, form based login, authorization, etc.</p>
|
||||
*
|
||||
* @see WebSecurity
|
||||
*
|
||||
* @author Rob Winch
|
||||
*
|
||||
* @param <O>
|
||||
* The object that this builder returns
|
||||
* @param <B>
|
||||
* The type of this builder (that is returned by the base class)
|
||||
*/
|
||||
public abstract class AbstractConfiguredSecurityBuilder<O, B extends SecurityBuilder<O>> extends AbstractSecurityBuilder<O> {
|
||||
|
||||
private final LinkedHashMap<Class<? extends SecurityConfigurer<O, B>>, List<SecurityConfigurer<O, B>>> configurers =
|
||||
new LinkedHashMap<Class<? extends SecurityConfigurer<O, B>>, List<SecurityConfigurer<O, B>>>();
|
||||
|
||||
private final Map<Class<Object>,Object> sharedObjects = new HashMap<Class<Object>,Object>();
|
||||
|
||||
private final boolean allowConfigurersOfSameType;
|
||||
|
||||
private BuildState buildState = BuildState.UNBUILT;
|
||||
|
||||
private ObjectPostProcessor<Object> objectPostProcessor;
|
||||
|
||||
/**
|
||||
* Creates a new instance without post processing
|
||||
*/
|
||||
protected AbstractConfiguredSecurityBuilder() {
|
||||
this(ObjectPostProcessor.QUIESCENT_POSTPROCESSOR);
|
||||
}
|
||||
|
||||
/***
|
||||
* Creates a new instance with the provided {@link ObjectPostProcessor}.
|
||||
* This post processor must support Object since there are many types of
|
||||
* objects that may be post processed.
|
||||
*
|
||||
* @param objectPostProcessor the {@link ObjectPostProcessor} to use
|
||||
*/
|
||||
protected AbstractConfiguredSecurityBuilder(ObjectPostProcessor<Object> objectPostProcessor) {
|
||||
this(objectPostProcessor,false);
|
||||
}
|
||||
|
||||
/***
|
||||
* Creates a new instance with the provided {@link ObjectPostProcessor}.
|
||||
* This post processor must support Object since there are many types of
|
||||
* objects that may be post processed.
|
||||
*
|
||||
* @param objectPostProcessor the {@link ObjectPostProcessor} to use
|
||||
* @param allowConfigurersOfSameType if true, will not override other {@link SecurityConfigurer}'s when performing apply
|
||||
*/
|
||||
protected AbstractConfiguredSecurityBuilder(ObjectPostProcessor<Object> objectPostProcessor, boolean allowConfigurersOfSameType) {
|
||||
Assert.notNull(objectPostProcessor, "objectPostProcessor cannot be null");
|
||||
this.objectPostProcessor = objectPostProcessor;
|
||||
this.allowConfigurersOfSameType = allowConfigurersOfSameType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies a {@link SecurityConfigurerAdapter} to this
|
||||
* {@link SecurityBuilder} and invokes
|
||||
* {@link SecurityConfigurerAdapter#setBuilder(SecurityBuilder)}.
|
||||
*
|
||||
* @param configurer
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public <C extends SecurityConfigurerAdapter<O, B>> C apply(C configurer)
|
||||
throws Exception {
|
||||
add(configurer);
|
||||
configurer.addObjectPostProcessor(objectPostProcessor);
|
||||
configurer.setBuilder((B) this);
|
||||
return configurer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies a {@link SecurityConfigurer} to this {@link SecurityBuilder}
|
||||
* overriding any {@link SecurityConfigurer} of the exact same class. Note
|
||||
* that object hierarchies are not considered.
|
||||
*
|
||||
* @param configurer
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
public <C extends SecurityConfigurer<O, B>> C apply(C configurer)
|
||||
throws Exception {
|
||||
add(configurer);
|
||||
return configurer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets an object that is shared by multiple {@link SecurityConfigurer}.
|
||||
*
|
||||
* @param sharedType the Class to key the shared object by.
|
||||
* @param object the Object to store
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public <C> void setSharedObject(Class<C> sharedType, C object) {
|
||||
this.sharedObjects.put((Class<Object>) sharedType, object);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a shared Object. Note that object heirarchies are not considered.
|
||||
*
|
||||
* @param sharedType the type of the shared Object
|
||||
* @return the shared Object or null if it is not found
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public <C> C getSharedObject(Class<C> sharedType) {
|
||||
return (C) this.sharedObjects.get(sharedType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the shared objects
|
||||
* @return
|
||||
*/
|
||||
public Map<Class<Object>,Object> getSharedObjects() {
|
||||
return Collections.unmodifiableMap(this.sharedObjects);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds {@link SecurityConfigurer} ensuring that it is allowed and
|
||||
* invoking {@link SecurityConfigurer#init(SecurityBuilder)} immediately
|
||||
* if necessary.
|
||||
*
|
||||
* @param configurer the {@link SecurityConfigurer} to add
|
||||
* @throws Exception if an error occurs
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private <C extends SecurityConfigurer<O, B>> void add(C configurer) throws Exception {
|
||||
Assert.notNull(configurer, "configurer cannot be null");
|
||||
|
||||
Class<? extends SecurityConfigurer<O, B>> clazz = (Class<? extends SecurityConfigurer<O, B>>) configurer
|
||||
.getClass();
|
||||
synchronized(configurers) {
|
||||
if(buildState.isConfigured()) {
|
||||
throw new IllegalStateException("Cannot apply "+configurer+" to already built object");
|
||||
}
|
||||
List<SecurityConfigurer<O, B>> configs = allowConfigurersOfSameType ? this.configurers.get(clazz) : null;
|
||||
if(configs == null) {
|
||||
configs = new ArrayList<SecurityConfigurer<O,B>>(1);
|
||||
}
|
||||
configs.add(configurer);
|
||||
this.configurers.put(clazz, configs);
|
||||
if(buildState.isInitializing()) {
|
||||
configurer.init((B)this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all the {@link SecurityConfigurer} instances by its class name or an
|
||||
* empty List if not found. Note that object hierarchies are not considered.
|
||||
*
|
||||
* @param clazz the {@link SecurityConfigurer} class to look for
|
||||
* @return
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public <C extends SecurityConfigurer<O, B>> List<C> getConfigurers(
|
||||
Class<C> clazz) {
|
||||
List<C> configs = (List<C>) this.configurers.get(clazz);
|
||||
if(configs == null) {
|
||||
return new ArrayList<C>();
|
||||
}
|
||||
return new ArrayList<C>(configs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all the {@link SecurityConfigurer} instances by its class name or an
|
||||
* empty List if not found. Note that object hierarchies are not considered.
|
||||
*
|
||||
* @param clazz the {@link SecurityConfigurer} class to look for
|
||||
* @return
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public <C extends SecurityConfigurer<O, B>> List<C> removeConfigurers(
|
||||
Class<C> clazz) {
|
||||
List<C> configs = (List<C>) this.configurers.remove(clazz);
|
||||
if(configs == null) {
|
||||
return new ArrayList<C>();
|
||||
}
|
||||
return new ArrayList<C>(configs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the {@link SecurityConfigurer} by its class name or
|
||||
* <code>null</code> if not found. Note that object hierarchies are not
|
||||
* considered.
|
||||
*
|
||||
* @param clazz
|
||||
* @return
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public <C extends SecurityConfigurer<O, B>> C getConfigurer(
|
||||
Class<C> clazz) {
|
||||
List<SecurityConfigurer<O,B>> configs = this.configurers.get(clazz);
|
||||
if(configs == null) {
|
||||
return null;
|
||||
}
|
||||
if(configs.size() != 1) {
|
||||
throw new IllegalStateException("Only one configurer expected for type " + clazz + ", but got " + configs);
|
||||
}
|
||||
return (C) configs.get(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes and returns the {@link SecurityConfigurer} by its class name or
|
||||
* <code>null</code> if not found. Note that object hierarchies are not
|
||||
* considered.
|
||||
*
|
||||
* @param clazz
|
||||
* @return
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public <C extends SecurityConfigurer<O,B>> C removeConfigurer(Class<C> clazz) {
|
||||
List<SecurityConfigurer<O,B>> configs = this.configurers.remove(clazz);
|
||||
if(configs == null) {
|
||||
return null;
|
||||
}
|
||||
if(configs.size() != 1) {
|
||||
throw new IllegalStateException("Only one configurer expected for type " + clazz + ", but got " + configs);
|
||||
}
|
||||
return (C) configs.get(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies the {@link ObjectPostProcessor} to use.
|
||||
* @param objectPostProcessor the {@link ObjectPostProcessor} to use. Cannot be null
|
||||
* @return the {@link SecurityBuilder} for further customizations
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public O objectPostProcessor(ObjectPostProcessor<Object> objectPostProcessor) {
|
||||
Assert.notNull(objectPostProcessor,"objectPostProcessor cannot be null");
|
||||
this.objectPostProcessor = objectPostProcessor;
|
||||
return (O) this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs post processing of an object. The default is to delegate to the
|
||||
* {@link ObjectPostProcessor}.
|
||||
*
|
||||
* @param object the Object to post process
|
||||
* @return the possibly modified Object to use
|
||||
*/
|
||||
protected <P> P postProcess(P object) {
|
||||
return (P) this.objectPostProcessor.postProcess(object);
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the build using the {@link SecurityConfigurer}'s that have been applied using the following steps:
|
||||
*
|
||||
* <ul>
|
||||
* <li>Invokes {@link #beforeInit()} for any subclass to hook into</li>
|
||||
* <li>Invokes {@link SecurityConfigurer#init(SecurityBuilder)} for any {@link SecurityConfigurer} that was applied to this builder.</li>
|
||||
* <li>Invokes {@link #beforeConfigure()} for any subclass to hook into</li>
|
||||
* <li>Invokes {@link #performBuild()} which actually builds the Object</li>
|
||||
* </ul>
|
||||
*/
|
||||
@Override
|
||||
protected final O doBuild() throws Exception {
|
||||
synchronized(configurers) {
|
||||
buildState = BuildState.INITIALIZING;
|
||||
|
||||
beforeInit();
|
||||
init();
|
||||
|
||||
buildState = BuildState.CONFIGURING;
|
||||
|
||||
beforeConfigure();
|
||||
configure();
|
||||
|
||||
buildState = BuildState.BUILDING;
|
||||
|
||||
O result = performBuild();
|
||||
|
||||
buildState = BuildState.BUILT;
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoked prior to invoking each
|
||||
* {@link SecurityConfigurer#init(SecurityBuilder)} method. Subclasses may
|
||||
* override this method to hook into the lifecycle without using a
|
||||
* {@link SecurityConfigurer}.
|
||||
*/
|
||||
protected void beforeInit() throws Exception {
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoked prior to invoking each
|
||||
* {@link SecurityConfigurer#configure(SecurityBuilder)} method.
|
||||
* Subclasses may override this method to hook into the lifecycle without
|
||||
* using a {@link SecurityConfigurer}.
|
||||
*/
|
||||
protected void beforeConfigure() throws Exception {
|
||||
}
|
||||
|
||||
/**
|
||||
* Subclasses must implement this method to build the object that is being returned.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
protected abstract O performBuild() throws Exception;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void init() throws Exception {
|
||||
Collection<SecurityConfigurer<O,B>> configurers = getConfigurers();
|
||||
|
||||
for(SecurityConfigurer<O,B> configurer : configurers ) {
|
||||
configurer.init((B) this);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void configure() throws Exception {
|
||||
Collection<SecurityConfigurer<O,B>> configurers = getConfigurers();
|
||||
|
||||
for(SecurityConfigurer<O,B> configurer : configurers ) {
|
||||
configurer.configure((B) this);
|
||||
}
|
||||
}
|
||||
|
||||
private Collection<SecurityConfigurer<O, B>> getConfigurers() {
|
||||
List<SecurityConfigurer<O,B>> result = new ArrayList<SecurityConfigurer<O,B>>();
|
||||
for(List<SecurityConfigurer<O,B>> configs : this.configurers.values()) {
|
||||
result.addAll(configs);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* The build state for the application
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @since 3.2
|
||||
*/
|
||||
private static enum BuildState {
|
||||
/**
|
||||
* This is the state before the {@link Builder#build()} is invoked
|
||||
*/
|
||||
UNBUILT(0),
|
||||
|
||||
/**
|
||||
* The state from when {@link Builder#build()} is first invoked until
|
||||
* all the {@link SecurityConfigurer#init(SecurityBuilder)} methods
|
||||
* have been invoked.
|
||||
*/
|
||||
INITIALIZING(1),
|
||||
|
||||
/**
|
||||
* The state from after all
|
||||
* {@link SecurityConfigurer#init(SecurityBuilder)} have been invoked
|
||||
* until after all the
|
||||
* {@link SecurityConfigurer#configure(SecurityBuilder)} methods have
|
||||
* been invoked.
|
||||
*/
|
||||
CONFIGURING(2),
|
||||
|
||||
/**
|
||||
* From the point after all the
|
||||
* {@link SecurityConfigurer#configure(SecurityBuilder)} have
|
||||
* completed to just after
|
||||
* {@link AbstractConfiguredSecurityBuilder#performBuild()}.
|
||||
*/
|
||||
BUILDING(3),
|
||||
|
||||
/**
|
||||
* After the object has been completely built.
|
||||
*/
|
||||
BUILT(4);
|
||||
|
||||
private final int order;
|
||||
|
||||
BuildState(int order) {
|
||||
this.order = order;
|
||||
}
|
||||
|
||||
public boolean isInitializing() {
|
||||
return INITIALIZING.order == order;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the state is CONFIGURING or later
|
||||
* @return
|
||||
*/
|
||||
public boolean isConfigured() {
|
||||
return order >= CONFIGURING.order;
|
||||
}
|
||||
}
|
||||
}
|
||||
+67
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright 2002-2013 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.config.annotation;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
/**
|
||||
* A base {@link SecurityBuilder} that ensures the object being built is only
|
||||
* built one time.
|
||||
*
|
||||
* @param <O> the type of Object that is being built
|
||||
*
|
||||
* @author Rob Winch
|
||||
*
|
||||
*/
|
||||
public abstract class AbstractSecurityBuilder<O> implements SecurityBuilder<O> {
|
||||
private AtomicBoolean building = new AtomicBoolean();
|
||||
|
||||
private O object;
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.security.config.annotation.SecurityBuilder#build()
|
||||
*/
|
||||
@Override
|
||||
public final O build() throws Exception {
|
||||
if(building.compareAndSet(false, true)) {
|
||||
object = doBuild();
|
||||
return object;
|
||||
}
|
||||
throw new IllegalStateException("This object has already been built");
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the object that was built. If it has not been built yet an Exception
|
||||
* is thrown.
|
||||
*
|
||||
* @return the Object that was built
|
||||
*/
|
||||
public final O getObject() {
|
||||
if(!building.get()) {
|
||||
throw new IllegalStateException("This object has not been built");
|
||||
}
|
||||
return object;
|
||||
}
|
||||
|
||||
/**
|
||||
* Subclasses should implement this to perform the build.
|
||||
*
|
||||
* @return the object that should be returned by {@link #build()}.
|
||||
*
|
||||
* @throws Exception if an error occurs
|
||||
*/
|
||||
protected abstract O doBuild() throws Exception;
|
||||
}
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright 2002-2013 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.config.annotation;
|
||||
|
||||
import org.springframework.beans.factory.Aware;
|
||||
import org.springframework.beans.factory.DisposableBean;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
|
||||
/**
|
||||
* Allows initialization of Objects. Typically this is used to call the
|
||||
* {@link Aware} methods, {@link InitializingBean#afterPropertiesSet()}, and
|
||||
* ensure that {@link DisposableBean#destroy()} has been invoked.
|
||||
*
|
||||
* @param <T> the bound of the types of Objects this {@link ObjectPostProcessor} supports.
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @since 3.2
|
||||
*/
|
||||
public interface ObjectPostProcessor<T> {
|
||||
|
||||
/**
|
||||
* Initialize the object possibly returning a modified instance that should
|
||||
* be used instead.
|
||||
*
|
||||
* @param object the object to initialize
|
||||
* @return the initialized version of the object
|
||||
*/
|
||||
<O extends T> O postProcess(O object);
|
||||
|
||||
/**
|
||||
* A do nothing implementation of the {@link ObjectPostProcessor}
|
||||
*/
|
||||
ObjectPostProcessor<Object> QUIESCENT_POSTPROCESSOR = new ObjectPostProcessor<Object>() {
|
||||
@Override
|
||||
public <T> T postProcess(T object) {
|
||||
return object;
|
||||
}
|
||||
};
|
||||
}
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright 2002-2013 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.config.annotation;
|
||||
|
||||
/**
|
||||
* Interface for building an Object
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @since 3.2
|
||||
*
|
||||
* @param <O> The type of the Object being built
|
||||
*/
|
||||
public interface SecurityBuilder<O> {
|
||||
|
||||
/**
|
||||
* Builds the object and returns it or null.
|
||||
*
|
||||
* @return the Object to be built or null if the implementation allows it.
|
||||
* @throws Exception if an error occured when building the Object
|
||||
*/
|
||||
O build() throws Exception;
|
||||
}
|
||||
+55
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright 2002-2013 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.config.annotation;
|
||||
|
||||
/**
|
||||
* Allows for configuring a {@link SecurityBuilder}. All
|
||||
* {@link SecurityConfigurer} first have their {@link #init(SecurityBuilder)}
|
||||
* method invoked. After all {@link #init(SecurityBuilder)} methods have been
|
||||
* invoked, each {@link #configure(SecurityBuilder)} method is invoked.
|
||||
*
|
||||
* @see AbstractConfiguredSecurityBuilder
|
||||
*
|
||||
* @author Rob Winch
|
||||
*
|
||||
* @param <O>
|
||||
* The object being built by the {@link SecurityBuilder} B
|
||||
* @param <B>
|
||||
* The {@link SecurityBuilder} that builds objects of type O. This is
|
||||
* also the {@link SecurityBuilder} that is being configured.
|
||||
*/
|
||||
public interface SecurityConfigurer<O, B extends SecurityBuilder<O>> {
|
||||
/**
|
||||
* Initialize the {@link SecurityBuilder}. Here only shared state should be
|
||||
* created and modified, but not properties on the {@link SecurityBuilder}
|
||||
* used for building the object. This ensures that the
|
||||
* {@link #configure(SecurityBuilder)} method uses the correct shared
|
||||
* objects when building.
|
||||
*
|
||||
* @param builder
|
||||
* @throws Exception
|
||||
*/
|
||||
void init(B builder) throws Exception;
|
||||
|
||||
/**
|
||||
* Configure the {@link SecurityBuilder} by setting the necessary properties
|
||||
* on the {@link SecurityBuilder}.
|
||||
*
|
||||
* @param builder
|
||||
* @throws Exception
|
||||
*/
|
||||
void configure(B builder) throws Exception;
|
||||
}
|
||||
+135
@@ -0,0 +1,135 @@
|
||||
/*
|
||||
* Copyright 2002-2013 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.config.annotation;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.core.GenericTypeResolver;
|
||||
|
||||
/**
|
||||
* A base class for {@link SecurityConfigurer} that allows subclasses to only
|
||||
* implement the methods they are interested in. It also provides a mechanism
|
||||
* for using the {@link SecurityConfigurer} and when done gaining access to the
|
||||
* {@link SecurityBuilder} that is being configured.
|
||||
*
|
||||
* @author Rob Winch
|
||||
*
|
||||
* @param <O>
|
||||
* The Object being built by B
|
||||
* @param <B>
|
||||
* The Builder that is building O and is configured by {@link SecurityConfigurerAdapter}
|
||||
*/
|
||||
public abstract class SecurityConfigurerAdapter<O,B extends SecurityBuilder<O>> implements SecurityConfigurer<O,B> {
|
||||
private B securityBuilder;
|
||||
|
||||
private CompositeObjectPostProcessor objectPostProcessor = new CompositeObjectPostProcessor();
|
||||
|
||||
@Override
|
||||
public void init(B builder) throws Exception {}
|
||||
|
||||
@Override
|
||||
public void configure(B builder) throws Exception {}
|
||||
|
||||
/**
|
||||
* Return the {@link SecurityBuilder} when done using the
|
||||
* {@link SecurityConfigurer}. This is useful for method chaining.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public B and() {
|
||||
return getBuilder();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the {@link SecurityBuilder}. Cannot be null.
|
||||
*
|
||||
* @return the {@link SecurityBuilder}
|
||||
* @throw {@link IllegalStateException} if {@link SecurityBuilder} is null
|
||||
*/
|
||||
protected final B getBuilder() {
|
||||
if(securityBuilder == null) {
|
||||
throw new IllegalStateException("securityBuilder cannot be null");
|
||||
}
|
||||
return securityBuilder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs post processing of an object. The default is to delegate to the
|
||||
* {@link ObjectPostProcessor}.
|
||||
*
|
||||
* @param object the Object to post process
|
||||
* @return the possibly modified Object to use
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
protected <T> T postProcess(T object) {
|
||||
return (T) this.objectPostProcessor.postProcess(object);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an {@link ObjectPostProcessor} to be used for this
|
||||
* {@link SecurityConfigurerAdapter}. The default implementation does
|
||||
* nothing to the object.
|
||||
*
|
||||
* @param objectPostProcessor the {@link ObjectPostProcessor} to use
|
||||
*/
|
||||
public void addObjectPostProcessor(ObjectPostProcessor<?> objectPostProcessor) {
|
||||
this.objectPostProcessor.addObjectPostProcessor(objectPostProcessor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the {@link SecurityBuilder} to be used. This is automatically set
|
||||
* when using
|
||||
* {@link AbstractConfiguredSecurityBuilder#apply(SecurityConfigurerAdapter)}
|
||||
*
|
||||
* @param builder the {@link SecurityBuilder} to set
|
||||
*/
|
||||
public void setBuilder(B builder) {
|
||||
this.securityBuilder = builder;
|
||||
}
|
||||
|
||||
/**
|
||||
* An {@link ObjectPostProcessor} that delegates work to numerous
|
||||
* {@link ObjectPostProcessor} implementations.
|
||||
*
|
||||
* @author Rob Winch
|
||||
*/
|
||||
private static final class CompositeObjectPostProcessor implements ObjectPostProcessor<Object> {
|
||||
private List<ObjectPostProcessor<? extends Object>> postProcessors = new ArrayList<ObjectPostProcessor<?>>();
|
||||
|
||||
@Override
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
public Object postProcess(Object object) {
|
||||
for(ObjectPostProcessor opp : postProcessors) {
|
||||
Class<?> oppClass = opp.getClass();
|
||||
Class<?> oppType = GenericTypeResolver.resolveTypeArgument(oppClass,ObjectPostProcessor.class);
|
||||
if(oppType == null || oppType.isAssignableFrom(object.getClass())) {
|
||||
object = opp.postProcess(object);
|
||||
}
|
||||
}
|
||||
return object;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an {@link ObjectPostProcessor} to use
|
||||
* @param objectPostProcessor the {@link ObjectPostProcessor} to add
|
||||
* @return true if the {@link ObjectPostProcessor} was added, else false
|
||||
*/
|
||||
private boolean addObjectPostProcessor(ObjectPostProcessor<?extends Object> objectPostProcessor) {
|
||||
return this.postProcessors.add(objectPostProcessor);
|
||||
}
|
||||
}
|
||||
}
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright 2002-2013 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.config.annotation.authentication;
|
||||
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.authentication.AuthenticationProvider;
|
||||
import org.springframework.security.authentication.ProviderManager;
|
||||
import org.springframework.security.config.annotation.SecurityBuilder;
|
||||
|
||||
/**
|
||||
* Interface for operating on a SecurityBuilder that creates a {@link ProviderManager}
|
||||
*
|
||||
* @author Rob Winch
|
||||
*
|
||||
* @param <B> the type of the {@link SecurityBuilder}
|
||||
*/
|
||||
public interface ProviderManagerBuilder<B extends ProviderManagerBuilder<B>> extends SecurityBuilder<AuthenticationManager> {
|
||||
|
||||
/**
|
||||
* Add authentication based upon the custom {@link AuthenticationProvider}
|
||||
* that is passed in. Since the {@link AuthenticationProvider}
|
||||
* implementation is unknown, all customizations must be done externally and
|
||||
* the {@link ProviderManagerBuilder} is returned immediately.
|
||||
*
|
||||
* @return a {@link ProviderManagerBuilder} to allow further authentication
|
||||
* to be provided to the {@link ProviderManagerBuilder}
|
||||
* @throws Exception
|
||||
* if an error occurs when adding the {@link AuthenticationProvider}
|
||||
*/
|
||||
B authenticationProvider(AuthenticationProvider authenticationProvider);
|
||||
}
|
||||
+254
@@ -0,0 +1,254 @@
|
||||
/*
|
||||
* Copyright 2002-2013 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.config.annotation.authentication.builders;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.security.authentication.AuthenticationEventPublisher;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.authentication.AuthenticationProvider;
|
||||
import org.springframework.security.authentication.ProviderManager;
|
||||
import org.springframework.security.config.annotation.AbstractConfiguredSecurityBuilder;
|
||||
import org.springframework.security.config.annotation.ObjectPostProcessor;
|
||||
import org.springframework.security.config.annotation.SecurityBuilder;
|
||||
import org.springframework.security.config.annotation.authentication.ProviderManagerBuilder;
|
||||
import org.springframework.security.config.annotation.authentication.configurers.ldap.LdapAuthenticationProviderConfigurer;
|
||||
import org.springframework.security.config.annotation.authentication.configurers.provisioning.InMemoryUserDetailsManagerConfigurer;
|
||||
import org.springframework.security.config.annotation.authentication.configurers.provisioning.JdbcUserDetailsManagerConfigurer;
|
||||
import org.springframework.security.config.annotation.authentication.configurers.userdetails.DaoAuthenticationConfigurer;
|
||||
import org.springframework.security.config.annotation.authentication.configurers.userdetails.UserDetailsAwareConfigurer;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* {@link SecurityBuilder} used to create an {@link AuthenticationManager}.
|
||||
* Allows for easily building in memory authentication, LDAP authentication,
|
||||
* JDBC based authentication, adding {@link UserDetailsService}, and adding
|
||||
* {@link AuthenticationProvider}'s.
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @since 3.2
|
||||
*/
|
||||
public class AuthenticationManagerBuilder extends AbstractConfiguredSecurityBuilder<AuthenticationManager, AuthenticationManagerBuilder> implements ProviderManagerBuilder<AuthenticationManagerBuilder> {
|
||||
|
||||
private AuthenticationManager parentAuthenticationManager;
|
||||
private List<AuthenticationProvider> authenticationProviders = new ArrayList<AuthenticationProvider>();
|
||||
private UserDetailsService defaultUserDetailsService;
|
||||
private Boolean eraseCredentials;
|
||||
private AuthenticationEventPublisher eventPublisher;
|
||||
|
||||
/**
|
||||
* Creates a new instance
|
||||
*/
|
||||
public AuthenticationManagerBuilder() {
|
||||
super(ObjectPostProcessor.QUIESCENT_POSTPROCESSOR,true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows providing a parent {@link AuthenticationManager} that will be
|
||||
* tried if this {@link AuthenticationManager} was unable to attempt to
|
||||
* authenticate the provided {@link Authentication}.
|
||||
*
|
||||
* @param authenticationManager
|
||||
* the {@link AuthenticationManager} that should be used if the
|
||||
* current {@link AuthenticationManager} was unable to attempt to
|
||||
* authenticate the provided {@link Authentication}.
|
||||
* @return the {@link AuthenticationManagerBuilder} for further adding types
|
||||
* of authentication
|
||||
*/
|
||||
public AuthenticationManagerBuilder parentAuthenticationManager(
|
||||
AuthenticationManager authenticationManager) {
|
||||
this.parentAuthenticationManager = authenticationManager;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the {@link AuthenticationEventPublisher}
|
||||
*
|
||||
* @param eventPublisher
|
||||
* the {@link AuthenticationEventPublisher} to use
|
||||
* @return the {@link AuthenticationManagerBuilder} for further
|
||||
* customizations
|
||||
*/
|
||||
public AuthenticationManagerBuilder authenticationEventPublisher(AuthenticationEventPublisher eventPublisher) {
|
||||
Assert.notNull(eventPublisher, "AuthenticationEventPublisher cannot be null");
|
||||
this.eventPublisher = eventPublisher;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @param eraseCredentials
|
||||
* true if {@link AuthenticationManager} should clear the
|
||||
* credentials from the {@link Authentication} object after
|
||||
* authenticating
|
||||
* @return the {@link AuthenticationManagerBuilder} for further customizations
|
||||
*/
|
||||
public AuthenticationManagerBuilder eraseCredentials(boolean eraseCredentials) {
|
||||
this.eraseCredentials = eraseCredentials;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Add in memory authentication to the {@link AuthenticationManagerBuilder}
|
||||
* and return a {@link InMemoryUserDetailsManagerConfigurer} to
|
||||
* allow customization of the in memory authentication.
|
||||
*
|
||||
* <p>
|
||||
* This method also ensure that a {@link UserDetailsService} is available
|
||||
* for the {@link #getDefaultUserDetailsService()} method. Note that
|
||||
* additional {@link UserDetailsService}'s may override this
|
||||
* {@link UserDetailsService} as the default.
|
||||
* </p>
|
||||
*
|
||||
* @return a {@link InMemoryUserDetailsManagerConfigurer} to allow
|
||||
* customization of the in memory authentication
|
||||
* @throws Exception
|
||||
* if an error occurs when adding the in memory authentication
|
||||
*/
|
||||
public InMemoryUserDetailsManagerConfigurer<AuthenticationManagerBuilder> inMemoryAuthentication()
|
||||
throws Exception {
|
||||
return apply(new InMemoryUserDetailsManagerConfigurer<AuthenticationManagerBuilder>());
|
||||
}
|
||||
|
||||
/**
|
||||
* Add JDBC authentication to the {@link AuthenticationManagerBuilder} and
|
||||
* return a {@link JdbcUserDetailsManagerConfigurer} to allow customization of the
|
||||
* JDBC authentication.
|
||||
*
|
||||
* <p>
|
||||
* This method also ensure that a {@link UserDetailsService} is available
|
||||
* for the {@link #getDefaultUserDetailsService()} method. Note that
|
||||
* additional {@link UserDetailsService}'s may override this
|
||||
* {@link UserDetailsService} as the default.
|
||||
* </p>
|
||||
*
|
||||
* @return a {@link JdbcUserDetailsManagerConfigurer} to allow customization of the
|
||||
* JDBC authentication
|
||||
* @throws Exception if an error occurs when adding the JDBC authentication
|
||||
*/
|
||||
public JdbcUserDetailsManagerConfigurer<AuthenticationManagerBuilder> jdbcAuthentication()
|
||||
throws Exception {
|
||||
return apply(new JdbcUserDetailsManagerConfigurer<AuthenticationManagerBuilder>());
|
||||
}
|
||||
|
||||
/**
|
||||
* Add authentication based upon the custom {@link UserDetailsService} that
|
||||
* is passed in. It then returns a {@link DaoAuthenticationConfigurer} to
|
||||
* allow customization of the authentication.
|
||||
*
|
||||
* <p>
|
||||
* This method also ensure that the {@link UserDetailsService} is available
|
||||
* for the {@link #getDefaultUserDetailsService()} method. Note that
|
||||
* additional {@link UserDetailsService}'s may override this
|
||||
* {@link UserDetailsService} as the default.
|
||||
* </p>
|
||||
*
|
||||
* @return a {@link DaoAuthenticationConfigurer} to allow customization
|
||||
* of the DAO authentication
|
||||
* @throws Exception
|
||||
* if an error occurs when adding the {@link UserDetailsService}
|
||||
* based authentication
|
||||
*/
|
||||
public <T extends UserDetailsService> DaoAuthenticationConfigurer<AuthenticationManagerBuilder,T> userDetailsService(
|
||||
T userDetailsService) throws Exception {
|
||||
this.defaultUserDetailsService = userDetailsService;
|
||||
return apply(new DaoAuthenticationConfigurer<AuthenticationManagerBuilder,T>(userDetailsService));
|
||||
}
|
||||
|
||||
/**
|
||||
* Add LDAP authentication to the {@link AuthenticationManagerBuilder} and
|
||||
* return a {@link LdapAuthenticationProviderConfigurer} to allow
|
||||
* customization of the LDAP authentication.
|
||||
*
|
||||
* <p>
|
||||
* This method <b>does NOT</b> ensure that a {@link UserDetailsService} is
|
||||
* available for the {@link #getDefaultUserDetailsService()} method.
|
||||
* </p>
|
||||
*
|
||||
* @return a {@link LdapAuthenticationProviderConfigurer} to allow
|
||||
* customization of the LDAP authentication
|
||||
* @throws Exception
|
||||
* if an error occurs when adding the LDAP authentication
|
||||
*/
|
||||
public LdapAuthenticationProviderConfigurer<AuthenticationManagerBuilder> ldapAuthentication()
|
||||
throws Exception {
|
||||
return apply(new LdapAuthenticationProviderConfigurer<AuthenticationManagerBuilder>());
|
||||
}
|
||||
|
||||
/**
|
||||
* Add authentication based upon the custom {@link AuthenticationProvider}
|
||||
* that is passed in. Since the {@link AuthenticationProvider}
|
||||
* implementation is unknown, all customizations must be done externally and
|
||||
* the {@link AuthenticationManagerBuilder} is returned immediately.
|
||||
*
|
||||
* <p>
|
||||
* This method <b>does NOT</b> ensure that the {@link UserDetailsService} is
|
||||
* available for the {@link #getDefaultUserDetailsService()} method.
|
||||
* </p>
|
||||
*
|
||||
* @return a {@link AuthenticationManagerBuilder} to allow further authentication
|
||||
* to be provided to the {@link AuthenticationManagerBuilder}
|
||||
* @throws Exception
|
||||
* if an error occurs when adding the {@link AuthenticationProvider}
|
||||
*/
|
||||
public AuthenticationManagerBuilder authenticationProvider(
|
||||
AuthenticationProvider authenticationProvider) {
|
||||
this.authenticationProviders.add(authenticationProvider);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ProviderManager performBuild() throws Exception {
|
||||
ProviderManager providerManager = new ProviderManager(authenticationProviders, parentAuthenticationManager);
|
||||
if(eraseCredentials != null) {
|
||||
providerManager.setEraseCredentialsAfterAuthentication(eraseCredentials);
|
||||
}
|
||||
if(eventPublisher != null) {
|
||||
providerManager.setAuthenticationEventPublisher(eventPublisher);
|
||||
}
|
||||
providerManager = postProcess(providerManager);
|
||||
return providerManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the default {@link UserDetailsService} for the
|
||||
* {@link AuthenticationManagerBuilder}. The result may be null in some
|
||||
* circumstances.
|
||||
*
|
||||
* @return the default {@link UserDetailsService} for the
|
||||
* {@link AuthenticationManagerBuilder}
|
||||
*/
|
||||
public UserDetailsService getDefaultUserDetailsService() {
|
||||
return this.defaultUserDetailsService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Captures the {@link UserDetailsService} from any {@link UserDetailsAwareConfigurer}.
|
||||
*
|
||||
* @param configurer the {@link UserDetailsAwareConfigurer} to capture the {@link UserDetailsService} from.
|
||||
* @return the {@link UserDetailsAwareConfigurer} for further customizations
|
||||
* @throws Exception if an error occurs
|
||||
*/
|
||||
private <C extends UserDetailsAwareConfigurer<AuthenticationManagerBuilder,? extends UserDetailsService>> C apply(C configurer) throws Exception {
|
||||
this.defaultUserDetailsService = configurer.getUserDetailsService();
|
||||
return (C) super.apply(configurer);
|
||||
}
|
||||
}
|
||||
+469
@@ -0,0 +1,469 @@
|
||||
/*
|
||||
* Copyright 2002-2013 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.config.annotation.authentication.configurers.ldap;
|
||||
|
||||
import org.springframework.ldap.core.support.BaseLdapPathContextSource;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.authentication.AuthenticationProvider;
|
||||
import org.springframework.security.authentication.encoding.PasswordEncoder;
|
||||
import org.springframework.security.authentication.encoding.PlaintextPasswordEncoder;
|
||||
import org.springframework.security.config.annotation.SecurityConfigurerAdapter;
|
||||
import org.springframework.security.config.annotation.authentication.ProviderManagerBuilder;
|
||||
import org.springframework.security.core.authority.mapping.SimpleAuthorityMapper;
|
||||
import org.springframework.security.ldap.DefaultSpringSecurityContextSource;
|
||||
import org.springframework.security.ldap.authentication.AbstractLdapAuthenticator;
|
||||
import org.springframework.security.ldap.authentication.BindAuthenticator;
|
||||
import org.springframework.security.ldap.authentication.LdapAuthenticationProvider;
|
||||
import org.springframework.security.ldap.authentication.LdapAuthenticator;
|
||||
import org.springframework.security.ldap.authentication.PasswordComparisonAuthenticator;
|
||||
import org.springframework.security.ldap.search.FilterBasedLdapUserSearch;
|
||||
import org.springframework.security.ldap.search.LdapUserSearch;
|
||||
import org.springframework.security.ldap.server.ApacheDSContainer;
|
||||
import org.springframework.security.ldap.userdetails.DefaultLdapAuthoritiesPopulator;
|
||||
import org.springframework.security.ldap.userdetails.InetOrgPersonContextMapper;
|
||||
import org.springframework.security.ldap.userdetails.LdapUserDetailsMapper;
|
||||
import org.springframework.security.ldap.userdetails.PersonContextMapper;
|
||||
import org.springframework.security.ldap.userdetails.UserDetailsContextMapper;
|
||||
|
||||
/**
|
||||
* Configures LDAP {@link AuthenticationProvider} in the {@link ProviderManagerBuilder}.
|
||||
*
|
||||
* @param <B> the {@link ProviderManagerBuilder} type that this is configuring.
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @since 3.2
|
||||
*/
|
||||
public class LdapAuthenticationProviderConfigurer<B extends ProviderManagerBuilder<B>> extends SecurityConfigurerAdapter<AuthenticationManager,B> {
|
||||
private String groupRoleAttribute = "cn";
|
||||
private String groupSearchBase = "";
|
||||
private String groupSearchFilter = "(uniqueMember={0})";
|
||||
private String rolePrefix = "ROLE_";
|
||||
private String userSearchBase = ""; // only for search
|
||||
private String userSearchFilter = null;//"uid={0}"; // only for search
|
||||
private String[] userDnPatterns;
|
||||
private BaseLdapPathContextSource contextSource;
|
||||
private ContextSourceBuilder contextSourceBuilder = new ContextSourceBuilder();
|
||||
private UserDetailsContextMapper userDetailsContextMapper;
|
||||
private PasswordEncoder passwordEncoder;
|
||||
private String passwordAttribute;
|
||||
|
||||
private LdapAuthenticationProvider build() throws Exception {
|
||||
BaseLdapPathContextSource contextSource = getContextSource();
|
||||
LdapAuthenticator ldapAuthenticator = createLdapAuthenticator(contextSource);
|
||||
|
||||
DefaultLdapAuthoritiesPopulator authoritiesPopulator = new DefaultLdapAuthoritiesPopulator(
|
||||
contextSource, groupSearchBase);
|
||||
authoritiesPopulator.setGroupRoleAttribute(groupRoleAttribute);
|
||||
authoritiesPopulator.setGroupSearchFilter(groupSearchFilter);
|
||||
|
||||
LdapAuthenticationProvider ldapAuthenticationProvider = new LdapAuthenticationProvider(
|
||||
ldapAuthenticator, authoritiesPopulator);
|
||||
SimpleAuthorityMapper simpleAuthorityMapper = new SimpleAuthorityMapper();
|
||||
simpleAuthorityMapper.setPrefix(rolePrefix);
|
||||
simpleAuthorityMapper.afterPropertiesSet();
|
||||
ldapAuthenticationProvider.setAuthoritiesMapper(simpleAuthorityMapper);
|
||||
if(userDetailsContextMapper != null) {
|
||||
ldapAuthenticationProvider.setUserDetailsContextMapper(userDetailsContextMapper);
|
||||
}
|
||||
return ldapAuthenticationProvider;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the {@link LdapAuthenticator} to use
|
||||
*
|
||||
* @param contextSource the {@link BaseLdapPathContextSource} to use
|
||||
* @return the {@link LdapAuthenticator} to use
|
||||
*/
|
||||
private LdapAuthenticator createLdapAuthenticator(BaseLdapPathContextSource contextSource) {
|
||||
AbstractLdapAuthenticator ldapAuthenticator = passwordEncoder == null ? createBindAuthenticator(contextSource) : createPasswordCompareAuthenticator(contextSource);
|
||||
LdapUserSearch userSearch = createUserSearch();
|
||||
if(userSearch != null) {
|
||||
ldapAuthenticator.setUserSearch(userSearch);
|
||||
}
|
||||
if(userDnPatterns != null && userDnPatterns.length > 0) {
|
||||
ldapAuthenticator.setUserDnPatterns(userDnPatterns);
|
||||
}
|
||||
return postProcess(ldapAuthenticator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates {@link PasswordComparisonAuthenticator}
|
||||
*
|
||||
* @param contextSource the {@link BaseLdapPathContextSource} to use
|
||||
* @return
|
||||
*/
|
||||
private PasswordComparisonAuthenticator createPasswordCompareAuthenticator(BaseLdapPathContextSource contextSource) {
|
||||
PasswordComparisonAuthenticator ldapAuthenticator = new PasswordComparisonAuthenticator(contextSource);
|
||||
ldapAuthenticator.setPasswordAttributeName(passwordAttribute);
|
||||
ldapAuthenticator.setPasswordEncoder(passwordEncoder);
|
||||
return ldapAuthenticator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link BindAuthenticator}
|
||||
*
|
||||
* @param contextSource the {@link BaseLdapPathContextSource} to use
|
||||
* @return the {@link BindAuthenticator} to use
|
||||
*/
|
||||
private BindAuthenticator createBindAuthenticator(
|
||||
BaseLdapPathContextSource contextSource) {
|
||||
return new BindAuthenticator(contextSource);
|
||||
}
|
||||
|
||||
private LdapUserSearch createUserSearch() {
|
||||
if(userSearchFilter == null) {
|
||||
return null;
|
||||
}
|
||||
return new FilterBasedLdapUserSearch(userSearchBase, userSearchFilter, contextSource);
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies the {@link BaseLdapPathContextSource} to be used. If not
|
||||
* specified, an embedded LDAP server will be created using
|
||||
* {@link #contextSource()}.
|
||||
*
|
||||
* @param contextSource
|
||||
* the {@link BaseLdapPathContextSource} to use
|
||||
* @return the {@link LdapAuthenticationProviderConfigurer} for further
|
||||
* customizations
|
||||
* @see #contextSource()
|
||||
*/
|
||||
public LdapAuthenticationProviderConfigurer<B> contextSource(BaseLdapPathContextSource contextSource) {
|
||||
this.contextSource = contextSource;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows easily configuring of a {@link BaseLdapPathContextSource} with
|
||||
* defaults pointing to an embedded LDAP server that is created.
|
||||
*
|
||||
* @return the {@link ContextSourceBuilder} for further customizations
|
||||
*/
|
||||
public ContextSourceBuilder contextSource() {
|
||||
return contextSourceBuilder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies the {@link PasswordEncoder} to be used when authenticating with
|
||||
* password comparison.
|
||||
*
|
||||
* @param passwordEncoder the {@link PasswordEncoder} to use
|
||||
* @return the {@link LdapAuthenticationProviderConfigurer} for further customization
|
||||
*/
|
||||
public LdapAuthenticationProviderConfigurer<B> passwordEncoder(PasswordEncoder passwordEncoder) {
|
||||
this.passwordEncoder = passwordEncoder;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* If your users are at a fixed location in the directory (i.e. you can work
|
||||
* out the DN directly from the username without doing a directory search),
|
||||
* you can use this attribute to map directly to the DN. It maps directly to
|
||||
* the userDnPatterns property of AbstractLdapAuthenticator. The value is a
|
||||
* specific pattern used to build the user's DN, for example
|
||||
* "uid={0},ou=people". The key "{0}" must be present and will be
|
||||
* substituted with the username.
|
||||
*
|
||||
* @param userDnPatterns the LDAP patterns for finding the usernames
|
||||
* @return the {@link LdapAuthenticationProviderConfigurer} for further customizations
|
||||
*/
|
||||
public LdapAuthenticationProviderConfigurer<B> userDnPatterns(String...userDnPatterns) {
|
||||
this.userDnPatterns = userDnPatterns;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows explicit customization of the loaded user object by specifying a
|
||||
* UserDetailsContextMapper bean which will be called with the context
|
||||
* information from the user's directory entry.
|
||||
*
|
||||
* @param userDetailsContextMapper the {@link UserDetailsContextMapper} to use
|
||||
* @return the {@link LdapAuthenticationProviderConfigurer} for further
|
||||
* customizations
|
||||
*
|
||||
* @see PersonContextMapper
|
||||
* @see InetOrgPersonContextMapper
|
||||
* @see LdapUserDetailsMapper
|
||||
*/
|
||||
public LdapAuthenticationProviderConfigurer<B> userDetailsContextMapper(UserDetailsContextMapper userDetailsContextMapper) {
|
||||
this.userDetailsContextMapper = userDetailsContextMapper;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies the attribute name which contains the role name. Default is "cn".
|
||||
* @param groupRoleAttribute the attribute name that maps a group to a role.
|
||||
* @return
|
||||
*/
|
||||
public LdapAuthenticationProviderConfigurer<B> groupRoleAttribute(String groupRoleAttribute) {
|
||||
this.groupRoleAttribute = groupRoleAttribute;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* The search base for group membership searches. Defaults to "".
|
||||
* @param groupSearchBase
|
||||
* @return the {@link LdapAuthenticationProviderConfigurer} for further customizations
|
||||
*/
|
||||
public LdapAuthenticationProviderConfigurer<B> groupSearchBase(String groupSearchBase) {
|
||||
this.groupSearchBase = groupSearchBase;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* The LDAP filter to search for groups. Defaults to "(uniqueMember={0})".
|
||||
* The substituted parameter is the DN of the user.
|
||||
*
|
||||
* @param groupSearchFilter the LDAP filter to search for groups
|
||||
* @return the {@link LdapAuthenticationProviderConfigurer} for further customizations
|
||||
*/
|
||||
public LdapAuthenticationProviderConfigurer<B> groupSearchFilter(String groupSearchFilter) {
|
||||
this.groupSearchFilter = groupSearchFilter;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* A non-empty string prefix that will be added as a prefix to the existing
|
||||
* roles. The default is "ROLE_".
|
||||
*
|
||||
* @param rolePrefix the prefix to be added to the roles that are loaded.
|
||||
* @return the {@link LdapAuthenticationProviderConfigurer} for further customizations
|
||||
* @see SimpleAuthorityMapper#setPrefix(String)
|
||||
*/
|
||||
public LdapAuthenticationProviderConfigurer<B> rolePrefix(String rolePrefix) {
|
||||
this.rolePrefix = rolePrefix;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Search base for user searches. Defaults to "". Only used with {@link #userSearchFilter(String)}.
|
||||
*
|
||||
* @param userSearchBase search base for user searches
|
||||
* @return the {@link LdapAuthenticationProviderConfigurer} for further customizations
|
||||
*/
|
||||
public LdapAuthenticationProviderConfigurer<B> userSearchBase(String userSearchBase) {
|
||||
this.userSearchBase = userSearchBase;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* The LDAP filter used to search for users (optional). For example
|
||||
* "(uid={0})". The substituted parameter is the user's login name.
|
||||
*
|
||||
* @param userSearchFilter
|
||||
* the LDAP filter used to search for users
|
||||
* @return the {@link LdapAuthenticationProviderConfigurer} for further
|
||||
* customizations
|
||||
*/
|
||||
public LdapAuthenticationProviderConfigurer<B> userSearchFilter(String userSearchFilter) {
|
||||
this.userSearchFilter = userSearchFilter;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(B builder) throws Exception {
|
||||
LdapAuthenticationProvider provider = postProcess(build());
|
||||
builder.authenticationProvider(provider);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up Password based comparison
|
||||
*
|
||||
* @author Rob Winch
|
||||
*/
|
||||
public final class PasswordCompareConfigurer {
|
||||
|
||||
/**
|
||||
* Allows specifying the {@link PasswordEncoder} to use. The default is {@link PlaintextPasswordEncoder}.
|
||||
* @param passwordEncoder the {@link PasswordEncoder} to use
|
||||
* @return the {@link PasswordEncoder} to use
|
||||
*/
|
||||
public PasswordCompareConfigurer passwordEncoder(PasswordEncoder passwordEncoder) {
|
||||
LdapAuthenticationProviderConfigurer.this.passwordEncoder = passwordEncoder;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* The attribute in the directory which contains the user password. Defaults to "userPassword".
|
||||
*
|
||||
* @param passwordAttribute the attribute in the directory which contains the user password
|
||||
* @return the {@link PasswordCompareConfigurer} for further customizations
|
||||
*/
|
||||
public PasswordCompareConfigurer passwordAttribute(String passwordAttribute) {
|
||||
LdapAuthenticationProviderConfigurer.this.passwordAttribute = passwordAttribute;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows obtaining a reference to the
|
||||
* {@link LdapAuthenticationProviderConfigurer} for further
|
||||
* customizations
|
||||
*
|
||||
* @return attribute in the directory which contains the user password
|
||||
*/
|
||||
public LdapAuthenticationProviderConfigurer<B> and() {
|
||||
return LdapAuthenticationProviderConfigurer.this;
|
||||
}
|
||||
|
||||
private PasswordCompareConfigurer() {}
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows building a {@link BaseLdapPathContextSource} and optionally
|
||||
* creating an embedded LDAP instance.
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @since 3.2
|
||||
*/
|
||||
public final class ContextSourceBuilder {
|
||||
private String ldif = "classpath*:*.ldif";
|
||||
private String managerPassword;
|
||||
private String managerDn;
|
||||
private int port = 33389;
|
||||
private String root = "dc=springframework,dc=org";
|
||||
private String url;
|
||||
|
||||
/**
|
||||
* Specifies an ldif to load at startup for an embedded LDAP server.
|
||||
* This only loads if using an embedded instance. The default is
|
||||
* "classpath*:*.ldif".
|
||||
*
|
||||
* @param ldif
|
||||
* the ldif to load at startup for an embedded LDAP server.
|
||||
* @return the {@link ContextSourceBuilder} for further customization
|
||||
*/
|
||||
public ContextSourceBuilder ldif(String ldif) {
|
||||
this.ldif = ldif;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Username (DN) of the "manager" user identity (i.e.
|
||||
* "uid=admin,ou=system") which will be used to authenticate to a
|
||||
* (non-embedded) LDAP server. If omitted, anonymous access will be
|
||||
* used.
|
||||
*
|
||||
* @param managerDn
|
||||
* the username (DN) of the "manager" user identity used to
|
||||
* authenticate to a LDAP server.
|
||||
* @return the {@link ContextSourceBuilder} for further customization
|
||||
*/
|
||||
public ContextSourceBuilder managerDn(String managerDn) {
|
||||
this.managerDn = managerDn;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* The password for the manager DN. This is required if the manager-dn is specified.
|
||||
* @param managerPassword password for the manager DN
|
||||
* @return the {@link ContextSourceBuilder} for further customization
|
||||
*/
|
||||
public ContextSourceBuilder managerPassword(String managerPassword) {
|
||||
this.managerPassword = managerPassword;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* The port to connect to LDAP to (the default is 33389).
|
||||
* @param port the port to connect to
|
||||
* @return the {@link ContextSourceBuilder} for further customization
|
||||
*/
|
||||
public ContextSourceBuilder port(int port) {
|
||||
this.port = port;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Optional root suffix for the embedded LDAP server. Default is
|
||||
* "dc=springframework,dc=org"
|
||||
*
|
||||
* @param root
|
||||
* root suffix for the embedded LDAP server
|
||||
* @return the {@link ContextSourceBuilder} for further customization
|
||||
*/
|
||||
public ContextSourceBuilder root(String root) {
|
||||
this.root = root;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies the ldap server URL when not using the embedded LDAP
|
||||
* server. For example, "ldaps://ldap.example.com:33389/dc=myco,dc=org".
|
||||
*
|
||||
* @param url
|
||||
* the ldap server URL
|
||||
* @return the {@link ContextSourceBuilder} for further customization
|
||||
*/
|
||||
public ContextSourceBuilder url(String url) {
|
||||
this.url = url;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the {@link LdapAuthenticationProviderConfigurer} for further
|
||||
* customizations
|
||||
*
|
||||
* @return the {@link LdapAuthenticationProviderConfigurer} for further
|
||||
* customizations
|
||||
*/
|
||||
public LdapAuthenticationProviderConfigurer<B> and() {
|
||||
return LdapAuthenticationProviderConfigurer.this;
|
||||
}
|
||||
|
||||
private DefaultSpringSecurityContextSource build() throws Exception {
|
||||
DefaultSpringSecurityContextSource contextSource = new DefaultSpringSecurityContextSource(getProviderUrl());
|
||||
if(managerDn != null) {
|
||||
contextSource.setUserDn(managerDn);
|
||||
if(managerPassword == null) {
|
||||
throw new IllegalStateException("managerPassword is required if managerDn is supplied");
|
||||
}
|
||||
contextSource.setPassword(managerPassword);
|
||||
}
|
||||
contextSource = postProcess(contextSource);
|
||||
if(url != null) {
|
||||
return contextSource;
|
||||
}
|
||||
ApacheDSContainer apacheDsContainer = new ApacheDSContainer(root, ldif);
|
||||
apacheDsContainer.setPort(port);
|
||||
postProcess(apacheDsContainer);
|
||||
return contextSource;
|
||||
}
|
||||
|
||||
private String getProviderUrl() {
|
||||
if(url == null) {
|
||||
return "ldap://127.0.0.1:" + port + "/" + root;
|
||||
}
|
||||
return url;
|
||||
}
|
||||
|
||||
private ContextSourceBuilder() {}
|
||||
}
|
||||
|
||||
private BaseLdapPathContextSource getContextSource() throws Exception {
|
||||
if(contextSource == null) {
|
||||
contextSource = contextSourceBuilder.build();
|
||||
}
|
||||
return contextSource;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
public PasswordCompareConfigurer passwordCompare() {
|
||||
return new PasswordCompareConfigurer()
|
||||
.passwordAttribute("password")
|
||||
.passwordEncoder(new PlaintextPasswordEncoder());
|
||||
}
|
||||
}
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright 2002-2013 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.config.annotation.authentication.configurers.provisioning;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import org.springframework.security.config.annotation.authentication.ProviderManagerBuilder;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
|
||||
|
||||
/**
|
||||
* Configures an {@link org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder} to
|
||||
* have in memory authentication. It also allows easily adding users to the in memory authentication.
|
||||
*
|
||||
* @param <B> the type of the {@link SecurityBuilder} that is being configured
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @since 3.2
|
||||
*/
|
||||
public class InMemoryUserDetailsManagerConfigurer<B extends ProviderManagerBuilder<B>> extends
|
||||
UserDetailsManagerConfigurer<B,InMemoryUserDetailsManagerConfigurer<B>> {
|
||||
|
||||
/**
|
||||
* Creates a new instance
|
||||
*/
|
||||
public InMemoryUserDetailsManagerConfigurer() {
|
||||
super(new InMemoryUserDetailsManager(new ArrayList<UserDetails>()));
|
||||
}
|
||||
}
|
||||
+192
@@ -0,0 +1,192 @@
|
||||
/*
|
||||
* Copyright 2002-2013 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.config.annotation.authentication.configurers.provisioning;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.jdbc.datasource.init.DataSourceInitializer;
|
||||
import org.springframework.jdbc.datasource.init.DatabasePopulator;
|
||||
import org.springframework.jdbc.datasource.init.ResourceDatabasePopulator;
|
||||
import org.springframework.security.config.annotation.authentication.ProviderManagerBuilder;
|
||||
import org.springframework.security.core.userdetails.UserCache;
|
||||
import org.springframework.security.provisioning.JdbcUserDetailsManager;
|
||||
|
||||
/**
|
||||
* Configures an {@link org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder} to
|
||||
* have JDBC authentication. It also allows easily adding users to the database used for authentication and setting up
|
||||
* the schema.
|
||||
*
|
||||
* <p>
|
||||
* The only required method is the {@link #dataSource(javax.sql.DataSource)} all other methods have reasonable defaults.
|
||||
* </p>
|
||||
*
|
||||
* @param <B> the type of the {@link ProviderManagerBuilder} that is being configured
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @since 3.2
|
||||
*/
|
||||
public class JdbcUserDetailsManagerConfigurer<B extends ProviderManagerBuilder<B>> extends
|
||||
UserDetailsManagerConfigurer<B,JdbcUserDetailsManagerConfigurer<B>> {
|
||||
|
||||
private DataSource dataSource;
|
||||
|
||||
private List<Resource> initScripts = new ArrayList<Resource>();
|
||||
|
||||
public JdbcUserDetailsManagerConfigurer(JdbcUserDetailsManager manager) {
|
||||
super(manager);
|
||||
}
|
||||
|
||||
public JdbcUserDetailsManagerConfigurer() {
|
||||
this(new JdbcUserDetailsManager());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Populates the {@link DataSource} to be used. This is the only required attribute.
|
||||
*
|
||||
* @param dataSource the {@link DataSource} to be used. Cannot be null.
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
public JdbcUserDetailsManagerConfigurer<B> dataSource(DataSource dataSource) throws Exception {
|
||||
this.dataSource = dataSource;
|
||||
getUserDetailsService().setDataSource(dataSource);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the query to be used for finding a user by their username. For example:
|
||||
*
|
||||
* <code>
|
||||
* select username,password,enabled from users where username = ?
|
||||
* </code>
|
||||
* @param query The query to use for selecting the username, password, and if the user is enabled by username.
|
||||
* Must contain a single parameter for the username.
|
||||
* @return The {@link JdbcUserDetailsManagerRegistry} used for additional customizations
|
||||
* @throws Exception
|
||||
*/
|
||||
public JdbcUserDetailsManagerConfigurer<B> usersByUsernameQuery(String query) throws Exception {
|
||||
getUserDetailsService().setUsersByUsernameQuery(query);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the query to be used for finding a user's authorities by their username. For example:
|
||||
*
|
||||
* <code>
|
||||
* select username,authority from authorities where username = ?
|
||||
* </code>
|
||||
*
|
||||
* @param query The query to use for selecting the username, authority by username.
|
||||
* Must contain a single parameter for the username.
|
||||
* @return The {@link JdbcUserDetailsManagerRegistry} used for additional customizations
|
||||
* @throws Exception
|
||||
*/
|
||||
public JdbcUserDetailsManagerConfigurer<B> authoritiesByUsernameQuery(String query) throws Exception {
|
||||
getUserDetailsService().setAuthoritiesByUsernameQuery(query);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* An SQL statement to query user's group authorities given a username. For example:
|
||||
*
|
||||
* <code>
|
||||
* select
|
||||
* g.id, g.group_name, ga.authority
|
||||
* from
|
||||
* groups g, group_members gm, group_authorities ga
|
||||
* where
|
||||
* gm.username = ? and g.id = ga.group_id and g.id = gm.group_id
|
||||
* </code>
|
||||
*
|
||||
* @param query The query to use for selecting the authorities by group.
|
||||
* Must contain a single parameter for the username.
|
||||
* @return The {@link JdbcUserDetailsManagerRegistry} used for additional customizations
|
||||
* @throws Exception
|
||||
*/
|
||||
public JdbcUserDetailsManagerConfigurer<B> groupAuthoritiesByUsername(String query) throws Exception {
|
||||
JdbcUserDetailsManager userDetailsService = getUserDetailsService();
|
||||
userDetailsService.setEnableGroups(true);
|
||||
userDetailsService.setGroupAuthoritiesByUsernameQuery(query);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* A non-empty string prefix that will be added to role strings loaded from persistent storage (default is "").
|
||||
*
|
||||
* @param rolePrefix
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
public JdbcUserDetailsManagerConfigurer<B> rolePrefix(String rolePrefix) throws Exception {
|
||||
getUserDetailsService().setRolePrefix(rolePrefix);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Defines the {@link UserCache} to use
|
||||
*
|
||||
* @param userCache the {@link UserCache} to use
|
||||
* @return the {@link JdbcUserDetailsManagerConfigurer} for further customizations
|
||||
* @throws Exception
|
||||
*/
|
||||
public JdbcUserDetailsManagerConfigurer<B> userCache(UserCache userCache) throws Exception {
|
||||
getUserDetailsService().setUserCache(userCache);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initUserDetailsService() throws Exception {
|
||||
if(!initScripts.isEmpty()) {
|
||||
getDataSourceInit().afterPropertiesSet();
|
||||
}
|
||||
super.initUserDetailsService();
|
||||
}
|
||||
|
||||
@Override
|
||||
public JdbcUserDetailsManager getUserDetailsService() {
|
||||
return (JdbcUserDetailsManager) super.getUserDetailsService();
|
||||
}
|
||||
|
||||
/**
|
||||
* Populates the default schema that allows users and authorities to be stored.
|
||||
*
|
||||
* @return The {@link JdbcUserDetailsManagerRegistry} used for additional customizations
|
||||
*/
|
||||
public JdbcUserDetailsManagerConfigurer<B> withDefaultSchema() {
|
||||
this.initScripts.add(new ClassPathResource("org/springframework/security/core/userdetails/jdbc/users.ddl"));
|
||||
return this;
|
||||
}
|
||||
|
||||
protected DatabasePopulator getDatabasePopulator() {
|
||||
ResourceDatabasePopulator dbp = new ResourceDatabasePopulator();
|
||||
dbp.setScripts(initScripts.toArray(new Resource[initScripts.size()]));
|
||||
return dbp;
|
||||
}
|
||||
|
||||
private DataSourceInitializer getDataSourceInit() {
|
||||
DataSourceInitializer dsi = new DataSourceInitializer();
|
||||
dsi.setDatabasePopulator(getDatabasePopulator());
|
||||
dsi.setDataSource(dataSource);
|
||||
return dsi;
|
||||
}
|
||||
}
|
||||
+263
@@ -0,0 +1,263 @@
|
||||
/*
|
||||
* Copyright 2002-2013 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.config.annotation.authentication.configurers.provisioning;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.security.config.annotation.SecurityBuilder;
|
||||
import org.springframework.security.config.annotation.authentication.ProviderManagerBuilder;
|
||||
import org.springframework.security.config.annotation.authentication.configurers.userdetails.UserDetailsServiceConfigurer;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.authority.AuthorityUtils;
|
||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||
import org.springframework.security.core.userdetails.User;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.security.provisioning.UserDetailsManager;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Base class for populating an
|
||||
* {@link org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder} with a
|
||||
* {@link UserDetailsManager}.
|
||||
*
|
||||
* @param <B> the type of the {@link SecurityBuilder} that is being configured
|
||||
* @param <C> the type of {@link UserDetailsManagerConfigurer}
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @since 3.2
|
||||
*/
|
||||
public class UserDetailsManagerConfigurer<B extends ProviderManagerBuilder<B>, C extends UserDetailsManagerConfigurer<B,C>> extends
|
||||
UserDetailsServiceConfigurer<B,C,UserDetailsManager> {
|
||||
|
||||
private final List<UserDetailsBuilder> userBuilders = new ArrayList<UserDetailsBuilder>();
|
||||
|
||||
protected UserDetailsManagerConfigurer(UserDetailsManager userDetailsManager) {
|
||||
super(userDetailsManager);
|
||||
}
|
||||
|
||||
/**
|
||||
* Populates the users that have been added.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Override
|
||||
protected void initUserDetailsService() throws Exception {
|
||||
for(UserDetailsBuilder userBuilder : userBuilders) {
|
||||
getUserDetailsService().createUser(userBuilder.build());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows adding a user to the {@link UserDetailsManager} that is being created. This method can be invoked
|
||||
* multiple times to add multiple users.
|
||||
*
|
||||
* @param username the username for the user being added. Cannot be null.
|
||||
* @return
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public final UserDetailsBuilder withUser(String username) {
|
||||
UserDetailsBuilder userBuilder = new UserDetailsBuilder((C)this);
|
||||
userBuilder.username(username);
|
||||
this.userBuilders.add(userBuilder);
|
||||
return userBuilder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the user to be added. At minimum the username, password, and authorities should provided. The remaining
|
||||
* attributes have reasonable defaults.
|
||||
*
|
||||
* @param <T> the type of {@link UserDetailsManagerConfigurer} to return for chaining methods.
|
||||
*/
|
||||
public class UserDetailsBuilder {
|
||||
private String username;
|
||||
private String password;
|
||||
private List<GrantedAuthority> authorities;
|
||||
private boolean accountExpired;
|
||||
private boolean accountLocked;
|
||||
private boolean credentialsExpired;
|
||||
private boolean disabled;
|
||||
private final C builder;
|
||||
|
||||
/**
|
||||
* Creates a new instance
|
||||
* @param builder the builder to return
|
||||
*/
|
||||
private UserDetailsBuilder(C builder) {
|
||||
this.builder = builder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link UserDetailsManagerRegistry} for method chaining (i.e. to add another user)
|
||||
*
|
||||
* @return the {@link UserDetailsManagerRegistry} for method chaining (i.e. to add another user)
|
||||
*/
|
||||
public C and() {
|
||||
return builder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Populates the username. This attribute is required.
|
||||
*
|
||||
* @param username the username. Cannot be null.
|
||||
* @return the {@link UserDetailsBuilder} for method chaining (i.e. to populate additional attributes for this
|
||||
* user)
|
||||
*/
|
||||
private UserDetailsBuilder username(String username) {
|
||||
Assert.notNull(username, "username cannot be null");
|
||||
this.username = username;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Populates the password. This attribute is required.
|
||||
*
|
||||
* @param password the password. Cannot be null.
|
||||
* @return the {@link UserDetailsBuilder} for method chaining (i.e. to populate additional attributes for this
|
||||
* user)
|
||||
*/
|
||||
public UserDetailsBuilder password(String password) {
|
||||
Assert.notNull(password, "password cannot be null");
|
||||
this.password = password;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Populates the roles. This method is a shortcut for calling {@link #authorities(String...)}, but automatically
|
||||
* prefixes each entry with "ROLE_". This means the following:
|
||||
*
|
||||
* <code>
|
||||
* builder.roles("USER","ADMIN");
|
||||
* </code>
|
||||
*
|
||||
* is equivalent to
|
||||
*
|
||||
* <code>
|
||||
* builder.authorities("ROLE_USER","ROLE_ADMIN");
|
||||
* </code>
|
||||
*
|
||||
* <p>This attribute is required, but can also be populated with {@link #authorities(String...)}.</p>
|
||||
*
|
||||
* @param roles the roles for this user (i.e. USER, ADMIN, etc). Cannot be null, contain null values or start
|
||||
* with "ROLE_"
|
||||
* @return the {@link UserDetailsBuilder} for method chaining (i.e. to populate additional attributes for this
|
||||
* user)
|
||||
*/
|
||||
public UserDetailsBuilder roles(String... roles) {
|
||||
List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>(roles.length);
|
||||
for(String role : roles) {
|
||||
Assert.isTrue(!role.startsWith("ROLE_"), role + " cannot start with ROLE_ (it is automatically added)");
|
||||
authorities.add(new SimpleGrantedAuthority("ROLE_"+role));
|
||||
}
|
||||
return authorities(authorities);
|
||||
}
|
||||
|
||||
/**
|
||||
* Populates the authorities. This attribute is required.
|
||||
*
|
||||
* @param authorities the authorities for this user. Cannot be null, or contain null
|
||||
* values
|
||||
* @return the {@link UserDetailsBuilder} for method chaining (i.e. to populate additional attributes for this
|
||||
* user)
|
||||
* @see #roles(String...)
|
||||
*/
|
||||
public UserDetailsBuilder authorities(GrantedAuthority...authorities) {
|
||||
return authorities(Arrays.asList(authorities));
|
||||
}
|
||||
|
||||
/**
|
||||
* Populates the authorities. This attribute is required.
|
||||
*
|
||||
* @param authorities the authorities for this user. Cannot be null, or contain null
|
||||
* values
|
||||
* @return the {@link UserDetailsBuilder} for method chaining (i.e. to populate additional attributes for this
|
||||
* user)
|
||||
* @see #roles(String...)
|
||||
*/
|
||||
public UserDetailsBuilder authorities(List<? extends GrantedAuthority> authorities) {
|
||||
this.authorities = new ArrayList<GrantedAuthority>(authorities);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Populates the authorities. This attribute is required.
|
||||
*
|
||||
* @param authorities the authorities for this user (i.e. ROLE_USER, ROLE_ADMIN, etc). Cannot be null, or contain null
|
||||
* values
|
||||
* @return the {@link UserDetailsBuilder} for method chaining (i.e. to populate additional attributes for this
|
||||
* user)
|
||||
* @see #roles(String...)
|
||||
*/
|
||||
public UserDetailsBuilder authorities(String... authorities) {
|
||||
return authorities(AuthorityUtils.createAuthorityList(authorities));
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines if the account is expired or not. Default is false.
|
||||
*
|
||||
* @param accountExpired true if the account is expired, false otherwise
|
||||
* @return the {@link UserDetailsBuilder} for method chaining (i.e. to populate additional attributes for this
|
||||
* user)
|
||||
*/
|
||||
public UserDetailsBuilder accountExpired(boolean accountExpired) {
|
||||
this.accountExpired = accountExpired;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines if the account is locked or not. Default is false.
|
||||
*
|
||||
* @param accountLocked true if the account is locked, false otherwise
|
||||
* @return the {@link UserDetailsBuilder} for method chaining (i.e. to populate additional attributes for this
|
||||
* user)
|
||||
*/
|
||||
public UserDetailsBuilder accountLocked(boolean accountLocked) {
|
||||
this.accountLocked = accountLocked;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines if the credentials are expired or not. Default is false.
|
||||
*
|
||||
* @param credentialsExpired true if the credentials are expired, false otherwise
|
||||
* @return the {@link UserDetailsBuilder} for method chaining (i.e. to populate additional attributes for this
|
||||
* user)
|
||||
*/
|
||||
public UserDetailsBuilder credentialsExpired(boolean credentialsExpired) {
|
||||
this.credentialsExpired = credentialsExpired;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Defines if the account is disabled or not. Default is false.
|
||||
*
|
||||
* @param disabled true if the account is disabled, false otherwise
|
||||
* @return the {@link UserDetailsBuilder} for method chaining (i.e. to populate additional attributes for this
|
||||
* user)
|
||||
*/
|
||||
public UserDetailsBuilder disabled(boolean disabled) {
|
||||
this.disabled = disabled;
|
||||
return this;
|
||||
}
|
||||
|
||||
private UserDetails build() {
|
||||
return new User(username, password, !disabled, !accountExpired,
|
||||
!credentialsExpired, !accountLocked, authorities);
|
||||
}
|
||||
}
|
||||
}
|
||||
+95
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* Copyright 2002-2013 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.config.annotation.authentication.configurers.userdetails;
|
||||
|
||||
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
|
||||
import org.springframework.security.config.annotation.SecurityBuilder;
|
||||
import org.springframework.security.config.annotation.SecurityConfigurer;
|
||||
import org.springframework.security.config.annotation.authentication.ProviderManagerBuilder;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
|
||||
/**
|
||||
* Allows configuring a {@link DaoAuthenticationProvider}
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @since 3.2
|
||||
*
|
||||
* @param <B> the type of the {@link SecurityBuilder}
|
||||
* @param <C> the type of {@link AbstractDaoAuthenticationConfigurer} this is
|
||||
* @param <U> The type of {@link UserDetailsService} that is being used
|
||||
*
|
||||
*/
|
||||
abstract class AbstractDaoAuthenticationConfigurer<B extends ProviderManagerBuilder<B>, C extends AbstractDaoAuthenticationConfigurer<B,C,U>,U extends UserDetailsService> extends UserDetailsAwareConfigurer<B,U> {
|
||||
private DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
|
||||
private final U userDetailsService;
|
||||
|
||||
/**
|
||||
* Creates a new instance
|
||||
*
|
||||
* @param userDetailsService
|
||||
*/
|
||||
protected AbstractDaoAuthenticationConfigurer(U userDetailsService) {
|
||||
this.userDetailsService = userDetailsService;
|
||||
provider.setUserDetailsService(userDetailsService);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows specifying the {@link PasswordEncoder} to use with the {@link DaoAuthenticationProvider}. The default is
|
||||
* is to use plain text.
|
||||
*
|
||||
* @param passwordEncoder The {@link PasswordEncoder} to use.
|
||||
* @return
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public C passwordEncoder(PasswordEncoder passwordEncoder) {
|
||||
provider.setPasswordEncoder(passwordEncoder);
|
||||
return (C) this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows specifying the
|
||||
* {@link org.springframework.security.authentication.encoding.PasswordEncoder}
|
||||
* to use with the {@link DaoAuthenticationProvider}. The default is is to
|
||||
* use plain text.
|
||||
*
|
||||
* @param passwordEncoder
|
||||
* The
|
||||
* {@link org.springframework.security.authentication.encoding.PasswordEncoder}
|
||||
* to use.
|
||||
* @return the {@link SecurityConfigurer} for further customizations
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public C passwordEncoder(org.springframework.security.authentication.encoding.PasswordEncoder passwordEncoder) {
|
||||
provider.setPasswordEncoder(passwordEncoder);
|
||||
return (C) this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(B builder) throws Exception {
|
||||
provider = postProcess(provider);
|
||||
builder.authenticationProvider(provider);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the {@link UserDetailsService} that is used with the {@link DaoAuthenticationProvider}
|
||||
*
|
||||
* @return the {@link UserDetailsService} that is used with the {@link DaoAuthenticationProvider}
|
||||
*/
|
||||
public U getUserDetailsService() {
|
||||
return userDetailsService;
|
||||
}
|
||||
}
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright 2002-2013 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.config.annotation.authentication.configurers.userdetails;
|
||||
|
||||
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
|
||||
import org.springframework.security.config.annotation.authentication.ProviderManagerBuilder;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
|
||||
/**
|
||||
* Allows configuring a {@link DaoAuthenticationProvider}
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @since 3.2
|
||||
*
|
||||
* @param <B> The type of {@link ProviderManagerBuilder} this is
|
||||
* @param <U> The type of {@link UserDetailsService} that is being used
|
||||
*
|
||||
*/
|
||||
public class DaoAuthenticationConfigurer<B extends ProviderManagerBuilder<B>, U extends UserDetailsService> extends AbstractDaoAuthenticationConfigurer<B,DaoAuthenticationConfigurer<B,U>, U>{
|
||||
|
||||
/**
|
||||
* Creates a new instance
|
||||
* @param userDetailsService
|
||||
*/
|
||||
public DaoAuthenticationConfigurer(U userDetailsService) {
|
||||
super(userDetailsService);
|
||||
}
|
||||
}
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright 2002-2013 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.config.annotation.authentication.configurers.userdetails;
|
||||
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.config.annotation.SecurityConfigurerAdapter;
|
||||
import org.springframework.security.config.annotation.authentication.ProviderManagerBuilder;
|
||||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
|
||||
/**
|
||||
* Base class that allows access to the {@link UserDetailsService} for using as a default value with {@link AuthenticationManagerBuilder}.
|
||||
*
|
||||
* @author Rob Winch
|
||||
*
|
||||
* @param <B> the type of the {@link ProviderManagerBuilder}
|
||||
* @param <U> the type of {@link UserDetailsService}
|
||||
*/
|
||||
public abstract class UserDetailsAwareConfigurer<B extends ProviderManagerBuilder<B>, U extends UserDetailsService> extends SecurityConfigurerAdapter<AuthenticationManager,B> {
|
||||
|
||||
/**
|
||||
* Gets the {@link UserDetailsService} or null if it is not available
|
||||
* @return the {@link UserDetailsService} or null if it is not available
|
||||
*/
|
||||
public abstract U getUserDetailsService();
|
||||
}
|
||||
+58
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright 2002-2013 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.config.annotation.authentication.configurers.userdetails;
|
||||
|
||||
import org.springframework.security.config.annotation.SecurityConfigurer;
|
||||
import org.springframework.security.config.annotation.authentication.ProviderManagerBuilder;
|
||||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
|
||||
/**
|
||||
* Allows configuring a {@link UserDetailsService} within a {@link AuthenticationManagerBuilder}.
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @since 3.2
|
||||
*
|
||||
* @param <B> the type of the {@link SecurityBuilder}
|
||||
* @param <C> the {@link SecurityConfigurer} (or this)
|
||||
* @param <U> the type of UserDetailsService being used to allow for returning the concrete UserDetailsService.
|
||||
*/
|
||||
public class UserDetailsServiceConfigurer<B extends ProviderManagerBuilder<B>,
|
||||
C extends UserDetailsServiceConfigurer<B, C, U>,
|
||||
U extends UserDetailsService>
|
||||
extends AbstractDaoAuthenticationConfigurer<B, C, U> {
|
||||
|
||||
/**
|
||||
* Creates a new instance
|
||||
* @param userDetailsService the {@link UserDetailsService} that should be used
|
||||
*/
|
||||
public UserDetailsServiceConfigurer(U userDetailsService) {
|
||||
super(userDetailsService);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(B builder) throws Exception {
|
||||
initUserDetailsService();
|
||||
|
||||
super.configure(builder);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows subclasses to initialize the {@link UserDetailsService}. For example, it might add users, initialize
|
||||
* schema, etc.
|
||||
*/
|
||||
protected void initUserDetailsService() throws Exception {}
|
||||
}
|
||||
+77
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Copyright 2002-2013 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.config.annotation.configuration;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.beans.factory.Aware;
|
||||
import org.springframework.beans.factory.DisposableBean;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
|
||||
import org.springframework.security.config.annotation.ObjectPostProcessor;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Allows registering Objects to participate with an
|
||||
* {@link AutowireCapableBeanFactory}'s post processing of {@link Aware}
|
||||
* methods, {@link InitializingBean#afterPropertiesSet()}, and
|
||||
* {@link DisposableBean#destroy()}.
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @since 3.2
|
||||
*/
|
||||
final class AutowireBeanFactoryObjectPostProcessor implements ObjectPostProcessor<Object>, DisposableBean {
|
||||
private final Log logger = LogFactory.getLog(getClass());
|
||||
private final AutowireCapableBeanFactory autowireBeanFactory;
|
||||
private final List<DisposableBean> disposableBeans = new ArrayList<DisposableBean>();
|
||||
|
||||
public AutowireBeanFactoryObjectPostProcessor(
|
||||
AutowireCapableBeanFactory autowireBeanFactory) {
|
||||
Assert.notNull(autowireBeanFactory, "autowireBeanFactory cannot be null");
|
||||
this.autowireBeanFactory = autowireBeanFactory;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.security.config.annotation.web.Initializer#initialize(java.lang.Object)
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public <T> T postProcess(T object) {
|
||||
T result = (T) autowireBeanFactory.initializeBean(object, null);
|
||||
if(result instanceof DisposableBean) {
|
||||
disposableBeans.add((DisposableBean) result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.beans.factory.DisposableBean#destroy()
|
||||
*/
|
||||
@Override
|
||||
public void destroy() throws Exception {
|
||||
for(DisposableBean disposable : disposableBeans) {
|
||||
try {
|
||||
disposable.destroy();
|
||||
} catch(Exception error) {
|
||||
logger.error(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright 2002-2013 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.config.annotation.configuration;
|
||||
|
||||
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.config.annotation.ObjectPostProcessor;
|
||||
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
|
||||
/**
|
||||
* Spring {@link Configuration} that exports the default
|
||||
* {@link ObjectPostProcessor}. This class is not intended to be imported
|
||||
* manually rather it is imported automatically when using
|
||||
* {@link EnableWebSecurity} or {@link EnableGlobalMethodSecurity}.
|
||||
*
|
||||
* @see EnableWebSecurity
|
||||
* @see EnableGlobalMethodSecurity
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @since 3.2
|
||||
*/
|
||||
@Configuration
|
||||
public class ObjectPostProcessorConfiguration {
|
||||
|
||||
@Bean
|
||||
public ObjectPostProcessor<Object> objectPostProcessor(AutowireCapableBeanFactory beanFactory) {
|
||||
return new AutowireBeanFactoryObjectPostProcessor(beanFactory);
|
||||
}
|
||||
}
|
||||
+101
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* Copyright 2002-2013 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.config.annotation.method.configuration;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import org.springframework.context.annotation.AdviceMode;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.security.access.annotation.Secured;
|
||||
import org.springframework.security.config.annotation.configuration.ObjectPostProcessorConfiguration;
|
||||
|
||||
/**
|
||||
* <p>Enables Spring Security global method security similar to the
|
||||
* <global-method-security> xml support.</p>
|
||||
*
|
||||
* <p>
|
||||
* More advanced configurations may wish to extend
|
||||
* {@link GlobalMethodSecurityConfiguration} and override the protected methods
|
||||
* to provide custom implementations. Note that
|
||||
* {@link EnableGlobalMethodSecurity} still must be included on the class
|
||||
* extending {@link GlobalMethodSecurityConfiguration} to determine the
|
||||
* settings.
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @since 3.2
|
||||
*/
|
||||
@Retention(value=java.lang.annotation.RetentionPolicy.RUNTIME)
|
||||
@Target(value={java.lang.annotation.ElementType.TYPE})
|
||||
@Documented
|
||||
@Import({GlobalMethodSecuritySelector.class,ObjectPostProcessorConfiguration.class})
|
||||
public @interface EnableGlobalMethodSecurity {
|
||||
|
||||
/**
|
||||
* Determines if Spring Security's pre post annotations should be enabled. Default is false.
|
||||
* @return true if pre post annotations should be enabled false otherwise.
|
||||
*/
|
||||
boolean prePostEnabled() default false;
|
||||
|
||||
/**
|
||||
* Determines if Spring Security's {@link Secured} annotations should be enabled.
|
||||
* @return true if {@link Secured} annotations should be enabled false otherwise. Default is false.
|
||||
*/
|
||||
boolean securedEnabled() default false;
|
||||
|
||||
/**
|
||||
* Determines if JSR-250 annotations should be enabled. Default is false.
|
||||
* @return true if JSR-250 should be enabled false otherwise.
|
||||
*/
|
||||
boolean jsr250Enabled() default false;
|
||||
|
||||
/**
|
||||
* Indicate whether subclass-based (CGLIB) proxies are to be created ({@code true}) as
|
||||
* opposed to standard Java interface-based proxies ({@code false}). The default is
|
||||
* {@code false}. <strong>Applicable only if {@link #mode()} is set to
|
||||
* {@link AdviceMode#PROXY}</strong>.
|
||||
*
|
||||
* <p>Note that setting this attribute to {@code true} will affect <em>all</em>
|
||||
* Spring-managed beans requiring proxying, not just those marked with
|
||||
* the Security annotations. For example, other beans marked with Spring's
|
||||
* {@code @Transactional} annotation will be upgraded to subclass proxying at the same
|
||||
* time. This approach has no negative impact in practice unless one is explicitly
|
||||
* expecting one type of proxy vs another, e.g. in tests.
|
||||
*
|
||||
* @return true if CGILIB proxies should be created instead of interface based proxies, else false
|
||||
*/
|
||||
boolean proxyTargetClass() default false;
|
||||
|
||||
/**
|
||||
* Indicate how security advice should be applied. The default is
|
||||
* {@link AdviceMode#PROXY}.
|
||||
* @see AdviceMode
|
||||
*
|
||||
* @return the {@link AdviceMode} to use
|
||||
*/
|
||||
AdviceMode mode() default AdviceMode.PROXY;
|
||||
|
||||
/**
|
||||
* Indicate the ordering of the execution of the security advisor
|
||||
* when multiple advices are applied at a specific joinpoint.
|
||||
* The default is {@link Ordered#LOWEST_PRECEDENCE}.
|
||||
*
|
||||
* @return the order the security advisor should be applied
|
||||
*/
|
||||
int order() default Ordered.LOWEST_PRECEDENCE;
|
||||
}
|
||||
+68
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright 2002-2013 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.config.annotation.method.configuration;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.aop.config.AopConfigUtils;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
|
||||
import org.springframework.core.annotation.AnnotationAttributes;
|
||||
import org.springframework.core.type.AnnotationMetadata;
|
||||
|
||||
/**
|
||||
* Registers an
|
||||
* {@link org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator
|
||||
* AnnotationAwareAspectJAutoProxyCreator} against the current
|
||||
* {@link BeanDefinitionRegistry} as appropriate based on a given @
|
||||
* {@link EnableGlobalMethodSecurity} annotation.
|
||||
*
|
||||
* <p>
|
||||
* Note: This class is necessary because AspectJAutoProxyRegistrar only supports
|
||||
* EnableAspectJAutoProxy.
|
||||
* </p>
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @since 3.2
|
||||
*/
|
||||
class GlobalMethodSecurityAspectJAutoProxyRegistrar implements
|
||||
ImportBeanDefinitionRegistrar {
|
||||
|
||||
/**
|
||||
* Register, escalate, and configure the AspectJ auto proxy creator based on
|
||||
* the value of the @{@link EnableGlobalMethodSecurity#proxyTargetClass()}
|
||||
* attribute on the importing {@code @Configuration} class.
|
||||
*/
|
||||
@Override
|
||||
public void registerBeanDefinitions(
|
||||
AnnotationMetadata importingClassMetadata,
|
||||
BeanDefinitionRegistry registry) {
|
||||
|
||||
AopConfigUtils
|
||||
.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
|
||||
|
||||
Map<String, Object> annotationAttributes = importingClassMetadata
|
||||
.getAnnotationAttributes(EnableGlobalMethodSecurity.class
|
||||
.getName());
|
||||
AnnotationAttributes enableAJAutoProxy = AnnotationAttributes
|
||||
.fromMap(annotationAttributes);
|
||||
|
||||
if (enableAJAutoProxy.getBoolean("proxyTargetClass")) {
|
||||
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+393
@@ -0,0 +1,393 @@
|
||||
/*
|
||||
* Copyright 2002-2013 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.config.annotation.method.configuration;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.aopalliance.intercept.MethodInterceptor;
|
||||
import org.springframework.aop.framework.ProxyFactoryBean;
|
||||
import org.springframework.aop.target.LazyInitTargetSource;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.ImportAware;
|
||||
import org.springframework.context.annotation.Role;
|
||||
import org.springframework.core.annotation.AnnotationAttributes;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.core.type.AnnotationMetadata;
|
||||
import org.springframework.security.access.AccessDecisionManager;
|
||||
import org.springframework.security.access.AccessDecisionVoter;
|
||||
import org.springframework.security.access.AfterInvocationProvider;
|
||||
import org.springframework.security.access.annotation.Jsr250MethodSecurityMetadataSource;
|
||||
import org.springframework.security.access.annotation.SecuredAnnotationSecurityMetadataSource;
|
||||
import org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler;
|
||||
import org.springframework.security.access.expression.method.ExpressionBasedAnnotationAttributeFactory;
|
||||
import org.springframework.security.access.expression.method.ExpressionBasedPostInvocationAdvice;
|
||||
import org.springframework.security.access.expression.method.ExpressionBasedPreInvocationAdvice;
|
||||
import org.springframework.security.access.expression.method.MethodSecurityExpressionHandler;
|
||||
import org.springframework.security.access.intercept.AfterInvocationManager;
|
||||
import org.springframework.security.access.intercept.AfterInvocationProviderManager;
|
||||
import org.springframework.security.access.intercept.RunAsManager;
|
||||
import org.springframework.security.access.intercept.aopalliance.MethodSecurityInterceptor;
|
||||
import org.springframework.security.access.intercept.aopalliance.MethodSecurityMetadataSourceAdvisor;
|
||||
import org.springframework.security.access.method.DelegatingMethodSecurityMetadataSource;
|
||||
import org.springframework.security.access.method.MethodSecurityMetadataSource;
|
||||
import org.springframework.security.access.prepost.PostInvocationAdviceProvider;
|
||||
import org.springframework.security.access.prepost.PreInvocationAuthorizationAdvice;
|
||||
import org.springframework.security.access.prepost.PreInvocationAuthorizationAdviceVoter;
|
||||
import org.springframework.security.access.prepost.PrePostAnnotationSecurityMetadataSource;
|
||||
import org.springframework.security.access.vote.AffirmativeBased;
|
||||
import org.springframework.security.access.vote.AuthenticatedVoter;
|
||||
import org.springframework.security.access.vote.RoleVoter;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.authentication.DefaultAuthenticationEventPublisher;
|
||||
import org.springframework.security.config.annotation.ObjectPostProcessor;
|
||||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Base {@link Configuration} for enabling global method security. Classes may
|
||||
* extend this class to customize the defaults, but must be sure to specify the
|
||||
* {@link EnableGlobalMethodSecurity} annotation on the subclass.
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @since 3.2
|
||||
* @see EnableGlobalMethodSecurity
|
||||
*/
|
||||
@Configuration
|
||||
public class GlobalMethodSecurityConfiguration implements ImportAware {
|
||||
private ApplicationContext context;
|
||||
private ObjectPostProcessor<Object> objectPostProcessor = new ObjectPostProcessor<Object>() {
|
||||
@Override
|
||||
public <T> T postProcess(T object) {
|
||||
throw new IllegalStateException(ObjectPostProcessor.class.getName()+ " is a required bean. Ensure you have used @"+EnableGlobalMethodSecurity.class.getName());
|
||||
}
|
||||
};
|
||||
private AuthenticationManager authenticationManager;
|
||||
private AuthenticationManagerBuilder auth = new AuthenticationManagerBuilder();
|
||||
private boolean disableAuthenticationRegistry;
|
||||
private AnnotationAttributes enableMethodSecurity;
|
||||
private MethodSecurityExpressionHandler expressionHandler;
|
||||
|
||||
/**
|
||||
* Creates the default MethodInterceptor which is a MethodSecurityInterceptor using the following methods to
|
||||
* construct it.
|
||||
* <ul>
|
||||
* <li>{@link #accessDecisionManager()}</li>
|
||||
* <li>{@link #afterInvocationManager()}</li>
|
||||
* <li>{@link #authenticationManager()}</li>
|
||||
* <li>{@link #methodSecurityMetadataSource()}</li>
|
||||
* <li>{@link #runAsManager()}</li>
|
||||
*
|
||||
* </ul>
|
||||
*
|
||||
* <p>
|
||||
* Subclasses can override this method to provide a different {@link MethodInterceptor}.
|
||||
* </p>
|
||||
*
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
@Bean
|
||||
public MethodInterceptor methodSecurityInterceptor() throws Exception {
|
||||
MethodSecurityInterceptor methodSecurityInterceptor = new MethodSecurityInterceptor();
|
||||
methodSecurityInterceptor
|
||||
.setAccessDecisionManager(accessDecisionManager());
|
||||
methodSecurityInterceptor
|
||||
.setAfterInvocationManager(afterInvocationManager());
|
||||
methodSecurityInterceptor
|
||||
.setAuthenticationManager(authenticationManager());
|
||||
methodSecurityInterceptor
|
||||
.setSecurityMetadataSource(methodSecurityMetadataSource());
|
||||
RunAsManager runAsManager = runAsManager();
|
||||
if (runAsManager != null) {
|
||||
methodSecurityInterceptor.setRunAsManager(runAsManager);
|
||||
}
|
||||
return methodSecurityInterceptor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide a custom {@link AfterInvocationManager} for the default
|
||||
* implementation of {@link #methodSecurityInterceptor()}. The default is
|
||||
* null if pre post is not enabled. Otherwise, it returns a {@link AfterInvocationProviderManager}.
|
||||
*
|
||||
* <p>
|
||||
* Subclasses should override this method to provide a custom {@link AfterInvocationManager}
|
||||
* </p>
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
protected AfterInvocationManager afterInvocationManager() {
|
||||
if(prePostEnabled()) {
|
||||
AfterInvocationProviderManager invocationProviderManager = new AfterInvocationProviderManager();
|
||||
ExpressionBasedPostInvocationAdvice postAdvice = new ExpressionBasedPostInvocationAdvice(getExpressionHandler());
|
||||
PostInvocationAdviceProvider postInvocationAdviceProvider = new PostInvocationAdviceProvider(postAdvice);
|
||||
List<AfterInvocationProvider> afterInvocationProviders = new ArrayList<AfterInvocationProvider>();
|
||||
afterInvocationProviders.add(postInvocationAdviceProvider);
|
||||
invocationProviderManager.setProviders(afterInvocationProviders);
|
||||
return invocationProviderManager;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide a custom {@link RunAsManager} for the default implementation of
|
||||
* {@link #methodSecurityInterceptor()}. The default is null.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
protected RunAsManager runAsManager() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows subclasses to provide a custom {@link AccessDecisionManager}. The default is a {@link AffirmativeBased}
|
||||
* with the following voters:
|
||||
*
|
||||
* <ul>
|
||||
* <li>{@link PreInvocationAuthorizationAdviceVoter}</li>
|
||||
* <li>{@link RoleVoter} </li>
|
||||
* <li>{@link AuthenticatedVoter} </li>
|
||||
* </ul>
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@SuppressWarnings("rawtypes")
|
||||
protected AccessDecisionManager accessDecisionManager() {
|
||||
List<AccessDecisionVoter> decisionVoters = new ArrayList<AccessDecisionVoter>();
|
||||
ExpressionBasedPreInvocationAdvice expressionAdvice = new ExpressionBasedPreInvocationAdvice();
|
||||
expressionAdvice.setExpressionHandler(getExpressionHandler());
|
||||
|
||||
decisionVoters.add(new PreInvocationAuthorizationAdviceVoter(
|
||||
expressionAdvice));
|
||||
decisionVoters.add(new RoleVoter());
|
||||
decisionVoters.add(new AuthenticatedVoter());
|
||||
return new AffirmativeBased(decisionVoters);
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide a {@link MethodSecurityExpressionHandler} that is
|
||||
* registered with the {@link ExpressionBasedPreInvocationAdvice}. The default is
|
||||
* {@link DefaultMethodSecurityExpressionHandler}
|
||||
*
|
||||
* <p>Subclasses may override this method to provide a custom {@link MethodSecurityExpressionHandler}</p>
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
protected MethodSecurityExpressionHandler expressionHandler() {
|
||||
return new DefaultMethodSecurityExpressionHandler();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the {@link MethodSecurityExpressionHandler} or creates it using {@link #expressionHandler}.
|
||||
*
|
||||
* @return a non {@code null} {@link MethodSecurityExpressionHandler}
|
||||
*/
|
||||
protected final MethodSecurityExpressionHandler getExpressionHandler() {
|
||||
if(expressionHandler == null) {
|
||||
expressionHandler = expressionHandler();
|
||||
}
|
||||
return expressionHandler;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides a custom {@link MethodSecurityMetadataSource} that is registered
|
||||
* with the {@link #methodSecurityMetadataSource()}. Default is null.
|
||||
*
|
||||
* @return a custom {@link MethodSecurityMetadataSource} that is registered
|
||||
* with the {@link #methodSecurityMetadataSource()}
|
||||
*/
|
||||
protected MethodSecurityMetadataSource customMethodSecurityMetadataSource() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows providing a custom {@link AuthenticationManager}. The default is
|
||||
* to use any authentication mechanisms registered by {@link #registerAuthentication(AuthenticationManagerBuilder)}. If
|
||||
* {@link #registerAuthentication(AuthenticationManagerBuilder)} was not overriden, then an {@link AuthenticationManager}
|
||||
* is attempted to be autowired by type.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
protected AuthenticationManager authenticationManager() throws Exception {
|
||||
if(authenticationManager == null) {
|
||||
DefaultAuthenticationEventPublisher eventPublisher = objectPostProcessor.postProcess(new DefaultAuthenticationEventPublisher());
|
||||
auth.authenticationEventPublisher(eventPublisher);
|
||||
auth.objectPostProcessor(objectPostProcessor);
|
||||
registerAuthentication(auth);
|
||||
if(!disableAuthenticationRegistry) {
|
||||
authenticationManager = auth.build();
|
||||
}
|
||||
if(authenticationManager == null) {
|
||||
authenticationManager = lazyBean(AuthenticationManager.class);
|
||||
}
|
||||
}
|
||||
return authenticationManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sub classes can override this method to register different types of authentication. If not overridden,
|
||||
* {@link #registerAuthentication(AuthenticationManagerBuilder)} will attempt to autowire by type.
|
||||
*
|
||||
* @param auth the {@link AuthenticationManagerBuilder} used to register different authentication mechanisms for the
|
||||
* global method security.
|
||||
* @throws Exception
|
||||
*/
|
||||
protected void registerAuthentication(AuthenticationManagerBuilder auth) throws Exception {
|
||||
this.disableAuthenticationRegistry = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides the default {@link MethodSecurityMetadataSource} that will be
|
||||
* used. It creates a {@link DelegatingMethodSecurityMetadataSource} based
|
||||
* upon {@link #customMethodSecurityMetadataSource()} and the attributes on
|
||||
* {@link EnableGlobalMethodSecurity}.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Bean
|
||||
public MethodSecurityMetadataSource methodSecurityMetadataSource() {
|
||||
List<MethodSecurityMetadataSource> sources = new ArrayList<MethodSecurityMetadataSource>();
|
||||
ExpressionBasedAnnotationAttributeFactory attributeFactory = new ExpressionBasedAnnotationAttributeFactory(
|
||||
methodExpressionHandler());
|
||||
MethodSecurityMetadataSource customMethodSecurityMetadataSource = customMethodSecurityMetadataSource();
|
||||
if (customMethodSecurityMetadataSource != null) {
|
||||
sources.add(customMethodSecurityMetadataSource);
|
||||
}
|
||||
if (prePostEnabled()) {
|
||||
sources.add(new PrePostAnnotationSecurityMetadataSource(
|
||||
attributeFactory));
|
||||
}
|
||||
if (securedEnabled()) {
|
||||
sources.add(new SecuredAnnotationSecurityMetadataSource());
|
||||
}
|
||||
if (jsr250Enabled()) {
|
||||
sources.add(new Jsr250MethodSecurityMetadataSource());
|
||||
}
|
||||
return new DelegatingMethodSecurityMetadataSource(sources);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the {@link MethodSecurityExpressionHandler} to be used.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Bean
|
||||
public MethodSecurityExpressionHandler methodExpressionHandler() {
|
||||
return new DefaultMethodSecurityExpressionHandler();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the {@link PreInvocationAuthorizationAdvice} to be used. The
|
||||
* default is {@link ExpressionBasedPreInvocationAdvice}.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Bean
|
||||
public PreInvocationAuthorizationAdvice preInvocationAuthorizationAdvice() {
|
||||
ExpressionBasedPreInvocationAdvice preInvocationAdvice = new ExpressionBasedPreInvocationAdvice();
|
||||
preInvocationAdvice.setExpressionHandler(methodExpressionHandler());
|
||||
return preInvocationAdvice;
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains the {@link MethodSecurityMetadataSourceAdvisor} to be used.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
|
||||
@Bean
|
||||
public MethodSecurityMetadataSourceAdvisor metaDataSourceAdvisor() {
|
||||
MethodSecurityMetadataSourceAdvisor methodAdvisor = new MethodSecurityMetadataSourceAdvisor(
|
||||
"methodSecurityInterceptor", methodSecurityMetadataSource(),
|
||||
"methodSecurityMetadataSource");
|
||||
methodAdvisor.setOrder(order());
|
||||
return methodAdvisor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains the attributes from {@link EnableGlobalMethodSecurity} if this class was imported using the {@link EnableGlobalMethodSecurity} annotation.
|
||||
*/
|
||||
@Override
|
||||
public final void setImportMetadata(AnnotationMetadata importMetadata) {
|
||||
Map<String, Object> annotationAttributes = importMetadata
|
||||
.getAnnotationAttributes(EnableGlobalMethodSecurity.class
|
||||
.getName());
|
||||
enableMethodSecurity = AnnotationAttributes
|
||||
.fromMap(annotationAttributes);
|
||||
}
|
||||
|
||||
@Autowired
|
||||
public void setApplicationContext(ApplicationContext context) {
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
@Autowired(required=false)
|
||||
public void setObjectPostProcessor(ObjectPostProcessor<Object> objectPostProcessor) {
|
||||
this.objectPostProcessor = objectPostProcessor;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private <T> T lazyBean(Class<T> interfaceName) {
|
||||
LazyInitTargetSource lazyTargetSource = new LazyInitTargetSource();
|
||||
String[] beanNamesForType = context.getBeanNamesForType(interfaceName);
|
||||
Assert.isTrue(beanNamesForType.length == 1 , "Expecting to only find a single bean for type " + interfaceName + ", but found " + Arrays.asList(beanNamesForType));
|
||||
lazyTargetSource.setTargetBeanName(beanNamesForType[0]);
|
||||
lazyTargetSource.setBeanFactory(context);
|
||||
ProxyFactoryBean proxyFactory = new ProxyFactoryBean();
|
||||
proxyFactory.setTargetSource(lazyTargetSource);
|
||||
proxyFactory.setInterfaces(new Class[] { interfaceName });
|
||||
return (T) proxyFactory.getObject();
|
||||
}
|
||||
|
||||
private boolean prePostEnabled() {
|
||||
return enableMethodSecurity().getBoolean("prePostEnabled");
|
||||
}
|
||||
|
||||
private boolean securedEnabled() {
|
||||
return enableMethodSecurity().getBoolean("securedEnabled");
|
||||
}
|
||||
|
||||
private boolean jsr250Enabled() {
|
||||
return enableMethodSecurity().getBoolean("jsr250Enabled");
|
||||
}
|
||||
|
||||
private int order() {
|
||||
return (Integer) enableMethodSecurity().get("order");
|
||||
}
|
||||
|
||||
private AnnotationAttributes enableMethodSecurity() {
|
||||
if (enableMethodSecurity == null) {
|
||||
// if it is null look at this instance (i.e. a subclass was used)
|
||||
EnableGlobalMethodSecurity methodSecurityAnnotation = AnnotationUtils
|
||||
.findAnnotation(getClass(),
|
||||
EnableGlobalMethodSecurity.class);
|
||||
Assert.notNull(methodSecurityAnnotation,
|
||||
EnableGlobalMethodSecurity.class.getName() + " is required");
|
||||
Map<String, Object> methodSecurityAttrs = AnnotationUtils
|
||||
.getAnnotationAttributes(methodSecurityAnnotation);
|
||||
this.enableMethodSecurity = AnnotationAttributes
|
||||
.fromMap(methodSecurityAttrs);
|
||||
}
|
||||
return this.enableMethodSecurity;
|
||||
}
|
||||
|
||||
}
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright 2002-2013 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.config.annotation.method.configuration;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.context.annotation.AdviceMode;
|
||||
import org.springframework.context.annotation.AutoProxyRegistrar;
|
||||
import org.springframework.context.annotation.ImportSelector;
|
||||
import org.springframework.core.annotation.AnnotationAttributes;
|
||||
import org.springframework.core.type.AnnotationMetadata;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
/**
|
||||
* Dynamically determines which imports to include using the
|
||||
* {@link EnableGlobalMethodSecurity} annotation.
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @since 3.2
|
||||
*/
|
||||
final class GlobalMethodSecuritySelector implements ImportSelector {
|
||||
|
||||
@Override
|
||||
public final String[] selectImports(AnnotationMetadata importingClassMetadata) {
|
||||
Class<EnableGlobalMethodSecurity> annoType = EnableGlobalMethodSecurity.class;
|
||||
Map<String, Object> annotationAttributes = importingClassMetadata.getAnnotationAttributes(annoType.getName(), false);
|
||||
AnnotationAttributes attributes = AnnotationAttributes.fromMap(annotationAttributes);
|
||||
Assert.notNull(attributes, String.format(
|
||||
"@%s is not present on importing class '%s' as expected",
|
||||
annoType.getSimpleName(), importingClassMetadata.getClassName()));
|
||||
|
||||
// TODO would be nice if could use BeanClassLoaderAware (does not work)
|
||||
Class<?> importingClass = ClassUtils.resolveClassName(importingClassMetadata.getClassName(), ClassUtils.getDefaultClassLoader());
|
||||
boolean skipMethodSecurityConfiguration = GlobalMethodSecurityConfiguration.class.isAssignableFrom(importingClass);
|
||||
|
||||
AdviceMode mode = attributes.getEnum("mode");
|
||||
String autoProxyClassName = AdviceMode.PROXY == mode ? AutoProxyRegistrar.class.getName()
|
||||
: GlobalMethodSecurityAspectJAutoProxyRegistrar.class.getName();
|
||||
if(skipMethodSecurityConfiguration) {
|
||||
return new String[] { autoProxyClassName };
|
||||
}
|
||||
return new String[] { autoProxyClassName,
|
||||
GlobalMethodSecurityConfiguration.class.getName()};
|
||||
}
|
||||
}
|
||||
+198
@@ -0,0 +1,198 @@
|
||||
/*
|
||||
* Copyright 2002-2013 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.config.annotation.web;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.security.config.annotation.SecurityBuilder;
|
||||
import org.springframework.security.config.annotation.SecurityConfigurerAdapter;
|
||||
import org.springframework.security.config.annotation.web.configurers.AbstractRequestMatcherMappingConfigurer;
|
||||
import org.springframework.security.web.util.AntPathRequestMatcher;
|
||||
import org.springframework.security.web.util.AnyRequestMatcher;
|
||||
import org.springframework.security.web.util.RegexRequestMatcher;
|
||||
import org.springframework.security.web.util.RequestMatcher;
|
||||
|
||||
/**
|
||||
* A base class for registering {@link RequestMatcher}'s. For example, it might allow for specifying which
|
||||
* {@link RequestMatcher} require a certain level of authorization.
|
||||
*
|
||||
*
|
||||
* @param <B> The Builder that is building Object O and is configured by this {@link AbstractRequestMatcherMappingConfigurer}
|
||||
* @param <C> The object that is returned or Chained after creating the RequestMatcher
|
||||
* @param <O> The Object being built by Builder B
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @since 3.2
|
||||
*/
|
||||
public abstract class AbstractRequestMatcherConfigurer<B extends SecurityBuilder<O>,C,O> extends SecurityConfigurerAdapter<O,B> {
|
||||
private static final RequestMatcher ANY_REQUEST = new AnyRequestMatcher();
|
||||
/**
|
||||
* Maps any request.
|
||||
*
|
||||
* @param method the {@link HttpMethod} to use or {@code null} for any {@link HttpMethod}.
|
||||
* @param antPatterns the ant patterns to create {@link org.springframework.security.web.util.AntPathRequestMatcher}
|
||||
* from
|
||||
*
|
||||
* @return the object that is chained after creating the {@link RequestMatcher}
|
||||
*/
|
||||
public C anyRequest() {
|
||||
return requestMatchers(ANY_REQUEST);
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps a {@link List} of {@link org.springframework.security.web.util.AntPathRequestMatcher} instances.
|
||||
*
|
||||
* @param method the {@link HttpMethod} to use or {@code null} for any {@link HttpMethod}.
|
||||
* @param antPatterns the ant patterns to create {@link org.springframework.security.web.util.AntPathRequestMatcher}
|
||||
* from
|
||||
*
|
||||
* @return the object that is chained after creating the {@link RequestMatcher}
|
||||
*/
|
||||
public C antMatchers(HttpMethod method, String... antPatterns) {
|
||||
return chainRequestMatchers(RequestMatchers.antMatchers(method, antPatterns));
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps a {@link List} of {@link org.springframework.security.web.util.AntPathRequestMatcher} instances that do
|
||||
* not care which {@link HttpMethod} is used.
|
||||
*
|
||||
* @param antPatterns the ant patterns to create {@link org.springframework.security.web.util.AntPathRequestMatcher}
|
||||
* from
|
||||
*
|
||||
* @return the object that is chained after creating the {@link RequestMatcher}
|
||||
*/
|
||||
public C antMatchers(String... antPatterns) {
|
||||
return chainRequestMatchers(RequestMatchers.antMatchers(antPatterns));
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps a {@link List} of {@link org.springframework.security.web.util.RegexRequestMatcher} instances.
|
||||
*
|
||||
* @param method the {@link HttpMethod} to use or {@code null} for any {@link HttpMethod}.
|
||||
* @param regexPatterns the regular expressions to create
|
||||
* {@link org.springframework.security.web.util.RegexRequestMatcher} from
|
||||
*
|
||||
* @return the object that is chained after creating the {@link RequestMatcher}
|
||||
*/
|
||||
public C regexMatchers(HttpMethod method, String... regexPatterns) {
|
||||
return chainRequestMatchers(RequestMatchers.regexMatchers(method,
|
||||
regexPatterns));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a {@link List} of {@link org.springframework.security.web.util.RegexRequestMatcher} instances that do not
|
||||
* specify an {@link HttpMethod}.
|
||||
*
|
||||
* @param regexPatterns the regular expressions to create
|
||||
* {@link org.springframework.security.web.util.RegexRequestMatcher} from
|
||||
*
|
||||
* @return the object that is chained after creating the {@link RequestMatcher}
|
||||
*/
|
||||
public C regexMatchers(String... regexPatterns) {
|
||||
return chainRequestMatchers(RequestMatchers.regexMatchers(regexPatterns));
|
||||
}
|
||||
|
||||
/**
|
||||
* Associates a list of {@link RequestMatcher} instances with the {@link AbstractRequestMatcherMappingConfigurer}
|
||||
*
|
||||
* @param requestMatchers the {@link RequestMatcher} instances
|
||||
*
|
||||
* @return the object that is chained after creating the {@link RequestMatcher}
|
||||
*/
|
||||
public C requestMatchers(RequestMatcher... requestMatchers) {
|
||||
return chainRequestMatchers(Arrays.asList(requestMatchers));
|
||||
}
|
||||
|
||||
/**
|
||||
* Subclasses should implement this method for returning the object that is chained to the creation of the
|
||||
* {@link RequestMatcher} instances.
|
||||
*
|
||||
* @param requestMatchers the {@link RequestMatcher} instances that were created
|
||||
* @return the chained Object for the subclass which allows association of something else to the
|
||||
* {@link RequestMatcher}
|
||||
*/
|
||||
protected abstract C chainRequestMatchers(List<RequestMatcher> requestMatchers);
|
||||
|
||||
/**
|
||||
* Utilities for creating {@link RequestMatcher} instances.
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @since 3.2
|
||||
*/
|
||||
private static final class RequestMatchers {
|
||||
|
||||
/**
|
||||
* Create a {@link List} of {@link AntPathRequestMatcher} instances.
|
||||
*
|
||||
* @param httpMethod the {@link HttpMethod} to use or {@code null} for any {@link HttpMethod}.
|
||||
* @param antPatterns the ant patterns to create {@link AntPathRequestMatcher} from
|
||||
*
|
||||
* @return a {@link List} of {@link AntPathRequestMatcher} instances
|
||||
*/
|
||||
public static List<RequestMatcher> antMatchers(HttpMethod httpMethod, String...antPatterns) {
|
||||
String method = httpMethod == null ? null : httpMethod.toString();
|
||||
List<RequestMatcher> matchers = new ArrayList<RequestMatcher>();
|
||||
for(String pattern : antPatterns) {
|
||||
matchers.add(new AntPathRequestMatcher(pattern, method));
|
||||
}
|
||||
return matchers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a {@link List} of {@link AntPathRequestMatcher} instances that do not specify an {@link HttpMethod}.
|
||||
*
|
||||
* @param antPatterns the ant patterns to create {@link AntPathRequestMatcher} from
|
||||
*
|
||||
* @return a {@link List} of {@link AntPathRequestMatcher} instances
|
||||
*/
|
||||
public static List<RequestMatcher> antMatchers(String...antPatterns) {
|
||||
return antMatchers(null, antPatterns);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a {@link List} of {@link RegexRequestMatcher} instances.
|
||||
*
|
||||
* @param httpMethod the {@link HttpMethod} to use or {@code null} for any {@link HttpMethod}.
|
||||
* @param regexPatterns the regular expressions to create {@link RegexRequestMatcher} from
|
||||
*
|
||||
* @return a {@link List} of {@link RegexRequestMatcher} instances
|
||||
*/
|
||||
public static List<RequestMatcher> regexMatchers(HttpMethod httpMethod, String...regexPatterns) {
|
||||
String method = httpMethod == null ? null : httpMethod.toString();
|
||||
List<RequestMatcher> matchers = new ArrayList<RequestMatcher>();
|
||||
for(String pattern : regexPatterns) {
|
||||
matchers.add(new RegexRequestMatcher(pattern, method));
|
||||
}
|
||||
return matchers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a {@link List} of {@link RegexRequestMatcher} instances that do not specify an {@link HttpMethod}.
|
||||
*
|
||||
* @param regexPatterns the regular expressions to create {@link RegexRequestMatcher} from
|
||||
*
|
||||
* @return a {@link List} of {@link RegexRequestMatcher} instances
|
||||
*/
|
||||
public static List<RequestMatcher> regexMatchers(String...regexPatterns) {
|
||||
return regexMatchers(null, regexPatterns);
|
||||
}
|
||||
|
||||
private RequestMatchers() {}
|
||||
}
|
||||
}
|
||||
+177
@@ -0,0 +1,177 @@
|
||||
/*
|
||||
* Copyright 2002-2013 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.config.annotation.web;
|
||||
|
||||
import javax.servlet.Filter;
|
||||
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.authentication.AuthenticationProvider;
|
||||
import org.springframework.security.config.annotation.SecurityBuilder;
|
||||
import org.springframework.security.config.annotation.SecurityConfigurer;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
import org.springframework.security.openid.OpenIDAuthenticationFilter;
|
||||
import org.springframework.security.web.DefaultSecurityFilterChain;
|
||||
import org.springframework.security.web.access.ExceptionTranslationFilter;
|
||||
import org.springframework.security.web.access.channel.ChannelProcessingFilter;
|
||||
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
|
||||
import org.springframework.security.web.authentication.AnonymousAuthenticationFilter;
|
||||
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
|
||||
import org.springframework.security.web.authentication.logout.LogoutFilter;
|
||||
import org.springframework.security.web.authentication.preauth.AbstractPreAuthenticatedProcessingFilter;
|
||||
import org.springframework.security.web.authentication.preauth.x509.X509AuthenticationFilter;
|
||||
import org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationFilter;
|
||||
import org.springframework.security.web.authentication.switchuser.SwitchUserFilter;
|
||||
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
|
||||
import org.springframework.security.web.authentication.www.DigestAuthenticationFilter;
|
||||
import org.springframework.security.web.context.SecurityContextPersistenceFilter;
|
||||
import org.springframework.security.web.jaasapi.JaasApiIntegrationFilter;
|
||||
import org.springframework.security.web.savedrequest.RequestCacheAwareFilter;
|
||||
import org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter;
|
||||
import org.springframework.security.web.session.ConcurrentSessionFilter;
|
||||
import org.springframework.security.web.session.SessionManagementFilter;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Rob Winch
|
||||
*
|
||||
* @param <H>
|
||||
*/
|
||||
public interface HttpSecurityBuilder<H extends HttpSecurityBuilder<H>> extends SecurityBuilder<DefaultSecurityFilterChain> {
|
||||
|
||||
/**
|
||||
* Gets the {@link SecurityConfigurer} by its class name or
|
||||
* <code>null</code> if not found. Note that object hierarchies are not
|
||||
* considered.
|
||||
*
|
||||
* @param clazz the Class of the {@link SecurityConfigurer} to attempt to get.
|
||||
*/
|
||||
<C extends SecurityConfigurer<DefaultSecurityFilterChain, H>> C getConfigurer(
|
||||
Class<C> clazz);
|
||||
|
||||
/**
|
||||
* Removes the {@link SecurityConfigurer} by its class name or
|
||||
* <code>null</code> if not found. Note that object hierarchies are not
|
||||
* considered.
|
||||
*
|
||||
* @param clazz the Class of the {@link SecurityConfigurer} to attempt to remove.
|
||||
* @return the {@link SecurityConfigurer} that was removed or null if not found
|
||||
*/
|
||||
<C extends SecurityConfigurer<DefaultSecurityFilterChain, H>> C removeConfigurer(Class<C> clazz);
|
||||
|
||||
/**
|
||||
* Sets an object that is shared by multiple {@link SecurityConfigurer}.
|
||||
*
|
||||
* @param sharedType the Class to key the shared object by.
|
||||
* @param object the Object to store
|
||||
*/
|
||||
<C> void setSharedObject(Class<C> sharedType, C object);
|
||||
|
||||
/**
|
||||
* Gets a shared Object. Note that object heirarchies are not considered.
|
||||
*
|
||||
* @param sharedType the type of the shared Object
|
||||
* @return the shared Object or null if it is not found
|
||||
*/
|
||||
<C> C getSharedObject(Class<C> sharedType);
|
||||
|
||||
/**
|
||||
* Allows adding an additional {@link AuthenticationProvider} to be used
|
||||
*
|
||||
* @param authenticationProvider the {@link AuthenticationProvider} to be added
|
||||
* @return the {@link HttpSecurity} for further customizations
|
||||
*/
|
||||
H authenticationProvider(
|
||||
AuthenticationProvider authenticationProvider);
|
||||
|
||||
/**
|
||||
* Allows adding an additional {@link UserDetailsService} to be used
|
||||
*
|
||||
* @param userDetailsService the {@link UserDetailsService} to be added
|
||||
* @return the {@link HttpSecurity} for further customizations
|
||||
*/
|
||||
H userDetailsService(
|
||||
UserDetailsService userDetailsService) throws Exception;
|
||||
|
||||
/**
|
||||
* Allows adding a {@link Filter} after one of the known {@link Filter}
|
||||
* classes. The known {@link Filter} instances are either a {@link Filter}
|
||||
* listed in {@link #addFilter(Filter)} or a {@link Filter} that has already
|
||||
* been added using {@link #addFilterAfter(Filter, Class)} or
|
||||
* {@link #addFilterBefore(Filter, Class)}.
|
||||
*
|
||||
* @param filter the {@link Filter} to register before the type {@code afterFilter}
|
||||
* @param afterFilter the Class of the known {@link Filter}.
|
||||
* @return the {@link HttpSecurity} for further customizations
|
||||
*/
|
||||
H addFilterAfter(Filter filter,
|
||||
Class<? extends Filter> afterFilter);
|
||||
|
||||
/**
|
||||
* Allows adding a {@link Filter} before one of the known {@link Filter}
|
||||
* classes. The known {@link Filter} instances are either a {@link Filter}
|
||||
* listed in {@link #addFilter(Filter)} or a {@link Filter} that has already
|
||||
* been added using {@link #addFilterAfter(Filter, Class)} or
|
||||
* {@link #addFilterBefore(Filter, Class)}.
|
||||
*
|
||||
* @param filter the {@link Filter} to register before the type {@code beforeFilter}
|
||||
* @param beforeFilter the Class of the known {@link Filter}.
|
||||
* @return the {@link HttpSecurity} for further customizations
|
||||
*/
|
||||
H addFilterBefore(Filter filter,
|
||||
Class<? extends Filter> beforeFilter);
|
||||
|
||||
/**
|
||||
* Adds a {@link Filter} that must be an instance of or extend one of the
|
||||
* Filters provided within the Security framework. The method ensures that
|
||||
* the ordering of the Filters is automatically taken care of.
|
||||
*
|
||||
* The ordering of the Filters is:
|
||||
*
|
||||
* <ul>
|
||||
* <li>{@link ChannelProcessingFilter}</li>
|
||||
* <li>{@link ConcurrentSessionFilter}</li>
|
||||
* <li>{@link SecurityContextPersistenceFilter}</li>
|
||||
* <li>{@link LogoutFilter}</li>
|
||||
* <li>{@link X509AuthenticationFilter}</li>
|
||||
* <li>{@link AbstractPreAuthenticatedProcessingFilter}</li>
|
||||
* <li>{@link org.springframework.security.cas.web.CasAuthenticationFilter}</li>
|
||||
* <li>{@link UsernamePasswordAuthenticationFilter}</li>
|
||||
* <li>{@link ConcurrentSessionFilter}</li>
|
||||
* <li>{@link OpenIDAuthenticationFilter}</li>
|
||||
* <li>{@link DefaultLoginPageViewFilter}</li>
|
||||
* <li>{@link ConcurrentSessionFilter}</li>
|
||||
* <li>{@link DigestAuthenticationFilter}</li>
|
||||
* <li>{@link BasicAuthenticationFilter}</li>
|
||||
* <li>{@link RequestCacheAwareFilter}</li>
|
||||
* <li>{@link SecurityContextHolderAwareRequestFilter}</li>
|
||||
* <li>{@link JaasApiIntegrationFilter}</li>
|
||||
* <li>{@link RememberMeAuthenticationFilter}</li>
|
||||
* <li>{@link AnonymousAuthenticationFilter}</li>
|
||||
* <li>{@link SessionManagementFilter}</li>
|
||||
* <li>{@link ExceptionTranslationFilter}</li>
|
||||
* <li>{@link FilterSecurityInterceptor}</li>
|
||||
* <li>{@link SwitchUserFilter}</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param filter the {@link Filter} to add
|
||||
* @return the {@link HttpSecurity} for further customizations
|
||||
*/
|
||||
H addFilter(Filter filter);
|
||||
|
||||
// FIXME shared object or explicit?
|
||||
AuthenticationManager getAuthenticationManager();
|
||||
}
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright 2002-2013 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.config.annotation.web;
|
||||
|
||||
import javax.servlet.Filter;
|
||||
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.config.annotation.SecurityBuilder;
|
||||
import org.springframework.security.config.annotation.SecurityConfigurer;
|
||||
import org.springframework.security.config.annotation.web.builders.WebSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
|
||||
/**
|
||||
* Allows customization to the {@link WebSecurity}. In most instances
|
||||
* users will use {@link EnableWebSecurity} and a create {@link Configuration}
|
||||
* that extends {@link WebSecurityConfigurerAdapter} which will automatically be
|
||||
* applied to the {@link WebSecurity} by the {@link EnableWebSecurity}
|
||||
* annotation.
|
||||
*
|
||||
* @see WebSecurityConfigurerAdapter
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @since 3.2
|
||||
*/
|
||||
public interface WebSecurityConfigurer<T extends SecurityBuilder<Filter>> extends SecurityConfigurer<Filter, T> {
|
||||
|
||||
}
|
||||
+191
@@ -0,0 +1,191 @@
|
||||
/*
|
||||
* Copyright 2002-2013 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.config.annotation.web.builders;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.util.List;
|
||||
|
||||
import javax.servlet.Filter;
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.FilterConfig;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletRequestWrapper;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.http.HttpSession;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.security.web.FilterChainProxy;
|
||||
import org.springframework.security.web.SecurityFilterChain;
|
||||
import org.springframework.security.web.util.UrlUtils;
|
||||
|
||||
/**
|
||||
* Spring Security debugging filter.
|
||||
* <p>
|
||||
* Logs information (such as session creation) to help the user understand how requests are being handled
|
||||
* by Spring Security and provide them with other relevant information (such as when sessions are being created).
|
||||
*
|
||||
*
|
||||
* @author Luke Taylor
|
||||
* @author Rob Winch
|
||||
* @since 3.1
|
||||
*/
|
||||
class DebugFilter implements Filter {
|
||||
private static final String ALREADY_FILTERED_ATTR_NAME = DebugFilter.class.getName().concat(".FILTERED");
|
||||
|
||||
private final FilterChainProxy fcp;
|
||||
private final Logger logger = new Logger();
|
||||
|
||||
public DebugFilter(FilterChainProxy fcp) {
|
||||
this.fcp = fcp;
|
||||
}
|
||||
|
||||
public final void doFilter(ServletRequest srvltRequest, ServletResponse srvltResponse, FilterChain filterChain)
|
||||
throws ServletException, IOException {
|
||||
|
||||
if (!(srvltRequest instanceof HttpServletRequest) || !(srvltResponse instanceof HttpServletResponse)) {
|
||||
throw new ServletException("DebugFilter just supports HTTP requests");
|
||||
}
|
||||
HttpServletRequest request = (HttpServletRequest) srvltRequest;
|
||||
HttpServletResponse response = (HttpServletResponse) srvltResponse;
|
||||
|
||||
List<Filter> filters = getFilters(request);
|
||||
logger.log("Request received for '" + UrlUtils.buildRequestUrl(request) + "':\n\n" +
|
||||
request + "\n\n" +
|
||||
"servletPath:" + request.getServletPath() + "\n" +
|
||||
"pathInfo:" + request.getPathInfo() + "\n\n" +
|
||||
formatFilters(filters));
|
||||
|
||||
if (request.getAttribute(ALREADY_FILTERED_ATTR_NAME) == null) {
|
||||
invokeWithWrappedRequest(request, response, filterChain);
|
||||
} else {
|
||||
fcp.doFilter(request, response, filterChain);
|
||||
}
|
||||
}
|
||||
|
||||
private void invokeWithWrappedRequest(HttpServletRequest request,
|
||||
HttpServletResponse response, FilterChain filterChain) throws IOException, ServletException {
|
||||
request.setAttribute(ALREADY_FILTERED_ATTR_NAME, Boolean.TRUE);
|
||||
request = new DebugRequestWrapper(request);
|
||||
try {
|
||||
fcp.doFilter(request, response, filterChain);
|
||||
}
|
||||
finally {
|
||||
request.removeAttribute(ALREADY_FILTERED_ATTR_NAME);
|
||||
}
|
||||
}
|
||||
|
||||
String formatFilters(List<Filter> filters) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("Security filter chain: ");
|
||||
if (filters == null) {
|
||||
sb.append("no match");
|
||||
} else if (filters.isEmpty()) {
|
||||
sb.append("[] empty (bypassed by security='none') ");
|
||||
} else {
|
||||
sb.append("[\n");
|
||||
for (Filter f : filters) {
|
||||
sb.append(" ").append(f.getClass().getSimpleName()).append("\n");
|
||||
}
|
||||
sb.append("]");
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private List<Filter> getFilters(HttpServletRequest request) {
|
||||
for (SecurityFilterChain chain : fcp.getFilterChains()) {
|
||||
if (chain.matches(request)) {
|
||||
return chain.getFilters();
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public void init(FilterConfig filterConfig) throws ServletException {
|
||||
}
|
||||
|
||||
public void destroy() {
|
||||
}
|
||||
}
|
||||
|
||||
class DebugRequestWrapper extends HttpServletRequestWrapper {
|
||||
private static final Logger logger = new Logger();
|
||||
|
||||
public DebugRequestWrapper(HttpServletRequest request) {
|
||||
super(request);
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpSession getSession() {
|
||||
boolean sessionExists = super.getSession(false) != null;
|
||||
HttpSession session = super.getSession();
|
||||
|
||||
if (!sessionExists) {
|
||||
logger.log("New HTTP session created: " + session.getId(), true);
|
||||
}
|
||||
|
||||
return session;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpSession getSession(boolean create) {
|
||||
if (!create) {
|
||||
return super.getSession(create);
|
||||
}
|
||||
return getSession();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Controls output for the Spring Security debug feature.
|
||||
*
|
||||
* @author Luke Taylor
|
||||
* @since 3.1
|
||||
*/
|
||||
final class Logger {
|
||||
final static Log logger = LogFactory.getLog("Spring Security Debugger");
|
||||
|
||||
void log(String message) {
|
||||
log(message, false);
|
||||
}
|
||||
|
||||
void log(String message, boolean dumpStack) {
|
||||
StringBuilder output = new StringBuilder(256);
|
||||
output.append("\n\n************************************************************\n\n");
|
||||
output.append(message).append("\n");
|
||||
|
||||
if (dumpStack) {
|
||||
StringWriter os = new StringWriter();
|
||||
new Exception().printStackTrace(new PrintWriter(os));
|
||||
StringBuffer buffer = os.getBuffer();
|
||||
// Remove the exception in case it scares people.
|
||||
int start = buffer.indexOf("java.lang.Exception");
|
||||
buffer.replace(start, start + 19, "");
|
||||
output.append("\nCall stack: \n").append(os.toString());
|
||||
}
|
||||
|
||||
output.append("\n\n************************************************************\n\n");
|
||||
|
||||
logger.info(output.toString());
|
||||
}
|
||||
}
|
||||
+173
@@ -0,0 +1,173 @@
|
||||
/*
|
||||
* Copyright 2002-2013 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.config.annotation.web.builders;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.Filter;
|
||||
|
||||
import org.springframework.security.web.access.ExceptionTranslationFilter;
|
||||
import org.springframework.security.web.access.channel.ChannelProcessingFilter;
|
||||
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
|
||||
import org.springframework.security.web.authentication.AnonymousAuthenticationFilter;
|
||||
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
|
||||
import org.springframework.security.web.authentication.logout.LogoutFilter;
|
||||
import org.springframework.security.web.authentication.preauth.AbstractPreAuthenticatedProcessingFilter;
|
||||
import org.springframework.security.web.authentication.preauth.x509.X509AuthenticationFilter;
|
||||
import org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationFilter;
|
||||
import org.springframework.security.web.authentication.switchuser.SwitchUserFilter;
|
||||
import org.springframework.security.web.authentication.ui.DefaultLoginPageViewFilter;
|
||||
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
|
||||
import org.springframework.security.web.authentication.www.DigestAuthenticationFilter;
|
||||
import org.springframework.security.web.context.SecurityContextPersistenceFilter;
|
||||
import org.springframework.security.web.jaasapi.JaasApiIntegrationFilter;
|
||||
import org.springframework.security.web.savedrequest.RequestCacheAwareFilter;
|
||||
import org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter;
|
||||
import org.springframework.security.web.session.ConcurrentSessionFilter;
|
||||
import org.springframework.security.web.session.SessionManagementFilter;
|
||||
|
||||
/**
|
||||
* An internal use only {@link Comparator} that sorts the Security {@link Filter} instances to ensure they are in the
|
||||
* correct order.
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @since 3.2
|
||||
*/
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
final class FilterComparator implements Comparator<Filter>, Serializable {
|
||||
private static final int STEP = 100;
|
||||
private Map<String,Integer> filterToOrder = new HashMap<String,Integer>();
|
||||
|
||||
FilterComparator() {
|
||||
int order = 100;
|
||||
put(ChannelProcessingFilter.class, order);
|
||||
order += STEP;
|
||||
put(ConcurrentSessionFilter.class, order);
|
||||
order += STEP;
|
||||
put(SecurityContextPersistenceFilter.class, order);
|
||||
order += STEP;
|
||||
put(LogoutFilter.class, order);
|
||||
order += STEP;
|
||||
put(X509AuthenticationFilter.class, order);
|
||||
order += STEP;
|
||||
put(AbstractPreAuthenticatedProcessingFilter.class, order);
|
||||
order += STEP;
|
||||
filterToOrder.put("org.springframework.security.cas.web.CasAuthenticationFilter", order);
|
||||
order += STEP;
|
||||
put(UsernamePasswordAuthenticationFilter.class, order);
|
||||
order += STEP;
|
||||
put(ConcurrentSessionFilter.class, order);
|
||||
order += STEP;
|
||||
filterToOrder.put("org.springframework.security.openid.OpenIDAuthenticationFilter", order);
|
||||
order += STEP;
|
||||
put(DefaultLoginPageViewFilter.class, order);
|
||||
order += STEP;
|
||||
put(ConcurrentSessionFilter.class, order);
|
||||
order += STEP;
|
||||
put(DigestAuthenticationFilter.class, order);
|
||||
order += STEP;
|
||||
put(BasicAuthenticationFilter.class, order);
|
||||
order += STEP;
|
||||
put(RequestCacheAwareFilter.class, order);
|
||||
order += STEP;
|
||||
put(SecurityContextHolderAwareRequestFilter.class, order);
|
||||
order += STEP;
|
||||
put(JaasApiIntegrationFilter.class, order);
|
||||
order += STEP;
|
||||
put(RememberMeAuthenticationFilter.class, order);
|
||||
order += STEP;
|
||||
put(AnonymousAuthenticationFilter.class, order);
|
||||
order += STEP;
|
||||
put(SessionManagementFilter.class, order);
|
||||
order += STEP;
|
||||
put(ExceptionTranslationFilter.class, order);
|
||||
order += STEP;
|
||||
put(FilterSecurityInterceptor.class, order);
|
||||
order += STEP;
|
||||
put(SwitchUserFilter.class, order);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compare(Filter lhs, Filter rhs) {
|
||||
Integer left = getOrder(lhs.getClass());
|
||||
Integer right = getOrder(rhs.getClass());
|
||||
return left - right;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if a particular {@link Filter} is registered to be sorted
|
||||
*
|
||||
* @param filter
|
||||
* @return
|
||||
*/
|
||||
public boolean isRegistered(Class<? extends Filter> filter) {
|
||||
return getOrder(filter) != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a {@link Filter} to exist after a particular {@link Filter} that is already registered.
|
||||
* @param filter the {@link Filter} to register
|
||||
* @param afterFilter the {@link Filter} that is already registered and that {@code filter} should be placed after.
|
||||
*/
|
||||
public void registerAfter(Class<? extends Filter> filter, Class<? extends Filter> afterFilter) {
|
||||
Integer position = getOrder(afterFilter);
|
||||
if(position == null) {
|
||||
throw new IllegalArgumentException("Cannot register after unregistered Filter "+afterFilter);
|
||||
}
|
||||
|
||||
put(filter, position + 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a {@link Filter} to exist before a particular {@link Filter} that is already registered.
|
||||
* @param filter the {@link Filter} to register
|
||||
* @param beforeFilter the {@link Filter} that is already registered and that {@code filter} should be placed before.
|
||||
*/
|
||||
public void registerBefore(Class<? extends Filter> filter, Class<? extends Filter> beforeFilter) {
|
||||
Integer position = getOrder(beforeFilter);
|
||||
if(position == null) {
|
||||
throw new IllegalArgumentException("Cannot register after unregistered Filter "+beforeFilter);
|
||||
}
|
||||
|
||||
put(filter, position - 1);
|
||||
}
|
||||
|
||||
private void put(Class<? extends Filter> filter, int position) {
|
||||
String className = filter.getName();
|
||||
filterToOrder.put(className, position);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the order of a particular {@link Filter} class taking into consideration superclasses.
|
||||
*
|
||||
* @param clazz the {@link Filter} class to determine the sort order
|
||||
* @return the sort order or null if not defined
|
||||
*/
|
||||
private Integer getOrder(Class<?> clazz) {
|
||||
while(clazz != null) {
|
||||
Integer result = filterToOrder.get(clazz.getName());
|
||||
if(result != null) {
|
||||
return result;
|
||||
}
|
||||
clazz = clazz.getSuperclass();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
+1280
File diff suppressed because it is too large
Load Diff
+327
@@ -0,0 +1,327 @@
|
||||
/*
|
||||
* Copyright 2002-2013 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.config.annotation.web.builders;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.servlet.Filter;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.security.access.expression.SecurityExpressionHandler;
|
||||
import org.springframework.security.config.annotation.AbstractConfiguredSecurityBuilder;
|
||||
import org.springframework.security.config.annotation.SecurityBuilder;
|
||||
import org.springframework.security.config.annotation.web.AbstractRequestMatcherConfigurer;
|
||||
import org.springframework.security.config.annotation.web.WebSecurityConfigurer;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
import org.springframework.security.core.context.SecurityContext;
|
||||
import org.springframework.security.web.DefaultSecurityFilterChain;
|
||||
import org.springframework.security.web.FilterChainProxy;
|
||||
import org.springframework.security.web.FilterInvocation;
|
||||
import org.springframework.security.web.SecurityFilterChain;
|
||||
import org.springframework.security.web.access.DefaultWebInvocationPrivilegeEvaluator;
|
||||
import org.springframework.security.web.access.WebInvocationPrivilegeEvaluator;
|
||||
import org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler;
|
||||
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
|
||||
import org.springframework.security.web.firewall.DefaultHttpFirewall;
|
||||
import org.springframework.security.web.firewall.HttpFirewall;
|
||||
import org.springframework.security.web.util.RequestMatcher;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.web.filter.DelegatingFilterProxy;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* The {@link WebSecurity} is created by {@link WebSecurityConfiguration}
|
||||
* to create the {@link FilterChainProxy} known as the Spring Security Filter
|
||||
* Chain (springSecurityFilterChain). The springSecurityFilterChain is the
|
||||
* {@link Filter} that the {@link DelegatingFilterProxy} delegates to.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* Customizations to the {@link WebSecurity} can be made by creating a
|
||||
* {@link WebSecurityConfigurer} or more likely by overriding
|
||||
* {@link WebSecurityConfigurerAdapter}.
|
||||
* </p>
|
||||
*
|
||||
* @see EnableWebSecurity
|
||||
* @see WebSecurityConfiguration
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @since 3.2
|
||||
*/
|
||||
public final class WebSecurity extends
|
||||
AbstractConfiguredSecurityBuilder<Filter, WebSecurity> implements SecurityBuilder<Filter> {
|
||||
private final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
private final List<RequestMatcher> ignoredRequests = new ArrayList<RequestMatcher>();
|
||||
|
||||
private final List<SecurityBuilder<? extends SecurityFilterChain>> securityFilterChainBuilders =
|
||||
new ArrayList<SecurityBuilder<? extends SecurityFilterChain>>();
|
||||
|
||||
private final IgnoredRequestConfigurer ignoredRequestRegistry =
|
||||
new IgnoredRequestConfigurer();
|
||||
|
||||
private FilterSecurityInterceptor filterSecurityInterceptor;
|
||||
|
||||
private HttpFirewall httpFirewall;
|
||||
|
||||
private boolean debugEnabled;
|
||||
|
||||
private WebInvocationPrivilegeEvaluator privilegeEvaluator;
|
||||
|
||||
private SecurityExpressionHandler<FilterInvocation> expressionHandler = new DefaultWebSecurityExpressionHandler();
|
||||
|
||||
private Runnable postBuildAction = new Runnable() {
|
||||
public void run() {}
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a new instance
|
||||
* @see WebSecurityConfiguration
|
||||
*/
|
||||
public WebSecurity() {
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Allows adding {@link RequestMatcher} instances that should that Spring
|
||||
* Security should ignore. Web Security provided by Spring Security
|
||||
* (including the {@link SecurityContext}) will not be available on
|
||||
* {@link HttpServletRequest} that match. Typically the requests that are
|
||||
* registered should be that of only static resources. For requests that are
|
||||
* dynamic, consider mapping the request to allow all users instead.
|
||||
* </p>
|
||||
*
|
||||
* Example Usage:
|
||||
*
|
||||
* <pre>
|
||||
* webSecurityBuilder
|
||||
* .ignoring()
|
||||
* // ignore all URLs that start with /resources/ or /static/
|
||||
* .antMatchers("/resources/**", "/static/**");
|
||||
* </pre>
|
||||
*
|
||||
* Alternatively this will accomplish the same result:
|
||||
*
|
||||
* <pre>
|
||||
* webSecurityBuilder
|
||||
* .ignoring()
|
||||
* // ignore all URLs that start with /resources/ or /static/
|
||||
* .antMatchers("/resources/**")
|
||||
* .antMatchers("/static/**");
|
||||
* </pre>
|
||||
*
|
||||
* Multiple invocations of ignoring() are also additive, so the following is
|
||||
* also equivalent to the previous two examples:
|
||||
*
|
||||
* Alternatively this will accomplish the same result:
|
||||
*
|
||||
* <pre>
|
||||
* webSecurityBuilder
|
||||
* .ignoring()
|
||||
* // ignore all URLs that start with /resources/
|
||||
* .antMatchers("/resources/**");
|
||||
* webSecurityBuilder
|
||||
* .ignoring()
|
||||
* // ignore all URLs that start with /static/
|
||||
* .antMatchers("/static/**");
|
||||
* // now both URLs that start with /resources/ and /static/ will be ignored
|
||||
* </pre>
|
||||
*
|
||||
* @return the {@link IgnoredRequestConfigurer} to use for registering request
|
||||
* that should be ignored
|
||||
*/
|
||||
public IgnoredRequestConfigurer ignoring() {
|
||||
return ignoredRequestRegistry;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows customizing the {@link HttpFirewall}. The default is
|
||||
* {@link DefaultHttpFirewall}.
|
||||
*
|
||||
* @param httpFirewall the custom {@link HttpFirewall}
|
||||
* @return the {@link WebSecurity} for further customizations
|
||||
*/
|
||||
public WebSecurity httpFirewall(HttpFirewall httpFirewall) {
|
||||
this.httpFirewall = httpFirewall;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Controls debugging support for Spring Security.
|
||||
*
|
||||
* @param debugEnabled
|
||||
* if true, enables debug support with Spring Security. Default
|
||||
* is false.
|
||||
*
|
||||
* @return the {@link WebSecurity} for further customization.
|
||||
* @see EnableWebSecurity#debug()
|
||||
*/
|
||||
public WebSecurity debug(boolean debugEnabled) {
|
||||
this.debugEnabled = debugEnabled;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Adds builders to create {@link SecurityFilterChain} instances.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* Typically this method is invoked automatically within the framework from
|
||||
* {@link WebSecurityConfigurerAdapter#init(WebSecurity)}
|
||||
* </p>
|
||||
*
|
||||
* @param securityFilterChainBuilder
|
||||
* the builder to use to create the {@link SecurityFilterChain}
|
||||
* instances
|
||||
* @return the {@link WebSecurity} for further customizations
|
||||
*/
|
||||
public WebSecurity addSecurityFilterChainBuilder(SecurityBuilder<? extends SecurityFilterChain> securityFilterChainBuilder) {
|
||||
this.securityFilterChainBuilders.add(securityFilterChainBuilder);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the {@link WebInvocationPrivilegeEvaluator} to be used. If this is
|
||||
* null, then a {@link DefaultWebInvocationPrivilegeEvaluator} will be
|
||||
* created when {@link #securityInterceptor(FilterSecurityInterceptor)}
|
||||
* is non null.
|
||||
*
|
||||
* @param privilegeEvaluator
|
||||
* the {@link WebInvocationPrivilegeEvaluator} to use
|
||||
* @return the {@link WebSecurity} for further customizations
|
||||
*/
|
||||
public WebSecurity privilegeEvaluator(WebInvocationPrivilegeEvaluator privilegeEvaluator) {
|
||||
this.privilegeEvaluator = privilegeEvaluator;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the {@link SecurityExpressionHandler} to be used. If this is null,
|
||||
* then a {@link DefaultWebSecurityExpressionHandler} will be used.
|
||||
*
|
||||
* @param expressionHandler
|
||||
* the {@link SecurityExpressionHandler} to use
|
||||
* @return the {@link WebSecurity} for further customizations
|
||||
*/
|
||||
public WebSecurity expressionHandler(SecurityExpressionHandler<FilterInvocation> expressionHandler) {
|
||||
Assert.notNull(expressionHandler, "expressionHandler cannot be null");
|
||||
this.expressionHandler = expressionHandler;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the {@link SecurityExpressionHandler} to be used.
|
||||
* @return
|
||||
*/
|
||||
public SecurityExpressionHandler<FilterInvocation> getExpressionHandler() {
|
||||
return expressionHandler;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the {@link WebInvocationPrivilegeEvaluator} to be used.
|
||||
* @return
|
||||
*/
|
||||
public WebInvocationPrivilegeEvaluator getPrivilegeEvaluator() {
|
||||
if(privilegeEvaluator != null) {
|
||||
return privilegeEvaluator;
|
||||
}
|
||||
return filterSecurityInterceptor == null ? null : new DefaultWebInvocationPrivilegeEvaluator(filterSecurityInterceptor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the {@link FilterSecurityInterceptor}. This is typically invoked by {@link WebSecurityConfigurerAdapter}.
|
||||
* @param securityInterceptor the {@link FilterSecurityInterceptor} to use
|
||||
* @return the {@link WebSecurity} for further customizations
|
||||
*/
|
||||
public WebSecurity securityInterceptor(FilterSecurityInterceptor securityInterceptor) {
|
||||
this.filterSecurityInterceptor = securityInterceptor;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the Runnable immediately after the build takes place
|
||||
*
|
||||
* @param postBuildAction
|
||||
* @return the {@link WebSecurity} for further customizations
|
||||
*/
|
||||
public WebSecurity postBuildAction(Runnable postBuildAction) {
|
||||
this.postBuildAction = postBuildAction;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Filter performBuild() throws Exception {
|
||||
Assert.state(!securityFilterChainBuilders.isEmpty(), "At least one SecurityFilterBuilder needs to be specified. Invoke FilterChainProxyBuilder.securityFilterChains");
|
||||
int chainSize = ignoredRequests.size() + securityFilterChainBuilders.size();
|
||||
List<SecurityFilterChain> securityFilterChains = new ArrayList<SecurityFilterChain>(chainSize);
|
||||
for(RequestMatcher ignoredRequest : ignoredRequests) {
|
||||
securityFilterChains.add(new DefaultSecurityFilterChain(ignoredRequest));
|
||||
}
|
||||
for(SecurityBuilder<? extends SecurityFilterChain> securityFilterChainBuilder : securityFilterChainBuilders) {
|
||||
securityFilterChains.add(securityFilterChainBuilder.build());
|
||||
}
|
||||
FilterChainProxy filterChainProxy = new FilterChainProxy(securityFilterChains);
|
||||
if(httpFirewall != null) {
|
||||
filterChainProxy.setFirewall(httpFirewall);
|
||||
}
|
||||
filterChainProxy.afterPropertiesSet();
|
||||
|
||||
Filter result = filterChainProxy;
|
||||
if(debugEnabled) {
|
||||
logger.warn("\n\n" +
|
||||
"********************************************************************\n" +
|
||||
"********** Security debugging is enabled. *************\n" +
|
||||
"********** This may include sensitive information. *************\n" +
|
||||
"********** Do not use in a production system! *************\n" +
|
||||
"********************************************************************\n\n");
|
||||
result = new DebugFilter(filterChainProxy);
|
||||
}
|
||||
postBuildAction.run();
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows registering {@link RequestMatcher} instances that should be
|
||||
* ignored by Spring Security.
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @since 3.2
|
||||
*/
|
||||
public final class IgnoredRequestConfigurer extends AbstractRequestMatcherConfigurer<WebSecurity,IgnoredRequestConfigurer,Filter> {
|
||||
|
||||
@Override
|
||||
protected IgnoredRequestConfigurer chainRequestMatchers(List<RequestMatcher> requestMatchers) {
|
||||
ignoredRequests.addAll(requestMatchers);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link WebSecurity} to be returned for chaining.
|
||||
*/
|
||||
@Override
|
||||
public WebSecurity and() {
|
||||
return WebSecurity.this;
|
||||
}
|
||||
|
||||
private IgnoredRequestConfigurer(){}
|
||||
}
|
||||
}
|
||||
+87
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Copyright 2002-2013 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.config.annotation.web.configuration;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.security.config.annotation.configuration.ObjectPostProcessorConfiguration;
|
||||
import org.springframework.security.config.annotation.web.WebSecurityConfigurer;
|
||||
|
||||
/**
|
||||
* Add this annotation to an {@code @Configuration} class to have the Spring Security
|
||||
* configuration defined in any {@link WebSecurityConfigurer} or more likely by extending the
|
||||
* {@link WebSecurityConfigurerAdapter} base class and overriding individual methods:
|
||||
*
|
||||
* <pre class="code">
|
||||
* @Configuration
|
||||
* @EnableWebSecurity
|
||||
* public class MyWebSecurityConfiguration extends WebSecurityConfigurerAdapter {
|
||||
*
|
||||
* @Override
|
||||
* public void configure(WebSecurity web) throws Exception {
|
||||
* web
|
||||
* .ignoring()
|
||||
* // Spring Security should completely ignore URLs starting with /resources/
|
||||
* .antMatchers("/resources/**");
|
||||
* }
|
||||
*
|
||||
* @Override
|
||||
* protected void configure(HttpSecurity http) throws Exception {
|
||||
* http
|
||||
* .authorizeUrls()
|
||||
* .antMatchers("/public/**").permitAll()
|
||||
* .anyRequest().hasRole("USER")
|
||||
* .and()
|
||||
* // Possibly more configuration ...
|
||||
* .formLogin() // enable form based log in
|
||||
* // set permitAll for all URLs associated with Form Login
|
||||
* .permitAll();
|
||||
* }
|
||||
*
|
||||
* @Override
|
||||
* protected void registerAuthentication(AuthenticationManagerBuilder auth) {
|
||||
* registry
|
||||
* // enable in memory based authentication with a user named "user" and "admin"
|
||||
* .inMemoryAuthentication()
|
||||
* .withUser("user").password("password").roles("USER").and()
|
||||
* .withUser("admin").password("password").roles("USER", "ADMIN");
|
||||
* }
|
||||
*
|
||||
* // Possibly more overridden methods ...
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* @see WebSecurityConfigurer
|
||||
* @see WebSecurityConfigurerAdapter
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @since 3.2
|
||||
*/
|
||||
@Retention(value=java.lang.annotation.RetentionPolicy.RUNTIME)
|
||||
@Target(value={java.lang.annotation.ElementType.TYPE})
|
||||
@Documented
|
||||
@Import({WebSecurityConfiguration.class,ObjectPostProcessorConfiguration.class})
|
||||
public @interface EnableWebSecurity {
|
||||
|
||||
/**
|
||||
* Controls debugging support for Spring Security. Default is false.
|
||||
* @return if true, enables debug support with Spring Security
|
||||
*/
|
||||
boolean debug() default false;
|
||||
}
|
||||
+187
@@ -0,0 +1,187 @@
|
||||
/*
|
||||
* Copyright 2002-2013 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.config.annotation.web.configuration;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.Filter;
|
||||
|
||||
import org.springframework.beans.factory.BeanClassLoaderAware;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.DependsOn;
|
||||
import org.springframework.context.annotation.ImportAware;
|
||||
import org.springframework.core.OrderComparator;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.annotation.AnnotationAttributes;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.core.type.AnnotationMetadata;
|
||||
import org.springframework.security.access.expression.SecurityExpressionHandler;
|
||||
import org.springframework.security.config.annotation.SecurityConfigurer;
|
||||
import org.springframework.security.config.annotation.web.WebSecurityConfigurer;
|
||||
import org.springframework.security.config.annotation.web.builders.WebSecurity;
|
||||
import org.springframework.security.web.FilterChainProxy;
|
||||
import org.springframework.security.web.FilterInvocation;
|
||||
import org.springframework.security.web.access.WebInvocationPrivilegeEvaluator;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
/**
|
||||
* Uses a {@link WebSecurity} to create the {@link FilterChainProxy} that
|
||||
* performs the web based security for Spring Security. It then exports the
|
||||
* necessary beans. Customizations can be made to {@link WebSecurity} by
|
||||
* extending {@link WebSecurityConfigurerAdapter} and exposing it as a
|
||||
* {@link Configuration} or implementing {@link WebSecurityConfigurer} and
|
||||
* exposing it as a {@link Configuration}. This configuration is imported when
|
||||
* using {@link EnableWebSecurity}.
|
||||
*
|
||||
* @see EnableWebSecurity
|
||||
* @see WebSecurity
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @since 3.2
|
||||
*/
|
||||
@Configuration
|
||||
public class WebSecurityConfiguration implements ImportAware, BeanClassLoaderAware {
|
||||
private final WebSecurity webSecurity = new WebSecurity();
|
||||
|
||||
private List<SecurityConfigurer<Filter, WebSecurity>> webSecurityConfigurers;
|
||||
|
||||
private ClassLoader beanClassLoader;
|
||||
|
||||
@Bean
|
||||
@DependsOn("springSecurityFilterChain")
|
||||
public SecurityExpressionHandler<FilterInvocation> webSecurityExpressionHandler() {
|
||||
return webSecurity.getExpressionHandler();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the Spring Security Filter Chain
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
@Bean(name="springSecurityFilterChain")
|
||||
public Filter springSecurityFilterChain() throws Exception {
|
||||
boolean hasConfigurers = webSecurityConfigurers != null && !webSecurityConfigurers.isEmpty();
|
||||
if(!hasConfigurers) {
|
||||
throw new IllegalStateException("At least one non-null instance of "+ WebSecurityConfigurer.class.getSimpleName()+" must be exposed as a @Bean when using @EnableWebSecurity. Hint try extending "+ WebSecurityConfigurerAdapter.class.getSimpleName());
|
||||
}
|
||||
return webSecurity.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the {@link WebInvocationPrivilegeEvaluator} that is necessary for the JSP tag support.
|
||||
* @return the {@link WebInvocationPrivilegeEvaluator}
|
||||
* @throws Exception
|
||||
*/
|
||||
@Bean
|
||||
@DependsOn("springSecurityFilterChain")
|
||||
public WebInvocationPrivilegeEvaluator privilegeEvaluator() throws Exception {
|
||||
return webSecurity.getPrivilegeEvaluator();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the {@code <SecurityConfigurer<FilterChainProxy, WebSecurityBuilder>} instances used to create the web configuration.
|
||||
*
|
||||
* @param webSecurityConfigurers the {@code <SecurityConfigurer<FilterChainProxy, WebSecurityBuilder>} instances used to create the web configuration
|
||||
* @throws Exception
|
||||
*/
|
||||
@Autowired(required = false)
|
||||
public void setFilterChainProxySecurityConfigurer(
|
||||
List<SecurityConfigurer<Filter, WebSecurity>> webSecurityConfigurers) throws Exception {
|
||||
Collections.sort(webSecurityConfigurers, AnnotationAwareOrderComparator.INSTANCE);
|
||||
|
||||
Integer previousOrder = null;
|
||||
for(SecurityConfigurer<Filter, WebSecurity> config : webSecurityConfigurers) {
|
||||
Integer order = AnnotationAwareOrderComparator.lookupOrder(config);
|
||||
if(previousOrder != null && previousOrder.equals(order)) {
|
||||
throw new IllegalStateException("@Order on WebSecurityConfigurers must be unique. Order of " + order + " was already used, so it cannot be used on " + config + " too.");
|
||||
}
|
||||
previousOrder = order;
|
||||
}
|
||||
for(SecurityConfigurer<Filter, WebSecurity> webSecurityConfigurer : webSecurityConfigurers) {
|
||||
webSecurity.apply(webSecurityConfigurer);
|
||||
}
|
||||
this.webSecurityConfigurers = webSecurityConfigurers;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A custom verision of the Spring provided AnnotationAwareOrderComparator
|
||||
* that uses {@link AnnotationUtils#findAnnotation(Class, Class)} to look on
|
||||
* super class instances for the {@link Order} annotation.
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @since 3.2
|
||||
*/
|
||||
private static class AnnotationAwareOrderComparator extends OrderComparator {
|
||||
private static final AnnotationAwareOrderComparator INSTANCE = new AnnotationAwareOrderComparator();
|
||||
|
||||
@Override
|
||||
protected int getOrder(Object obj) {
|
||||
return lookupOrder(obj);
|
||||
}
|
||||
|
||||
private static int lookupOrder(Object obj) {
|
||||
if (obj instanceof Ordered) {
|
||||
return ((Ordered) obj).getOrder();
|
||||
}
|
||||
if (obj != null) {
|
||||
Class<?> clazz = (obj instanceof Class ? (Class<?>) obj : obj.getClass());
|
||||
Order order = AnnotationUtils.findAnnotation(clazz,Order.class);
|
||||
if (order != null) {
|
||||
return order.value();
|
||||
}
|
||||
}
|
||||
return Ordered.LOWEST_PRECEDENCE;
|
||||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.context.annotation.ImportAware#setImportMetadata(org.springframework.core.type.AnnotationMetadata)
|
||||
*/
|
||||
@Override
|
||||
public void setImportMetadata(AnnotationMetadata importMetadata) {
|
||||
Map<String, Object> enableWebSecurityAttrMap = importMetadata.getAnnotationAttributes(EnableWebSecurity.class.getName());
|
||||
AnnotationAttributes enableWebSecurityAttrs = AnnotationAttributes.fromMap(enableWebSecurityAttrMap);
|
||||
if(enableWebSecurityAttrs == null) {
|
||||
// search parent classes
|
||||
Class<?> currentClass = ClassUtils.resolveClassName(importMetadata.getClassName(), beanClassLoader);
|
||||
for(Class<?> classToInspect = currentClass ;classToInspect != null; classToInspect = classToInspect.getSuperclass()) {
|
||||
EnableWebSecurity enableWebSecurityAnnotation = AnnotationUtils.findAnnotation(classToInspect, EnableWebSecurity.class);
|
||||
if(enableWebSecurityAnnotation == null) {
|
||||
continue;
|
||||
}
|
||||
enableWebSecurityAttrMap = AnnotationUtils
|
||||
.getAnnotationAttributes(enableWebSecurityAnnotation);
|
||||
enableWebSecurityAttrs = AnnotationAttributes.fromMap(enableWebSecurityAttrMap);
|
||||
}
|
||||
}
|
||||
boolean debugEnabled = enableWebSecurityAttrs.getBoolean("debug");
|
||||
this.webSecurity.debug(debugEnabled);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.beans.factory.BeanClassLoaderAware#setBeanClassLoader(java.lang.ClassLoader)
|
||||
*/
|
||||
@Override
|
||||
public void setBeanClassLoader(ClassLoader classLoader) {
|
||||
this.beanClassLoader = classLoader;
|
||||
}
|
||||
}
|
||||
+340
@@ -0,0 +1,340 @@
|
||||
/*
|
||||
* Copyright 2002-2013 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.config.annotation.web.configuration;
|
||||
|
||||
|
||||
import javax.servlet.Filter;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.authentication.DefaultAuthenticationEventPublisher;
|
||||
import org.springframework.security.config.annotation.ObjectPostProcessor;
|
||||
import org.springframework.security.config.annotation.SecurityConfigurer;
|
||||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
||||
import org.springframework.security.config.annotation.web.WebSecurityConfigurer;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.builders.WebSecurity;
|
||||
import org.springframework.security.config.annotation.web.configurers.DefaultLoginPageConfigurer;
|
||||
import org.springframework.security.config.annotation.web.configurers.SecurityContextConfigurer;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
|
||||
|
||||
/**
|
||||
* Provides a convenient base class for creating a {@link WebSecurityConfigurer}
|
||||
* instance. The implementation allows customization by overriding methods.
|
||||
*
|
||||
* @see EnableWebSecurity
|
||||
*
|
||||
* @author Rob Winch
|
||||
*/
|
||||
public abstract class WebSecurityConfigurerAdapter implements SecurityConfigurer<Filter,WebSecurity> {
|
||||
private final Log logger = LogFactory.getLog(WebSecurityConfigurerAdapter.class);
|
||||
|
||||
private ApplicationContext context;
|
||||
|
||||
private ObjectPostProcessor<Object> objectPostProcessor = new ObjectPostProcessor<Object>() {
|
||||
@Override
|
||||
public <T> T postProcess(T object) {
|
||||
throw new IllegalStateException(ObjectPostProcessor.class.getName()+ " is a required bean. Ensure you have used @EnableWebSecurity and @Configuration");
|
||||
}
|
||||
};
|
||||
|
||||
private final AuthenticationManagerBuilder authenticationBuilder = new AuthenticationManagerBuilder();
|
||||
private final AuthenticationManagerBuilder parentAuthenticationBuilder = new AuthenticationManagerBuilder() {
|
||||
@Override
|
||||
public AuthenticationManagerBuilder eraseCredentials(boolean eraseCredentials) {
|
||||
authenticationBuilder.eraseCredentials(eraseCredentials);
|
||||
return super.eraseCredentials(eraseCredentials);
|
||||
}
|
||||
|
||||
};
|
||||
private boolean disableAuthenticationRegistration;
|
||||
private boolean authenticationManagerInitialized;
|
||||
private AuthenticationManager authenticationManager;
|
||||
private HttpSecurity http;
|
||||
private boolean disableDefaults;
|
||||
|
||||
/**
|
||||
* Creates an instance with the default configuration enabled.
|
||||
*/
|
||||
protected WebSecurityConfigurerAdapter() {
|
||||
this(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an instance which allows specifying if the default configuration
|
||||
* should be enabled. Disabling the default configuration should be
|
||||
* considered more advanced usage as it requires more understanding of how
|
||||
* the framework is implemented.
|
||||
*
|
||||
* @param disableDefaults
|
||||
* true if the default configuration should be enabled, else
|
||||
* false
|
||||
*/
|
||||
protected WebSecurityConfigurerAdapter(boolean disableDefaults) {
|
||||
this.disableDefaults = disableDefaults;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used by the default implementation of {@link #authenticationManager()} to attempt to obtain an
|
||||
* {@link AuthenticationManager}. If overridden, the {@link AuthenticationManagerBuilder} should be used to specify
|
||||
* the {@link AuthenticationManager}. The resulting {@link AuthenticationManager}
|
||||
* will be exposed as a Bean as will the last populated {@link UserDetailsService} that is created with the
|
||||
* {@link AuthenticationManagerBuilder}. The {@link UserDetailsService} will also automatically be populated on
|
||||
* {@link HttpSecurity#getSharedObject(Class)} for use with other {@link SecurityContextConfigurer}
|
||||
* (i.e. RememberMeConfigurer )
|
||||
*
|
||||
* <p>For example, the following configuration could be used to register
|
||||
* in memory authentication that exposes an in memory {@link UserDetailsService}:</p>
|
||||
*
|
||||
* <pre>
|
||||
* @Override
|
||||
* protected void registerAuthentication(AuthenticationManagerBuilder auth) {
|
||||
* registry
|
||||
* // enable in memory based authentication with a user named "user" and "admin"
|
||||
* .inMemoryAuthentication()
|
||||
* .withUser("user").password("password").roles("USER").and()
|
||||
* .withUser("admin").password("password").roles("USER", "ADMIN");
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* @param auth the {@link AuthenticationManagerBuilder} to use
|
||||
* @throws Exception
|
||||
*/
|
||||
protected void registerAuthentication(AuthenticationManagerBuilder auth) throws Exception {
|
||||
this.disableAuthenticationRegistration = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the {@link HttpSecurity} or returns the current instance
|
||||
*
|
||||
* @return the {@link HttpSecurity}
|
||||
* @throws Exception
|
||||
*/
|
||||
protected final HttpSecurity getHttp() throws Exception {
|
||||
if(http != null) {
|
||||
return http;
|
||||
}
|
||||
|
||||
authenticationBuilder.objectPostProcessor(objectPostProcessor);
|
||||
parentAuthenticationBuilder.objectPostProcessor(objectPostProcessor);
|
||||
|
||||
DefaultAuthenticationEventPublisher eventPublisher = objectPostProcessor.postProcess(new DefaultAuthenticationEventPublisher());
|
||||
parentAuthenticationBuilder.authenticationEventPublisher(eventPublisher);
|
||||
|
||||
AuthenticationManager authenticationManager = authenticationManager();
|
||||
authenticationBuilder.parentAuthenticationManager(authenticationManager);
|
||||
http = new HttpSecurity(objectPostProcessor,authenticationBuilder, parentAuthenticationBuilder.getSharedObjects());
|
||||
http.setSharedObject(UserDetailsService.class, userDetailsService());
|
||||
if(!disableDefaults) {
|
||||
http
|
||||
.exceptionHandling().and()
|
||||
.sessionManagement().and()
|
||||
.securityContext().and()
|
||||
.requestCache().and()
|
||||
.anonymous().and()
|
||||
.servletApi().and()
|
||||
.apply(new DefaultLoginPageConfigurer<HttpSecurity>()).and()
|
||||
.logout();
|
||||
}
|
||||
configure(http);
|
||||
return http;
|
||||
}
|
||||
|
||||
/**
|
||||
* Override this method to expose the {@link AuthenticationManager} from
|
||||
* {@link #registerAuthentication(AuthenticationManagerBuilder)} to be exposed as
|
||||
* a Bean. For example:
|
||||
*
|
||||
* <pre>
|
||||
* @Bean(name name="myAuthenticationManager")
|
||||
* @Override
|
||||
* public AuthenticationManager authenticationManagerBean() throws Exception {
|
||||
* return super.authenticationManagerBean();
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* @return the {@link AuthenticationManager}
|
||||
* @throws Exception
|
||||
*/
|
||||
public AuthenticationManager authenticationManagerBean() throws Exception {
|
||||
return new AuthenticationManagerDelegator(authenticationBuilder);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the {@link AuthenticationManager} to use. The default strategy is if
|
||||
* {@link #registerAuthentication(AuthenticationManagerBuilder)} method is
|
||||
* overridden to use the {@link AuthenticationManagerBuilder} that was passed in.
|
||||
* Otherwise, autowire the {@link AuthenticationManager} by type.
|
||||
*
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
protected AuthenticationManager authenticationManager() throws Exception {
|
||||
if(!authenticationManagerInitialized) {
|
||||
registerAuthentication(parentAuthenticationBuilder);
|
||||
if(disableAuthenticationRegistration) {
|
||||
try {
|
||||
authenticationManager = context.getBean(AuthenticationManager.class);
|
||||
} catch(NoSuchBeanDefinitionException e) {
|
||||
logger.debug("The AuthenticationManager was not found. This is ok for now as it may not be required.",e);
|
||||
}
|
||||
} else {
|
||||
authenticationManagerInitialized = true;
|
||||
authenticationManager = parentAuthenticationBuilder.build();
|
||||
}
|
||||
authenticationManagerInitialized = true;
|
||||
}
|
||||
return authenticationManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Override this method to expose a {@link UserDetailsService} created from
|
||||
* {@link #registerAuthentication(AuthenticationManagerBuilder)} as a bean. In
|
||||
* general only the following override should be done of this method:
|
||||
*
|
||||
* <pre>
|
||||
* @Bean(name = "myUserDetailsService") // any or no name specified is allowed
|
||||
* @Override
|
||||
* public UserDetailsService userDetailsServiceBean() throws Exception {
|
||||
* return super.userDetailsServiceBean();
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* To change the instance returned, developers should change
|
||||
* {@link #userDetailsService()} instead
|
||||
* @return
|
||||
* @throws Exception
|
||||
* @see {@link #userDetailsService()}
|
||||
*/
|
||||
public UserDetailsService userDetailsServiceBean() throws Exception {
|
||||
return userDetailsService();
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows modifying and accessing the {@link UserDetailsService} from
|
||||
* {@link #userDetailsServiceBean()()} without interacting with the
|
||||
* {@link ApplicationContext}. Developers should override this method when
|
||||
* changing the instance of {@link #userDetailsServiceBean()}.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
protected UserDetailsService userDetailsService() {
|
||||
return parentAuthenticationBuilder.getDefaultUserDetailsService();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(final WebSecurity web) throws Exception {
|
||||
final HttpSecurity http = getHttp();
|
||||
web
|
||||
.addSecurityFilterChainBuilder(http)
|
||||
.postBuildAction(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
FilterSecurityInterceptor securityInterceptor = http.getSharedObject(FilterSecurityInterceptor.class);
|
||||
web.securityInterceptor(securityInterceptor);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Override this method to configure {@link WebSecurity}. For
|
||||
* example, if you wish to ignore certain requests.
|
||||
*/
|
||||
@Override
|
||||
public void configure(WebSecurity web) throws Exception {
|
||||
}
|
||||
|
||||
/**
|
||||
* Override this method to configure the {@link HttpSecurity}.
|
||||
* Typically subclasses should not invoke this method by calling super
|
||||
* as it may override their configuration. The default configuration is:
|
||||
*
|
||||
* <pre>
|
||||
* http
|
||||
* .authorizeUrls()
|
||||
* .anyRequest().authenticated().and()
|
||||
* .formLogin().and()
|
||||
* .httpBasic();
|
||||
* </pre>
|
||||
*
|
||||
* @param http
|
||||
* the {@link HttpSecurity} to modify
|
||||
* @throws Exception
|
||||
* if an error occurs
|
||||
*/
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
logger.debug("Using default configure(HttpSecurity). If subclassed this will potentially override subclass configure(HttpSecurity).");
|
||||
|
||||
http
|
||||
.authorizeUrls()
|
||||
.anyRequest().authenticated()
|
||||
.and()
|
||||
.formLogin().and()
|
||||
.httpBasic();
|
||||
}
|
||||
|
||||
@Autowired
|
||||
public void setApplicationContext(ApplicationContext context) {
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
@Autowired(required=false)
|
||||
public void setObjectPostProcessor(ObjectPostProcessor<Object> objectPostProcessor) {
|
||||
this.objectPostProcessor = objectPostProcessor;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Delays the use of the {@link AuthenticationManager} build from the
|
||||
* {@link AuthenticationManagerBuilder} to ensure that it has been fully
|
||||
* configured.
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @since 3.2
|
||||
*/
|
||||
static final class AuthenticationManagerDelegator implements AuthenticationManager {
|
||||
private AuthenticationManagerBuilder delegateBuilder;
|
||||
private AuthenticationManager delegate;
|
||||
private final Object delegateMonitor = new Object();
|
||||
|
||||
AuthenticationManagerDelegator(AuthenticationManagerBuilder authentication) {
|
||||
this.delegateBuilder = authentication;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
|
||||
if(delegate != null) {
|
||||
return delegate.authenticate(authentication);
|
||||
}
|
||||
|
||||
synchronized(delegateMonitor) {
|
||||
if (delegate == null) {
|
||||
delegate = this.delegateBuilder.getObject();
|
||||
this.delegateBuilder = null;
|
||||
}
|
||||
}
|
||||
|
||||
return delegate.authenticate(authentication);
|
||||
}
|
||||
}
|
||||
}
|
||||
+319
@@ -0,0 +1,319 @@
|
||||
/*
|
||||
* Copyright 2002-2013 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.config.annotation.web.configurers;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.springframework.security.authentication.AuthenticationDetailsSource;
|
||||
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
import org.springframework.security.config.annotation.web.configurers.openid.OpenIDLoginConfigurer;
|
||||
import org.springframework.security.web.AuthenticationEntryPoint;
|
||||
import org.springframework.security.web.PortMapper;
|
||||
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
|
||||
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
|
||||
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
|
||||
import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint;
|
||||
import org.springframework.security.web.authentication.RememberMeServices;
|
||||
import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;
|
||||
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;
|
||||
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
|
||||
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
|
||||
import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy;
|
||||
|
||||
/**
|
||||
* Base class for confuring {@link AbstractAuthenticationFilterConfigurer}. This is intended for internal use only.
|
||||
*
|
||||
* @see FormLoginConfigurer
|
||||
* @see OpenIDLoginConfigurer
|
||||
*
|
||||
* @param T refers to "this" for returning the current configurer
|
||||
* @param F refers to the {@link AbstractAuthenticationProcessingFilter} that is being built
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @since 3.2
|
||||
*/
|
||||
public abstract class AbstractAuthenticationFilterConfigurer<B extends HttpSecurityBuilder<B>,T extends AbstractAuthenticationFilterConfigurer<B,T, F>, F extends AbstractAuthenticationProcessingFilter> extends AbstractHttpConfigurer<B> {
|
||||
|
||||
private final F authFilter;
|
||||
|
||||
private AuthenticationDetailsSource<HttpServletRequest, ?> authenticationDetailsSource;
|
||||
|
||||
private AuthenticationSuccessHandler successHandler = new SavedRequestAwareAuthenticationSuccessHandler();
|
||||
|
||||
private LoginUrlAuthenticationEntryPoint authenticationEntryPoint;
|
||||
|
||||
private boolean customLoginPage;
|
||||
private String loginPage;
|
||||
private String loginProcessingUrl;
|
||||
|
||||
private AuthenticationFailureHandler failureHandler;
|
||||
|
||||
private boolean permitAll;
|
||||
|
||||
private String failureUrl;
|
||||
|
||||
/**
|
||||
* Creates a new instance
|
||||
* @param authenticationFilter the {@link AbstractAuthenticationProcessingFilter} to use
|
||||
* @param defaultLoginProcessingUrl the default URL to use for {@link #loginProcessingUrl(String)}
|
||||
*/
|
||||
protected AbstractAuthenticationFilterConfigurer(F authenticationFilter, String defaultLoginProcessingUrl) {
|
||||
this.authFilter = authenticationFilter;
|
||||
loginUrl("/login");
|
||||
failureUrl("/login?error");
|
||||
loginProcessingUrl(defaultLoginProcessingUrl);
|
||||
this.customLoginPage = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies where users will go after authenticating successfully if they
|
||||
* have not visited a secured page prior to authenticating. This is a
|
||||
* shortcut for calling {@link #defaultSuccessUrl(String)}.
|
||||
*
|
||||
* @param defaultSuccessUrl
|
||||
* the default success url
|
||||
* @return the {@link FormLoginConfigurer} for additional customization
|
||||
*/
|
||||
public final T defaultSuccessUrl(String defaultSuccessUrl) {
|
||||
return defaultSuccessUrl(defaultSuccessUrl, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies where users will go after authenticating successfully if they
|
||||
* have not visited a secured page prior to authenticating or
|
||||
* {@code alwaysUse} is true. This is a shortcut for calling
|
||||
* {@link #successHandler(AuthenticationSuccessHandler)}.
|
||||
*
|
||||
* @param defaultSuccessUrl
|
||||
* the default success url
|
||||
* @param alwaysUse
|
||||
* true if the {@code defaultSuccesUrl} should be used after
|
||||
* authentication despite if a protected page had been previously
|
||||
* visited
|
||||
* @return the {@link FormLoginConfigurer} for additional customization
|
||||
*/
|
||||
public final T defaultSuccessUrl(String defaultSuccessUrl, boolean alwaysUse) {
|
||||
SavedRequestAwareAuthenticationSuccessHandler handler = new SavedRequestAwareAuthenticationSuccessHandler();
|
||||
handler.setDefaultTargetUrl(defaultSuccessUrl);
|
||||
handler.setAlwaysUseDefaultTargetUrl(alwaysUse);
|
||||
return successHandler(handler);
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies the URL used to log in. If the request matches the URL and is an HTTP POST, the
|
||||
* {@link UsernamePasswordAuthenticationFilter} will attempt to authenticate
|
||||
* the request. Otherwise, if the request matches the URL the user will be sent to the login form.
|
||||
*
|
||||
* @param loginUrl the URL used to perform authentication
|
||||
* @return the {@link FormLoginConfigurer} for additional customization
|
||||
*/
|
||||
public final T loginUrl(String loginUrl) {
|
||||
loginProcessingUrl(loginUrl);
|
||||
return loginPage(loginUrl);
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies the URL to validate the credentials.
|
||||
*
|
||||
* @param loginProcessingUrl
|
||||
* the URL to validate username and password
|
||||
* @return the {@link FormLoginConfigurer} for additional customization
|
||||
*/
|
||||
public T loginProcessingUrl(String loginProcessingUrl) {
|
||||
this.loginProcessingUrl = loginProcessingUrl;
|
||||
authFilter.setFilterProcessesUrl(loginProcessingUrl);
|
||||
return getSelf();
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies a custom {@link AuthenticationDetailsSource}. The default is {@link WebAuthenticationDetailsSource}.
|
||||
*
|
||||
* @param authenticationDetailsSource the custom {@link AuthenticationDetailsSource}
|
||||
* @return the {@link FormLoginConfigurer} for additional customization
|
||||
*/
|
||||
public final T authenticationDetailsSource(AuthenticationDetailsSource<HttpServletRequest, ?> authenticationDetailsSource) {
|
||||
this.authenticationDetailsSource = authenticationDetailsSource;
|
||||
return getSelf();
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies the {@link AuthenticationSuccessHandler} to be used. The
|
||||
* default is {@link SavedRequestAwareAuthenticationSuccessHandler} with no
|
||||
* additional properites set.
|
||||
*
|
||||
* @param successHandler
|
||||
* the {@link AuthenticationSuccessHandler}.
|
||||
* @return the {@link FormLoginConfigurer} for additional customization
|
||||
*/
|
||||
public final T successHandler(AuthenticationSuccessHandler successHandler) {
|
||||
this.successHandler = successHandler;
|
||||
return getSelf();
|
||||
}
|
||||
|
||||
/**
|
||||
* Equivalent of invoking permitAll(true)
|
||||
* @return
|
||||
*/
|
||||
public final T permitAll() {
|
||||
return permitAll(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures the urls for {@link #failureUrl(String)} and
|
||||
* {@link #loginUrl(String)} are granted access to any user.
|
||||
*
|
||||
* @param permitAll true to grant access to the URLs false to skip this step
|
||||
* @return the {@link FormLoginConfigurer} for additional customization
|
||||
*/
|
||||
public final T permitAll(boolean permitAll) {
|
||||
this.permitAll = permitAll;
|
||||
return getSelf();
|
||||
}
|
||||
|
||||
/**
|
||||
* The URL to send users if authentication fails. This is a shortcut for
|
||||
* invoking {@link #failureHandler(AuthenticationFailureHandler)}. The
|
||||
* default is "/login?error".
|
||||
*
|
||||
* @param authenticationFailureUrl
|
||||
* the URL to send users if authentication fails (i.e.
|
||||
* "/login?error").
|
||||
* @return the {@link FormLoginConfigurer} for additional customization
|
||||
*/
|
||||
public final T failureUrl(String authenticationFailureUrl) {
|
||||
T result = failureHandler(new SimpleUrlAuthenticationFailureHandler(authenticationFailureUrl));
|
||||
this.failureUrl = authenticationFailureUrl;
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies the {@link AuthenticationFailureHandler} to use when
|
||||
* authentication fails. The default is redirecting to "/login?error" using
|
||||
* {@link SimpleUrlAuthenticationFailureHandler}
|
||||
*
|
||||
* @param authenticationFailureHandler
|
||||
* the {@link AuthenticationFailureHandler} to use when
|
||||
* authentication fails.
|
||||
* @return the {@link FormLoginConfigurer} for additional customization
|
||||
*/
|
||||
public final T failureHandler(AuthenticationFailureHandler authenticationFailureHandler) {
|
||||
this.failureUrl = null;
|
||||
this.failureHandler = authenticationFailureHandler;
|
||||
return getSelf();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(B http) throws Exception {
|
||||
if(permitAll) {
|
||||
PermitAllSupport.permitAll(http, loginPage, loginProcessingUrl, failureUrl);
|
||||
}
|
||||
http.setSharedObject(AuthenticationEntryPoint.class, postProcess(authenticationEntryPoint));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(B http) throws Exception {
|
||||
PortMapper portMapper = http.getSharedObject(PortMapper.class);
|
||||
if(portMapper != null) {
|
||||
authenticationEntryPoint.setPortMapper(portMapper);
|
||||
}
|
||||
|
||||
authFilter.setAuthenticationManager(http.getAuthenticationManager());
|
||||
authFilter.setAuthenticationSuccessHandler(successHandler);
|
||||
authFilter.setAuthenticationFailureHandler(failureHandler);
|
||||
if(authenticationDetailsSource != null) {
|
||||
authFilter.setAuthenticationDetailsSource(authenticationDetailsSource);
|
||||
}
|
||||
SessionAuthenticationStrategy sessionAuthenticationStrategy = http.getSharedObject(SessionAuthenticationStrategy.class);
|
||||
if(sessionAuthenticationStrategy != null) {
|
||||
authFilter.setSessionAuthenticationStrategy(sessionAuthenticationStrategy);
|
||||
}
|
||||
RememberMeServices rememberMeServices = http.getSharedObject(RememberMeServices.class);
|
||||
if(rememberMeServices != null) {
|
||||
authFilter.setRememberMeServices(rememberMeServices);
|
||||
}
|
||||
F filter = postProcess(authFilter);
|
||||
http.addFilter(filter);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Specifies the URL to send users to if login is required. If used with
|
||||
* {@link WebSecurityConfigurerAdapter} a default login page will be
|
||||
* generated when this attribute is not specified.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* If a URL is specified or this is not being used in conjuction with
|
||||
* {@link WebSecurityConfigurerAdapter}, users are required to process the
|
||||
* specified URL to generate a login page.
|
||||
* </p>
|
||||
*/
|
||||
protected T loginPage(String loginPage) {
|
||||
this.loginPage = loginPage;
|
||||
this.authenticationEntryPoint = new LoginUrlAuthenticationEntryPoint(loginPage);
|
||||
this.customLoginPage = true;
|
||||
return getSelf();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return true if a custom login page has been specified, else false
|
||||
*/
|
||||
public final boolean isCustomLoginPage() {
|
||||
return customLoginPage;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the Authentication Filter
|
||||
* @return
|
||||
*/
|
||||
protected final F getAuthenticationFilter() {
|
||||
return authFilter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the login page
|
||||
* @return the login page
|
||||
*/
|
||||
protected final String getLoginPage() {
|
||||
return loginPage;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the URL to submit an authentication request to (i.e. where
|
||||
* username/password must be submitted)
|
||||
*
|
||||
* @return the URL to submit an authentication request to
|
||||
*/
|
||||
protected final String getLoginProcessingUrl() {
|
||||
return loginProcessingUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the URL to send users to if authentication fails
|
||||
* @return
|
||||
*/
|
||||
protected final String getFailureUrl() {
|
||||
return failureUrl;
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private T getSelf() {
|
||||
return (T) this;
|
||||
}
|
||||
}
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright 2002-2013 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.config.annotation.web.configurers;
|
||||
|
||||
import org.springframework.security.config.annotation.SecurityConfigurer;
|
||||
import org.springframework.security.config.annotation.SecurityConfigurerAdapter;
|
||||
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.web.DefaultSecurityFilterChain;
|
||||
|
||||
/**
|
||||
* Adds a convenient base class for {@link SecurityConfigurer} instances that
|
||||
* operate on {@link HttpSecurity}.
|
||||
*
|
||||
* @author Rob Winch
|
||||
*
|
||||
*/
|
||||
abstract class AbstractHttpConfigurer<B extends HttpSecurityBuilder<B>> extends SecurityConfigurerAdapter<DefaultSecurityFilterChain, B> {
|
||||
|
||||
}
|
||||
+182
@@ -0,0 +1,182 @@
|
||||
/*
|
||||
* Copyright 2002-2013 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.config.annotation.web.configurers;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.security.access.AccessDecisionManager;
|
||||
import org.springframework.security.access.AccessDecisionVoter;
|
||||
import org.springframework.security.access.vote.AffirmativeBased;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.config.annotation.SecurityConfigurer;
|
||||
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
|
||||
import org.springframework.security.web.DefaultSecurityFilterChain;
|
||||
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
|
||||
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
|
||||
|
||||
/**
|
||||
* A base class for configuring the {@link FilterSecurityInterceptor}.
|
||||
*
|
||||
* <h2>Security Filters</h2>
|
||||
*
|
||||
* The following Filters are populated
|
||||
*
|
||||
* <ul>
|
||||
* <li>{@link FilterSecurityInterceptor}</li>
|
||||
* </ul>
|
||||
*
|
||||
* <h2>Shared Objects Created</h2>
|
||||
*
|
||||
* The following shared objects are populated to allow other {@link SecurityConfigurer}'s to customize:
|
||||
* <ul>
|
||||
* <li>{@link FilterSecurityInterceptor}</li>
|
||||
* </ul>
|
||||
*
|
||||
* <h2>Shared Objects Used</h2>
|
||||
*
|
||||
* The following shared objects are used:
|
||||
*
|
||||
* <ul>
|
||||
* <li>{@link org.springframework.security.config.annotation.web.builders.HttpSecurity#getAuthenticationManager()}</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param <H> the type of {@link HttpSecurityBuilder} that is being configured
|
||||
* @param <C> the type of object that is changed
|
||||
* @param <R> the type of object that is changed for the {@link AbstractRequestMatcherMappingConfigurer}
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @since 3.2
|
||||
* @see ExpressionUrlAuthorizationConfigurer
|
||||
* @see UrlAuthorizationConfigurer
|
||||
*/
|
||||
abstract class AbstractInterceptUrlConfigurer<H extends HttpSecurityBuilder<H>,C,R> extends
|
||||
AbstractRequestMatcherMappingConfigurer<H,R,DefaultSecurityFilterChain> implements
|
||||
SecurityConfigurer<DefaultSecurityFilterChain,H> {
|
||||
private Boolean filterSecurityInterceptorOncePerRequest;
|
||||
|
||||
private AccessDecisionManager accessDecisionManager;
|
||||
|
||||
/**
|
||||
* Allows setting the {@link AccessDecisionManager}. If none is provided, a default {@l AccessDecisionManager} is
|
||||
* created.
|
||||
*
|
||||
* @param accessDecisionManager the {@link AccessDecisionManager} to use
|
||||
* @return the {@link AbstractInterceptUrlConfigurer} for further customization
|
||||
*/
|
||||
public C accessDecisionManager(
|
||||
AccessDecisionManager accessDecisionManager) {
|
||||
this.accessDecisionManager = accessDecisionManager;
|
||||
return getSelf();
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows setting if the {@link FilterSecurityInterceptor} should be only applied once per request (i.e. if the
|
||||
* filter intercepts on a forward, should it be applied again).
|
||||
*
|
||||
* @param filterSecurityInterceptorOncePerRequest if the {@link FilterSecurityInterceptor} should be only applied
|
||||
* once per request
|
||||
* @return the {@link AbstractInterceptUrlConfigurer} for further customization
|
||||
*/
|
||||
public C filterSecurityInterceptorOncePerRequest(
|
||||
boolean filterSecurityInterceptorOncePerRequest) {
|
||||
this.filterSecurityInterceptorOncePerRequest = filterSecurityInterceptorOncePerRequest;
|
||||
return getSelf();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(H http) throws Exception {
|
||||
FilterInvocationSecurityMetadataSource metadataSource = createMetadataSource();
|
||||
if(metadataSource == null) {
|
||||
return;
|
||||
}
|
||||
FilterSecurityInterceptor securityInterceptor = createFilterSecurityInterceptor(metadataSource, http.getAuthenticationManager());
|
||||
if(filterSecurityInterceptorOncePerRequest != null) {
|
||||
securityInterceptor.setObserveOncePerRequest(filterSecurityInterceptorOncePerRequest);
|
||||
}
|
||||
securityInterceptor = postProcess(securityInterceptor);
|
||||
http.addFilter(securityInterceptor);
|
||||
http.setSharedObject(FilterSecurityInterceptor.class, securityInterceptor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Subclasses should implement this method to provide a {@link FilterInvocationSecurityMetadataSource} for the
|
||||
* {@link FilterSecurityInterceptor}.
|
||||
*
|
||||
* @return the {@link FilterInvocationSecurityMetadataSource} to set on the {@link FilterSecurityInterceptor}.
|
||||
* Cannot be null.
|
||||
*/
|
||||
abstract FilterInvocationSecurityMetadataSource createMetadataSource();
|
||||
|
||||
/**
|
||||
* Subclasses should implement this method to provide the {@link AccessDecisionVoter} instances used to create the
|
||||
* default {@link AccessDecisionManager}
|
||||
*
|
||||
* @return the {@link AccessDecisionVoter} instances used to create the
|
||||
* default {@link AccessDecisionManager}
|
||||
*/
|
||||
@SuppressWarnings("rawtypes")
|
||||
abstract List<AccessDecisionVoter> getDecisionVoters();
|
||||
|
||||
/**
|
||||
* Creates the default {@code AccessDecisionManager}
|
||||
* @return the default {@code AccessDecisionManager}
|
||||
*/
|
||||
private AccessDecisionManager createDefaultAccessDecisionManager() {
|
||||
return new AffirmativeBased(getDecisionVoters());
|
||||
}
|
||||
|
||||
/**
|
||||
* If currently null, creates a default {@link AccessDecisionManager} using
|
||||
* {@link #createDefaultAccessDecisionManager()}. Otherwise returns the {@link AccessDecisionManager}.
|
||||
*
|
||||
* @return the {@link AccessDecisionManager} to use
|
||||
*/
|
||||
private AccessDecisionManager getAccessDecisionManager() {
|
||||
if (accessDecisionManager == null) {
|
||||
accessDecisionManager = createDefaultAccessDecisionManager();
|
||||
}
|
||||
return accessDecisionManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the {@link FilterSecurityInterceptor}
|
||||
*
|
||||
* @param metadataSource the {@link FilterInvocationSecurityMetadataSource} to use
|
||||
* @param authenticationManager the {@link AuthenticationManager} to use
|
||||
* @return the {@link FilterSecurityInterceptor}
|
||||
* @throws Exception
|
||||
*/
|
||||
private FilterSecurityInterceptor createFilterSecurityInterceptor(FilterInvocationSecurityMetadataSource metadataSource,
|
||||
AuthenticationManager authenticationManager) throws Exception {
|
||||
FilterSecurityInterceptor securityInterceptor = new FilterSecurityInterceptor();
|
||||
securityInterceptor.setSecurityMetadataSource(metadataSource);
|
||||
securityInterceptor.setAccessDecisionManager(getAccessDecisionManager());
|
||||
securityInterceptor.setAuthenticationManager(authenticationManager);
|
||||
securityInterceptor.afterPropertiesSet();
|
||||
return securityInterceptor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a reference to the current object with a single suppression of
|
||||
* the type
|
||||
*
|
||||
* @return a reference to the current object
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private C getSelf() {
|
||||
return (C) this;
|
||||
}
|
||||
}
|
||||
+144
@@ -0,0 +1,144 @@
|
||||
/*
|
||||
* Copyright 2002-2013 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.config.annotation.web.configurers;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.security.access.ConfigAttribute;
|
||||
import org.springframework.security.config.annotation.SecurityBuilder;
|
||||
import org.springframework.security.config.annotation.web.AbstractRequestMatcherConfigurer;
|
||||
import org.springframework.security.web.util.RequestMatcher;
|
||||
|
||||
/**
|
||||
* A base class for registering {@link RequestMatcher}'s. For example, it might allow for specifying which
|
||||
* {@link RequestMatcher} require a certain level of authorization.
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @since 3.2
|
||||
*
|
||||
* @param <B> The Builder that is building Object O and is configured by this {@link AbstractRequestMatcherMappingConfigurer}
|
||||
* @param <C> The object that is returned or Chained after creating the RequestMatcher
|
||||
* @param <O> The Object being built by Builder B
|
||||
*
|
||||
* @see ChannelSecurityConfigurer
|
||||
* @see UrlAuthorizationConfigurer
|
||||
* @see ExpressionUrlAuthorizationConfigurer
|
||||
*/
|
||||
public abstract class AbstractRequestMatcherMappingConfigurer<B extends SecurityBuilder<O>,C,O> extends AbstractRequestMatcherConfigurer<B,C,O> {
|
||||
private List<UrlMapping> urlMappings = new ArrayList<UrlMapping>();
|
||||
private List<RequestMatcher> unmappedMatchers;
|
||||
|
||||
/**
|
||||
* Gets the {@link UrlMapping} added by subclasses in {@link #chainRequestMatchers(java.util.List)}. May be empty.
|
||||
*
|
||||
* @return the {@link UrlMapping} added by subclasses in {@link #chainRequestMatchers(java.util.List)}
|
||||
*/
|
||||
final List<UrlMapping> getUrlMappings() {
|
||||
return urlMappings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a {@link UrlMapping} added by subclasses in
|
||||
* {@link #chainRequestMatchers(java.util.List)} and resets the unmapped
|
||||
* {@link RequestMatcher}'s.
|
||||
*
|
||||
* @param urlMapping
|
||||
* {@link UrlMapping} the mapping to add
|
||||
*/
|
||||
final void addMapping(UrlMapping urlMapping) {
|
||||
this.unmappedMatchers = null;
|
||||
this.urlMappings.add(urlMapping);
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks the {@link RequestMatcher}'s as unmapped and then calls {@link #chainRequestMatchersInternal(List)}.
|
||||
*
|
||||
* @param requestMatchers the {@link RequestMatcher} instances that were created
|
||||
* @return the chained Object for the subclass which allows association of something else to the
|
||||
* {@link RequestMatcher}
|
||||
*/
|
||||
protected final C chainRequestMatchers(List<RequestMatcher> requestMatchers) {
|
||||
this.unmappedMatchers = requestMatchers;
|
||||
return chainRequestMatchersInternal(requestMatchers);
|
||||
}
|
||||
|
||||
/**
|
||||
* Subclasses should implement this method for returning the object that is chained to the creation of the
|
||||
* {@link RequestMatcher} instances.
|
||||
*
|
||||
* @param requestMatchers the {@link RequestMatcher} instances that were created
|
||||
* @return the chained Object for the subclass which allows association of something else to the
|
||||
* {@link RequestMatcher}
|
||||
*/
|
||||
protected abstract C chainRequestMatchersInternal(List<RequestMatcher> requestMatchers);
|
||||
|
||||
/**
|
||||
* Adds a {@link UrlMapping} added by subclasses in {@link #chainRequestMatchers(java.util.List)} at a particular
|
||||
* index.
|
||||
*
|
||||
* @param index the index to add a {@link UrlMapping}
|
||||
* @param urlMapping {@link UrlMapping} the mapping to add
|
||||
*/
|
||||
final void addMapping(int index, UrlMapping urlMapping) {
|
||||
this.urlMappings.add(index, urlMapping);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the mapping of {@link RequestMatcher} to {@link Collection} of {@link ConfigAttribute} instances
|
||||
*
|
||||
* @return the mapping of {@link RequestMatcher} to {@link Collection} of {@link ConfigAttribute} instances. Cannot
|
||||
* be null.
|
||||
*/
|
||||
final LinkedHashMap<RequestMatcher, Collection<ConfigAttribute>> createRequestMap() {
|
||||
if(unmappedMatchers != null) {
|
||||
throw new IllegalStateException("An incomplete mapping was found for " + unmappedMatchers +". Try completing it with something like requestUrls().<something>.hasRole('USER')");
|
||||
}
|
||||
|
||||
LinkedHashMap<RequestMatcher, Collection<ConfigAttribute>> requestMap = new LinkedHashMap<RequestMatcher, Collection<ConfigAttribute>>();
|
||||
for (UrlMapping mapping : getUrlMappings()) {
|
||||
RequestMatcher matcher = mapping.getRequestMatcher();
|
||||
Collection<ConfigAttribute> configAttrs = mapping.getConfigAttrs();
|
||||
requestMap.put(matcher,configAttrs);
|
||||
}
|
||||
return requestMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* A mapping of {@link RequestMatcher} to {@link Collection} of {@link ConfigAttribute} instances
|
||||
*/
|
||||
static final class UrlMapping {
|
||||
private RequestMatcher requestMatcher;
|
||||
private Collection<ConfigAttribute> configAttrs;
|
||||
|
||||
UrlMapping(RequestMatcher requestMatcher,
|
||||
Collection<ConfigAttribute> configAttrs) {
|
||||
this.requestMatcher = requestMatcher;
|
||||
this.configAttrs = configAttrs;
|
||||
}
|
||||
|
||||
public RequestMatcher getRequestMatcher() {
|
||||
return requestMatcher;
|
||||
}
|
||||
|
||||
public Collection<ConfigAttribute> getConfigAttrs() {
|
||||
return configAttrs;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+165
@@ -0,0 +1,165 @@
|
||||
/*
|
||||
* Copyright 2002-2013 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.config.annotation.web.configurers;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.springframework.security.authentication.AnonymousAuthenticationProvider;
|
||||
import org.springframework.security.authentication.AuthenticationProvider;
|
||||
import org.springframework.security.config.annotation.SecurityConfigurer;
|
||||
import org.springframework.security.config.annotation.SecurityConfigurerAdapter;
|
||||
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.authority.AuthorityUtils;
|
||||
import org.springframework.security.web.DefaultSecurityFilterChain;
|
||||
import org.springframework.security.web.authentication.AnonymousAuthenticationFilter;
|
||||
|
||||
/**
|
||||
* Configures Anonymous authentication (i.e. populate an {@link Authentication} that represents an anonymous user
|
||||
* instead of having a null value) for an {@link HttpSecurity}. Specifically this will configure an
|
||||
* {@link AnonymousAuthenticationFilter} and an {@link AnonymousAuthenticationProvider}. All properties have reasonable
|
||||
* defaults, so no additional configuration is required other than applying this {@link SecurityConfigurer}.
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @since 3.2
|
||||
*/
|
||||
public final class AnonymousConfigurer<H extends HttpSecurityBuilder<H>> extends SecurityConfigurerAdapter<DefaultSecurityFilterChain,H> {
|
||||
private String key;
|
||||
private AuthenticationProvider authenticationProvider;
|
||||
private AnonymousAuthenticationFilter authenticationFilter;
|
||||
private Object principal = "anonymousUser";
|
||||
private List<GrantedAuthority> authorities = AuthorityUtils.createAuthorityList("ROLE_ANONYMOUS");
|
||||
|
||||
/**
|
||||
* Creates a new instance
|
||||
* @see HttpSecurity#anonymous()
|
||||
*/
|
||||
public AnonymousConfigurer() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Disables anonymous authentication.
|
||||
*
|
||||
* @return the {@link HttpSecurity} since no further customization of anonymous authentication would be
|
||||
* meaningful.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public H disable() {
|
||||
getBuilder().removeConfigurer(getClass());
|
||||
return getBuilder();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the key to identify tokens created for anonymous authentication. Default is a secure randomly generated
|
||||
* key.
|
||||
*
|
||||
* @param key the key to identify tokens created for anonymous authentication. Default is a secure randomly generated
|
||||
* key.
|
||||
* @return the {@link AnonymousConfigurer} for further customization of anonymous authentication
|
||||
*/
|
||||
public AnonymousConfigurer<H> key(String key) {
|
||||
this.key = key;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the principal for {@link Authentication} objects of anonymous users
|
||||
*
|
||||
* @param principal used for the {@link Authentication} object of anonymous users
|
||||
* @return the {@link AnonymousConfigurer} for further customization of anonymous authentication
|
||||
*/
|
||||
public AnonymousConfigurer<H> principal(Object principal) {
|
||||
this.principal = principal;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the {@link org.springframework.security.core.Authentication#getAuthorities()} for anonymous users
|
||||
*
|
||||
* @param authorities Sets the {@link org.springframework.security.core.Authentication#getAuthorities()} for anonymous users
|
||||
* @return the {@link AnonymousConfigurer} for further customization of anonymous authentication
|
||||
*/
|
||||
public AnonymousConfigurer<H> authorities(List<GrantedAuthority> authorities) {
|
||||
this.authorities = authorities;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the {@link org.springframework.security.core.Authentication#getAuthorities()} for anonymous users
|
||||
*
|
||||
* @param authorities Sets the {@link org.springframework.security.core.Authentication#getAuthorities()} for
|
||||
* anonymous users (i.e. "ROLE_ANONYMOUS")
|
||||
* @return the {@link AnonymousConfigurer} for further customization of anonymous authentication
|
||||
*/
|
||||
public AnonymousConfigurer<H> authorities(String... authorities) {
|
||||
return authorities(AuthorityUtils.createAuthorityList(authorities));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the {@link AuthenticationProvider} used to validate an anonymous user. If this is set, no attributes
|
||||
* on the {@link AnonymousConfigurer} will be set on the {@link AuthenticationProvider}.
|
||||
*
|
||||
* @param authenticationProvider the {@link AuthenticationProvider} used to validate an anonymous user. Default is
|
||||
* {@link AnonymousAuthenticationProvider}
|
||||
*
|
||||
* @return the {@link AnonymousConfigurer} for further customization of anonymous authentication
|
||||
*/
|
||||
public AnonymousConfigurer<H> authenticationProvider(AuthenticationProvider authenticationProvider) {
|
||||
this.authenticationProvider = authenticationProvider;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the {@link AnonymousAuthenticationFilter} used to populate an anonymous user. If this is set, no attributes
|
||||
* on the {@link AnonymousConfigurer} will be set on the {@link AnonymousAuthenticationFilter}.
|
||||
*
|
||||
* @param authenticationFilter the {@link AnonymousAuthenticationFilter} used to populate an anonymous user.
|
||||
*
|
||||
* @return the {@link AnonymousConfigurer} for further customization of anonymous authentication
|
||||
*/
|
||||
public AnonymousConfigurer<H> authenticationFilter(AnonymousAuthenticationFilter authenticationFilter) {
|
||||
this.authenticationFilter = authenticationFilter;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(H http) throws Exception {
|
||||
if(authenticationProvider == null) {
|
||||
authenticationProvider = new AnonymousAuthenticationProvider(getKey());
|
||||
}
|
||||
if(authenticationFilter == null) {
|
||||
authenticationFilter = new AnonymousAuthenticationFilter(getKey(), principal, authorities);
|
||||
}
|
||||
authenticationProvider = postProcess(authenticationProvider);
|
||||
http.authenticationProvider(authenticationProvider);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(H http) throws Exception {
|
||||
authenticationFilter.afterPropertiesSet();
|
||||
http.addFilter(authenticationFilter);
|
||||
}
|
||||
|
||||
private String getKey() {
|
||||
if(key == null) {
|
||||
key = UUID.randomUUID().toString();
|
||||
}
|
||||
return key;
|
||||
}
|
||||
}
|
||||
+168
@@ -0,0 +1,168 @@
|
||||
/*
|
||||
* Copyright 2002-2013 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.config.annotation.web.configurers;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.security.access.ConfigAttribute;
|
||||
import org.springframework.security.access.SecurityConfig;
|
||||
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.web.DefaultSecurityFilterChain;
|
||||
import org.springframework.security.web.PortMapper;
|
||||
import org.springframework.security.web.access.channel.ChannelDecisionManagerImpl;
|
||||
import org.springframework.security.web.access.channel.ChannelProcessingFilter;
|
||||
import org.springframework.security.web.access.channel.ChannelProcessor;
|
||||
import org.springframework.security.web.access.channel.InsecureChannelProcessor;
|
||||
import org.springframework.security.web.access.channel.RetryWithHttpEntryPoint;
|
||||
import org.springframework.security.web.access.channel.RetryWithHttpsEntryPoint;
|
||||
import org.springframework.security.web.access.channel.SecureChannelProcessor;
|
||||
import org.springframework.security.web.access.intercept.DefaultFilterInvocationSecurityMetadataSource;
|
||||
import org.springframework.security.web.util.RequestMatcher;
|
||||
|
||||
/**
|
||||
* Adds channel security (i.e. requires HTTPS or HTTP) to an application. In order for
|
||||
* {@link ChannelSecurityConfigurer} to be useful, at least one {@link RequestMatcher} should be mapped to HTTP
|
||||
* or HTTPS.
|
||||
*
|
||||
* <p>
|
||||
* By default an {@link InsecureChannelProcessor} and a {@link SecureChannelProcessor} will be registered.
|
||||
* </p>
|
||||
*
|
||||
* <h2>Security Filters</h2>
|
||||
*
|
||||
* The following Filters are populated
|
||||
*
|
||||
* <ul>
|
||||
* <li>{@link ChannelProcessingFilter}</li>
|
||||
* </ul>
|
||||
*
|
||||
* <h2>Shared Objects Created</h2>
|
||||
*
|
||||
* No shared objects are created.
|
||||
*
|
||||
* <h2>Shared Objects Used</h2>
|
||||
*
|
||||
* The following shared objects are used:
|
||||
*
|
||||
* <ul>
|
||||
* <li>{@link PortMapper} is used to create the default {@link ChannelProcessor} instances</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param <H> the type of {@link HttpSecurityBuilder} that is being configured
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @since 3.2
|
||||
*/
|
||||
public final class ChannelSecurityConfigurer<H extends HttpSecurityBuilder<H>> extends
|
||||
AbstractRequestMatcherMappingConfigurer<H,ChannelSecurityConfigurer<H>.RequiresChannelUrl,DefaultSecurityFilterChain> {
|
||||
private ChannelProcessingFilter channelFilter = new ChannelProcessingFilter();
|
||||
private LinkedHashMap<RequestMatcher,Collection<ConfigAttribute>> requestMap = new LinkedHashMap<RequestMatcher,Collection<ConfigAttribute>>();
|
||||
private List<ChannelProcessor> channelProcessors;
|
||||
|
||||
/**
|
||||
* Creates a new instance
|
||||
* @see HttpSecurity#requiresChannel()
|
||||
*/
|
||||
public ChannelSecurityConfigurer() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(H http) throws Exception {
|
||||
ChannelDecisionManagerImpl channelDecisionManager = new ChannelDecisionManagerImpl();
|
||||
channelDecisionManager.setChannelProcessors(getChannelProcessors(http));
|
||||
channelDecisionManager = postProcess(channelDecisionManager);
|
||||
|
||||
channelFilter.setChannelDecisionManager(channelDecisionManager);
|
||||
|
||||
DefaultFilterInvocationSecurityMetadataSource filterInvocationSecurityMetadataSource =
|
||||
new DefaultFilterInvocationSecurityMetadataSource(requestMap);
|
||||
channelFilter.setSecurityMetadataSource(filterInvocationSecurityMetadataSource);
|
||||
|
||||
channelFilter = postProcess(channelFilter);
|
||||
http.addFilter(channelFilter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the {@link ChannelProcessor} instances to use in {@link ChannelDecisionManagerImpl}
|
||||
* @param channelProcessors
|
||||
* @return
|
||||
*/
|
||||
public ChannelSecurityConfigurer<H> channelProcessors(List<ChannelProcessor> channelProcessors) {
|
||||
this.channelProcessors = channelProcessors;
|
||||
return this;
|
||||
}
|
||||
|
||||
private List<ChannelProcessor> getChannelProcessors(H http) {
|
||||
if(channelProcessors != null) {
|
||||
return channelProcessors;
|
||||
}
|
||||
|
||||
InsecureChannelProcessor insecureChannelProcessor = new InsecureChannelProcessor();
|
||||
SecureChannelProcessor secureChannelProcessor = new SecureChannelProcessor();
|
||||
|
||||
PortMapper portMapper = http.getSharedObject(PortMapper.class);
|
||||
if(portMapper != null) {
|
||||
RetryWithHttpEntryPoint httpEntryPoint = new RetryWithHttpEntryPoint();
|
||||
httpEntryPoint.setPortMapper(portMapper);
|
||||
insecureChannelProcessor.setEntryPoint(httpEntryPoint);
|
||||
|
||||
RetryWithHttpsEntryPoint httpsEntryPoint = new RetryWithHttpsEntryPoint();
|
||||
httpsEntryPoint.setPortMapper(portMapper);
|
||||
secureChannelProcessor.setEntryPoint(httpsEntryPoint);
|
||||
}
|
||||
insecureChannelProcessor = postProcess(insecureChannelProcessor);
|
||||
secureChannelProcessor = postProcess(secureChannelProcessor);
|
||||
return Arrays.<ChannelProcessor>asList(insecureChannelProcessor, secureChannelProcessor);
|
||||
}
|
||||
|
||||
|
||||
private ChannelSecurityConfigurer<H> addAttribute(String attribute, List<RequestMatcher> matchers) {
|
||||
for(RequestMatcher matcher : matchers) {
|
||||
Collection<ConfigAttribute> attrs = Arrays.<ConfigAttribute>asList(new SecurityConfig(attribute));
|
||||
requestMap.put(matcher, attrs);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected RequiresChannelUrl chainRequestMatchersInternal(List<RequestMatcher> requestMatchers) {
|
||||
return new RequiresChannelUrl(requestMatchers);
|
||||
}
|
||||
|
||||
public final class RequiresChannelUrl {
|
||||
private List<RequestMatcher> requestMatchers;
|
||||
|
||||
private RequiresChannelUrl(List<RequestMatcher> requestMatchers) {
|
||||
this.requestMatchers = requestMatchers;
|
||||
}
|
||||
|
||||
public ChannelSecurityConfigurer<H> requiresSecure() {
|
||||
return requires("REQUIRES_SECURE_CHANNEL");
|
||||
}
|
||||
|
||||
public ChannelSecurityConfigurer<H> requiresInsecure() {
|
||||
return requires("REQUIRES_INSECURE_CHANNEL");
|
||||
}
|
||||
|
||||
public ChannelSecurityConfigurer<H> requires(String attribute) {
|
||||
return addAttribute(attribute, requestMatchers);
|
||||
}
|
||||
}
|
||||
}
|
||||
+82
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Copyright 2002-2013 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.config.annotation.web.configurers;
|
||||
|
||||
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
import org.springframework.security.web.AuthenticationEntryPoint;
|
||||
import org.springframework.security.web.authentication.ui.DefaultLoginPageViewFilter;
|
||||
|
||||
/**
|
||||
* Adds a Filter that will generate a login page if one is not specified otherwise when using {@link WebSecurityConfigurerAdapter}.
|
||||
*
|
||||
* <p>
|
||||
* By default an {@link org.springframework.security.web.access.channel.InsecureChannelProcessor} and a {@link org.springframework.security.web.access.channel.SecureChannelProcessor} will be registered.
|
||||
* </p>
|
||||
*
|
||||
* <h2>Security Filters</h2>
|
||||
*
|
||||
* The following Filters are conditionally populated
|
||||
*
|
||||
* <ul>
|
||||
* <li>{@link DefaultLoginPageViewFilter} if the {@link FormLoginConfigurer} did not have a login page specified</li>
|
||||
* </ul>
|
||||
*
|
||||
* <h2>Shared Objects Created</h2>
|
||||
*
|
||||
* No shared objects are created.
|
||||
*isLogoutRequest
|
||||
* <h2>Shared Objects Used</h2>
|
||||
*
|
||||
* The following shared objects are used:
|
||||
*
|
||||
* <ul>
|
||||
* <li>{@link org.springframework.security.web.PortMapper} is used to create the default {@link org.springframework.security.web.access.channel.ChannelProcessor} instances</li>
|
||||
* <li>{@link FormLoginConfigurer} is used to determine if the {@link DefaultLoginPageConfigurer} should be added and how to configure it.</li>
|
||||
* </ul>
|
||||
*
|
||||
* @see WebSecurityConfigurerAdapter
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @since 3.2
|
||||
*/
|
||||
public final class DefaultLoginPageConfigurer<H extends HttpSecurityBuilder<H>> extends
|
||||
AbstractHttpConfigurer<H> {
|
||||
|
||||
private DefaultLoginPageViewFilter loginPageGeneratingFilter = new DefaultLoginPageViewFilter();
|
||||
|
||||
@Override
|
||||
public void init(H http) throws Exception {
|
||||
http.setSharedObject(DefaultLoginPageViewFilter.class, loginPageGeneratingFilter);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public void configure(H http) throws Exception {
|
||||
AuthenticationEntryPoint authenticationEntryPoint = null;
|
||||
ExceptionHandlingConfigurer<?> exceptionConf = http.getConfigurer(ExceptionHandlingConfigurer.class);
|
||||
if(exceptionConf != null) {
|
||||
authenticationEntryPoint = exceptionConf.getAuthenticationEntryPoint();
|
||||
}
|
||||
|
||||
if(loginPageGeneratingFilter.isEnabled() && authenticationEntryPoint == null) {
|
||||
loginPageGeneratingFilter = postProcess(loginPageGeneratingFilter);
|
||||
http.addFilter(loginPageGeneratingFilter);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
+164
@@ -0,0 +1,164 @@
|
||||
/*
|
||||
* Copyright 2002-2013 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.config.annotation.web.configurers;
|
||||
|
||||
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.web.AuthenticationEntryPoint;
|
||||
import org.springframework.security.web.access.AccessDeniedHandler;
|
||||
import org.springframework.security.web.access.AccessDeniedHandlerImpl;
|
||||
import org.springframework.security.web.access.ExceptionTranslationFilter;
|
||||
import org.springframework.security.web.authentication.Http403ForbiddenEntryPoint;
|
||||
import org.springframework.security.web.savedrequest.HttpSessionRequestCache;
|
||||
import org.springframework.security.web.savedrequest.RequestCache;
|
||||
|
||||
/**
|
||||
* Adds exception handling for Spring Security related exceptions to an application. All properties have reasonable
|
||||
* defaults, so no additional configuration is required other than applying this
|
||||
* {@link org.springframework.security.config.annotation.SecurityConfigurer}.
|
||||
*
|
||||
* <h2>Security Filters</h2>
|
||||
*
|
||||
* The following Filters are populated
|
||||
*
|
||||
* <ul>
|
||||
* <li>{@link ExceptionTranslationFilter}</li>
|
||||
* </ul>
|
||||
*
|
||||
* <h2>Shared Objects Created</h2>
|
||||
*
|
||||
* No shared objects are created.
|
||||
*
|
||||
* <h2>Shared Objects Used</h2>
|
||||
*
|
||||
* The following shared objects are used:
|
||||
*
|
||||
* <ul>
|
||||
* <li>{@link HttpSecurity#authenticationEntryPoint()} is used to process requests that require
|
||||
* authentication</li>
|
||||
* <li>If no explicit {@link RequestCache}, is provided a {@link RequestCache} shared object is used to replay
|
||||
* the request after authentication is successful</li>
|
||||
* <li>{@link AuthenticationEntryPoint} - see {@link #authenticationEntryPoint(AuthenticationEntryPoint)} </li>
|
||||
* </ul>
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @since 3.2
|
||||
*/
|
||||
public final class ExceptionHandlingConfigurer<H extends HttpSecurityBuilder<H>> extends AbstractHttpConfigurer<H> {
|
||||
|
||||
private AuthenticationEntryPoint authenticationEntryPoint;
|
||||
|
||||
private AccessDeniedHandler accessDeniedHandler;
|
||||
|
||||
/**
|
||||
* Creates a new instance
|
||||
* @see HttpSecurity#exceptionHandling()
|
||||
*/
|
||||
public ExceptionHandlingConfigurer() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Shortcut to specify the {@link AccessDeniedHandler} to be used is a specific error page
|
||||
*
|
||||
* @param accessDeniedUrl the URL to the access denied page (i.e. /errors/401)
|
||||
* @return the {@link ExceptionHandlingConfigurer} for further customization
|
||||
* @see AccessDeniedHandlerImpl
|
||||
* @see {@link #accessDeniedHandler(org.springframework.security.web.access.AccessDeniedHandler)}
|
||||
*/
|
||||
public ExceptionHandlingConfigurer<H> accessDeniedPage(String accessDeniedUrl) {
|
||||
AccessDeniedHandlerImpl accessDeniedHandler = new AccessDeniedHandlerImpl();
|
||||
accessDeniedHandler.setErrorPage(accessDeniedUrl);
|
||||
return accessDeniedHandler(accessDeniedHandler);
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies the {@link AccessDeniedHandler} to be used
|
||||
*
|
||||
* @param accessDeniedHandler the {@link AccessDeniedHandler} to be used
|
||||
* @return the {@link ExceptionHandlingConfigurer} for further customization
|
||||
*/
|
||||
public ExceptionHandlingConfigurer<H> accessDeniedHandler(AccessDeniedHandler accessDeniedHandler) {
|
||||
this.accessDeniedHandler = accessDeniedHandler;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the {@link AuthenticationEntryPoint} to be used. Defaults to the
|
||||
* {@link HttpSecurity#getSharedObject(Class)} value. If that is not
|
||||
* provided defaults to {@link Http403ForbiddenEntryPoint}.
|
||||
*
|
||||
* @param authenticationEntryPoint the {@link AuthenticationEntryPoint} to use
|
||||
* @return the {@link ExceptionHandlingConfigurer} for further customizations
|
||||
*/
|
||||
public ExceptionHandlingConfigurer<H> authenticationEntryPoint(AuthenticationEntryPoint authenticationEntryPoint) {
|
||||
this.authenticationEntryPoint = authenticationEntryPoint;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets any explicitly configured {@link AuthenticationEntryPoint}
|
||||
* @return
|
||||
*/
|
||||
AuthenticationEntryPoint getAuthenticationEntryPoint() {
|
||||
return this.authenticationEntryPoint;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(H http) throws Exception {
|
||||
AuthenticationEntryPoint entryPoint = getEntryPoint(http);
|
||||
ExceptionTranslationFilter exceptionTranslationFilter = new ExceptionTranslationFilter(entryPoint, getRequestCache(http));
|
||||
if(accessDeniedHandler != null) {
|
||||
exceptionTranslationFilter.setAccessDeniedHandler(accessDeniedHandler);
|
||||
}
|
||||
exceptionTranslationFilter = postProcess(exceptionTranslationFilter);
|
||||
http.addFilter(exceptionTranslationFilter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the {@link AuthenticationEntryPoint} according to the rules specified by {@link #authenticationEntryPoint(AuthenticationEntryPoint)}
|
||||
* @param http the {@link HttpSecurity} used to look up shared {@link AuthenticationEntryPoint}
|
||||
* @return the {@link AuthenticationEntryPoint} to use
|
||||
*/
|
||||
private AuthenticationEntryPoint getEntryPoint(H http) {
|
||||
AuthenticationEntryPoint entryPoint = this.authenticationEntryPoint;
|
||||
if(entryPoint == null) {
|
||||
AuthenticationEntryPoint sharedEntryPoint = http.getSharedObject(AuthenticationEntryPoint.class);
|
||||
if(sharedEntryPoint != null) {
|
||||
entryPoint = sharedEntryPoint;
|
||||
} else {
|
||||
entryPoint = new Http403ForbiddenEntryPoint();
|
||||
}
|
||||
}
|
||||
return entryPoint;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the {@link RequestCache} to use. If one is defined using
|
||||
* {@link #requestCache(org.springframework.security.web.savedrequest.RequestCache)}, then it is used. Otherwise, an
|
||||
* attempt to find a {@link RequestCache} shared object is made. If that fails, an {@link HttpSessionRequestCache}
|
||||
* is used
|
||||
*
|
||||
* @param http the {@link HttpSecurity} to attempt to fined the shared object
|
||||
* @return the {@link RequestCache} to use
|
||||
*/
|
||||
private RequestCache getRequestCache(H http) {
|
||||
RequestCache result = http.getSharedObject(RequestCache.class);
|
||||
if(result != null) {
|
||||
return result;
|
||||
}
|
||||
return new HttpSessionRequestCache();
|
||||
}
|
||||
}
|
||||
+296
@@ -0,0 +1,296 @@
|
||||
/*
|
||||
* Copyright 2002-2013 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.config.annotation.web.configurers;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.security.access.AccessDecisionVoter;
|
||||
import org.springframework.security.access.ConfigAttribute;
|
||||
import org.springframework.security.access.SecurityConfig;
|
||||
import org.springframework.security.access.expression.SecurityExpressionHandler;
|
||||
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.web.FilterInvocation;
|
||||
import org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler;
|
||||
import org.springframework.security.web.access.expression.ExpressionBasedFilterInvocationSecurityMetadataSource;
|
||||
import org.springframework.security.web.access.expression.WebExpressionVoter;
|
||||
import org.springframework.security.web.util.RequestMatcher;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Adds URL based authorization based upon SpEL expressions to an application. At least one
|
||||
* {@link org.springframework.web.bind.annotation.RequestMapping} needs to be mapped to {@link ConfigAttribute}'s for
|
||||
* this {@link SecurityContextConfigurer} to have meaning.
|
||||
* <h2>Security Filters</h2>
|
||||
*
|
||||
* The following Filters are populated
|
||||
*
|
||||
* <ul>
|
||||
* <li>{@link org.springframework.security.web.access.intercept.FilterSecurityInterceptor}</li>
|
||||
* </ul>
|
||||
*
|
||||
* <h2>Shared Objects Created</h2>
|
||||
*
|
||||
* The following shared objects are populated to allow other {@link org.springframework.security.config.annotation.SecurityConfigurer}'s to customize:
|
||||
* <ul>
|
||||
* <li>{@link org.springframework.security.web.access.intercept.FilterSecurityInterceptor}</li>
|
||||
* </ul>
|
||||
*
|
||||
* <h2>Shared Objects Used</h2>
|
||||
*
|
||||
* The following shared objects are used:
|
||||
*
|
||||
* <ul>
|
||||
* <li>{@link org.springframework.security.config.annotation.web.builders.HttpSecurity#getAuthenticationManager()}</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param <H> the type of {@link HttpSecurityBuilder} that is being configured
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @since 3.2
|
||||
* @see {@link org.springframework.security.config.annotation.web.builders.HttpSecurity#authorizeUrls()}
|
||||
*/
|
||||
public final class ExpressionUrlAuthorizationConfigurer<H extends HttpSecurityBuilder<H>> extends AbstractInterceptUrlConfigurer<H,ExpressionUrlAuthorizationConfigurer<H>,ExpressionUrlAuthorizationConfigurer<H>.AuthorizedUrl> {
|
||||
static final String permitAll = "permitAll";
|
||||
private static final String denyAll = "denyAll";
|
||||
private static final String anonymous = "anonymous";
|
||||
private static final String authenticated = "authenticated";
|
||||
private static final String fullyAuthenticated = "fullyAuthenticated";
|
||||
private static final String rememberMe = "rememberMe";
|
||||
|
||||
private SecurityExpressionHandler<FilterInvocation> expressionHandler = new DefaultWebSecurityExpressionHandler();
|
||||
|
||||
/**
|
||||
* Creates a new instance
|
||||
* @see HttpSecurity#authorizeUrls()
|
||||
*/
|
||||
public ExpressionUrlAuthorizationConfigurer() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows customization of the {@link SecurityExpressionHandler} to be used. The default is {@link DefaultWebSecurityExpressionHandler}
|
||||
*
|
||||
* @param expressionHandler the {@link SecurityExpressionHandler} to be used
|
||||
* @return the {@link ExpressionUrlAuthorizationConfigurer} for further customization.
|
||||
*/
|
||||
public ExpressionUrlAuthorizationConfigurer<H> expressionHandler(SecurityExpressionHandler<FilterInvocation> expressionHandler) {
|
||||
this.expressionHandler = expressionHandler;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected final AuthorizedUrl chainRequestMatchersInternal(List<RequestMatcher> requestMatchers) {
|
||||
return new AuthorizedUrl(requestMatchers);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("rawtypes")
|
||||
final List<AccessDecisionVoter> getDecisionVoters() {
|
||||
List<AccessDecisionVoter> decisionVoters = new ArrayList<AccessDecisionVoter>();
|
||||
WebExpressionVoter expressionVoter = new WebExpressionVoter();
|
||||
expressionVoter.setExpressionHandler(expressionHandler);
|
||||
decisionVoters.add(expressionVoter);
|
||||
return decisionVoters;
|
||||
}
|
||||
|
||||
@Override
|
||||
final ExpressionBasedFilterInvocationSecurityMetadataSource createMetadataSource() {
|
||||
LinkedHashMap<RequestMatcher, Collection<ConfigAttribute>> requestMap = createRequestMap();
|
||||
if(requestMap.isEmpty()) {
|
||||
throw new IllegalStateException("At least one mapping is required (i.e. authorizeUrls().anyRequest.authenticated())");
|
||||
}
|
||||
return new ExpressionBasedFilterInvocationSecurityMetadataSource(requestMap, expressionHandler);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows registering multiple {@link RequestMatcher} instances to a collection of {@link ConfigAttribute} instances
|
||||
*
|
||||
* @param requestMatchers the {@link RequestMatcher} instances to register to the {@link ConfigAttribute} instances
|
||||
* @param configAttributes the {@link ConfigAttribute} to be mapped by the {@link RequestMatcher} instances
|
||||
* @return the {@link ExpressionUrlAuthorizationConfigurer} for further customization.
|
||||
*/
|
||||
private ExpressionUrlAuthorizationConfigurer<H> interceptUrl(Iterable<? extends RequestMatcher> requestMatchers, Collection<ConfigAttribute> configAttributes) {
|
||||
for(RequestMatcher requestMatcher : requestMatchers) {
|
||||
addMapping(new UrlMapping(requestMatcher, configAttributes));
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
private static String hasRole(String role) {
|
||||
Assert.notNull(role, "role cannot be null");
|
||||
if (role.startsWith("ROLE_")) {
|
||||
throw new IllegalArgumentException("role should not start with 'ROLE_' since it is automatically inserted. Got '" + role + "'");
|
||||
}
|
||||
return "hasRole('ROLE_" + role + "')";
|
||||
}
|
||||
|
||||
private static String hasAuthority(String authority) {
|
||||
return "hasAuthority('" + authority + "')";
|
||||
}
|
||||
|
||||
private static String hasAnyAuthority(String... authorities) {
|
||||
String anyAuthorities = StringUtils.arrayToDelimitedString(authorities, "','");
|
||||
return "hasAnyAuthority('" + anyAuthorities + "')";
|
||||
}
|
||||
|
||||
private static String hasIpAddress(String ipAddressExpression) {
|
||||
return "hasIpAddress('" + ipAddressExpression + "')";
|
||||
}
|
||||
|
||||
public final class AuthorizedUrl {
|
||||
private List<RequestMatcher> requestMatchers;
|
||||
private boolean not;
|
||||
|
||||
/**
|
||||
* Creates a new instance
|
||||
*
|
||||
* @param requestMatchers the {@link RequestMatcher} instances to map
|
||||
*/
|
||||
private AuthorizedUrl(List<RequestMatcher> requestMatchers) {
|
||||
this.requestMatchers = requestMatchers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Negates the following expression.
|
||||
*
|
||||
* @param role the role to require (i.e. USER, ADMIN, etc). Note, it should not start with "ROLE_" as
|
||||
* this is automatically inserted.
|
||||
* @return the {@link ExpressionUrlAuthorizationConfigurer} for further customization
|
||||
*/
|
||||
public AuthorizedUrl not() {
|
||||
this.not = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Shortcut for specifying URLs require a particular role. If you do not want to have "ROLE_" automatically
|
||||
* inserted see {@link #hasAuthority(String)}.
|
||||
*
|
||||
* @param role the role to require (i.e. USER, ADMIN, etc). Note, it should not start with "ROLE_" as
|
||||
* this is automatically inserted.
|
||||
* @return the {@link ExpressionUrlAuthorizationConfigurer} for further customization
|
||||
*/
|
||||
public ExpressionUrlAuthorizationConfigurer<H> hasRole(String role) {
|
||||
return access(ExpressionUrlAuthorizationConfigurer.hasRole(role));
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify that URLs require a particular authority.
|
||||
*
|
||||
* @param authority the authority to require (i.e. ROLE_USER, ROLE_ADMIN, etc).
|
||||
* @return the {@link ExpressionUrlAuthorizationConfigurer} for further customization
|
||||
*/
|
||||
public ExpressionUrlAuthorizationConfigurer<H> hasAuthority(String authority) {
|
||||
return access(ExpressionUrlAuthorizationConfigurer.hasAuthority(authority));
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify that URLs requires any of a number authorities.
|
||||
*
|
||||
* @param authorities the requests require at least one of the authorities (i.e. "ROLE_USER","ROLE_ADMIN" would
|
||||
* mean either "ROLE_USER" or "ROLE_ADMIN" is required).
|
||||
* @return the {@link ExpressionUrlAuthorizationConfigurer} for further customization
|
||||
*/
|
||||
public ExpressionUrlAuthorizationConfigurer<H> hasAnyAuthority(String... authorities) {
|
||||
return access(ExpressionUrlAuthorizationConfigurer.hasAnyAuthority(authorities));
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify that URLs requires a specific IP Address or
|
||||
* <a href="http://forum.springsource.org/showthread.php?102783-How-to-use-hasIpAddress&p=343971#post343971">subnet</a>.
|
||||
*
|
||||
* @param ipaddressExpression the ipaddress (i.e. 192.168.1.79) or local subnet (i.e. 192.168.0/24)
|
||||
* @return the {@link ExpressionUrlAuthorizationConfigurer} for further customization
|
||||
*/
|
||||
public ExpressionUrlAuthorizationConfigurer<H> hasIpAddress(String ipaddressExpression) {
|
||||
return access(ExpressionUrlAuthorizationConfigurer.hasIpAddress(ipaddressExpression));
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify that URLs are allowed by anyone.
|
||||
*
|
||||
* @return the {@link ExpressionUrlAuthorizationConfigurer} for further customization
|
||||
*/
|
||||
public ExpressionUrlAuthorizationConfigurer<H> permitAll() {
|
||||
return access(permitAll);
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify that URLs are allowed by anonymous users.
|
||||
*
|
||||
* @return the {@link ExpressionUrlAuthorizationConfigurer} for further customization
|
||||
*/
|
||||
public ExpressionUrlAuthorizationConfigurer<H> anonymous() {
|
||||
return access(anonymous);
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify that URLs are allowed by users that have been remembered.
|
||||
*
|
||||
* @return the {@link ExpressionUrlAuthorizationConfigurer} for further customization
|
||||
* @see {@link RememberMeConfigurer}
|
||||
*/
|
||||
public ExpressionUrlAuthorizationConfigurer<H> rememberMe() {
|
||||
return access(rememberMe);
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify that URLs are not allowed by anyone.
|
||||
*
|
||||
* @return the {@link ExpressionUrlAuthorizationConfigurer} for further customization
|
||||
*/
|
||||
public ExpressionUrlAuthorizationConfigurer<H> denyAll() {
|
||||
return access(denyAll);
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify that URLs are allowed by any authenticated user.
|
||||
*
|
||||
* @return the {@link ExpressionUrlAuthorizationConfigurer} for further customization
|
||||
*/
|
||||
public ExpressionUrlAuthorizationConfigurer<H> authenticated() {
|
||||
return access(authenticated);
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify that URLs are allowed by users who have authenticated and were not "remembered".
|
||||
*
|
||||
* @return the {@link ExpressionUrlAuthorizationConfigurer} for further customization
|
||||
* @see {@link RememberMeConfigurer}
|
||||
*/
|
||||
public ExpressionUrlAuthorizationConfigurer<H> fullyAuthenticated() {
|
||||
return access(fullyAuthenticated);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows specifying that URLs are secured by an arbitrary expression
|
||||
*
|
||||
* @param attribute the expression to secure the URLs (i.e. "hasRole('ROLE_USER') and hasRole('ROLE_SUPER')")
|
||||
* @return the {@link ExpressionUrlAuthorizationConfigurer} for further customization
|
||||
*/
|
||||
public ExpressionUrlAuthorizationConfigurer<H> access(String attribute) {
|
||||
if(not) {
|
||||
attribute = "!" + attribute;
|
||||
}
|
||||
interceptUrl(requestMatchers, SecurityConfig.createList(attribute));
|
||||
return ExpressionUrlAuthorizationConfigurer.this;
|
||||
}
|
||||
}
|
||||
}
|
||||
+239
@@ -0,0 +1,239 @@
|
||||
/*
|
||||
* Copyright 2002-2013 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.config.annotation.web.configurers;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
import org.springframework.security.web.AuthenticationEntryPoint;
|
||||
import org.springframework.security.web.authentication.RememberMeServices;
|
||||
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
|
||||
import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy;
|
||||
import org.springframework.security.web.authentication.ui.DefaultLoginPageViewFilter;
|
||||
|
||||
/**
|
||||
* Adds form based authentication. All attributes have reasonable defaults
|
||||
* making all parameters are optional. If no {@link #loginPage(String)} is
|
||||
* specified, a default login page will be generated by the framework.
|
||||
*
|
||||
* <h2>Security Filters</h2>
|
||||
*
|
||||
* The following Filters are populated
|
||||
*
|
||||
* <ul>
|
||||
* <li>
|
||||
* {@link UsernamePasswordAuthenticationFilter}
|
||||
* </li>
|
||||
* </ul>
|
||||
*
|
||||
* <h2>Shared Objects Created</h2>
|
||||
*
|
||||
* The following shared objects are populated
|
||||
*
|
||||
* <ul>
|
||||
* <li> {@link AuthenticationEntryPoint} </li>
|
||||
* </ul>
|
||||
*
|
||||
* <h2>Shared Objects Used</h2>
|
||||
*
|
||||
* The following shared objects are used:
|
||||
*
|
||||
* <ul>
|
||||
* <li>{@link HttpSecurity#getAuthenticationManager()}</li>
|
||||
* <li>{@link RememberMeServices} - is optionally used. See {@link RememberMeConfigurer}</li>
|
||||
* <li>{@link SessionAuthenticationStrategy} - is optionally used. See {@link SessionManagementConfigurer}</li>
|
||||
* <li>{@link DefaultLoginPageViewFilter} - if present will be populated with information from the configuration</li>
|
||||
* </ul>
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @since 3.2
|
||||
*/
|
||||
public final class FormLoginConfigurer<H extends HttpSecurityBuilder<H>> extends AbstractAuthenticationFilterConfigurer<H,FormLoginConfigurer<H>,UsernamePasswordAuthenticationFilter> {
|
||||
|
||||
/**
|
||||
* Creates a new instance
|
||||
* @see HttpSecurity#formLogin()
|
||||
*/
|
||||
public FormLoginConfigurer() {
|
||||
super(createUsernamePasswordAuthenticationFilter(),"/login");
|
||||
usernameParameter("username");
|
||||
passwordParameter("password");
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Specifies the URL to send users to if login is required. If used with
|
||||
* {@link WebSecurityConfigurerAdapter} a default login page will be
|
||||
* generated when this attribute is not specified.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* If a URL is specified or this is not being used in conjuction with
|
||||
* {@link WebSecurityConfigurerAdapter}, users are required to process the
|
||||
* specified URL to generate a login page. In general, the login page should
|
||||
* create a form that submits a request with the following requirements to
|
||||
* work with {@link UsernamePasswordAuthenticationFilter}:
|
||||
* </p>
|
||||
*
|
||||
* <ul>
|
||||
* <li>It must be an HTTP POST</li>
|
||||
* <li>It must be submitted to {@link #loginProcessingUrl(String)}</li>
|
||||
* <li>It should include the username as an HTTP parameter by the name of
|
||||
* {@link #usernameParameter(String)}</li>
|
||||
* <li>It should include the password as an HTTP parameter by the name of
|
||||
* {@link #passwordParameter(String)}</li>
|
||||
* </ul>
|
||||
*
|
||||
* <h2>Example login.jsp</h2>
|
||||
*
|
||||
* Login pages can be rendered with any technology you choose so long as the
|
||||
* rules above are followed. Below is an example login.jsp that can be used as
|
||||
* a quick start when using JSP's or as a baseline to translate into another view
|
||||
* technology.
|
||||
*
|
||||
* <pre>
|
||||
* <!-- loginProcessingUrl should correspond to FormLoginConfigurer#loginProcessingUrl. Don't forget to perform a POST -->
|
||||
* <c:url value="/login" var="loginProcessingUrl"/>
|
||||
* <form action="${loginProcessingUrl}" method="post">
|
||||
* <fieldset>
|
||||
* <legend>Please Login</legend>
|
||||
* <!-- use param.error assuming FormLoginConfigurer#failureUrl contains the query parameter error -->
|
||||
* <c:if test="${param.error != null}">
|
||||
* <div>
|
||||
* Failed to login.
|
||||
* <c:if test="${SPRING_SECURITY_LAST_EXCEPTION != null}">
|
||||
* Reason: <c:out value="${SPRING_SECURITY_LAST_EXCEPTION.message}" />
|
||||
* </c:if>
|
||||
* </div>
|
||||
* </c:if>
|
||||
* <!-- the configured LogoutConfigurer#logoutSuccessUrl is /login?logout and contains the query param logout -->
|
||||
* <c:if test="${param.logout != null}">
|
||||
* <div>
|
||||
* You have been logged out.
|
||||
* </div>
|
||||
* </c:if>
|
||||
* <p>
|
||||
* <label for="username">Username</label>
|
||||
* <input type="text" id="username" name="username"/>
|
||||
* </p>
|
||||
* <p>
|
||||
* <label for="password">Password</label>
|
||||
* <input type="password" id="password" name="password"/>
|
||||
* </p>
|
||||
* <!-- if using RememberMeConfigurer make sure remember-me matches RememberMeConfigurer#rememberMeParameter -->
|
||||
* <p>
|
||||
* <label for="remember-me">Remember Me?</label>
|
||||
* <input type="checkbox" id="remember-me" name="remember-me"/>
|
||||
* </p>
|
||||
* <div>
|
||||
* <button type="submit" class="btn">Log in</button>
|
||||
* </div>
|
||||
* </fieldset>
|
||||
* </form>
|
||||
* </pre>
|
||||
*
|
||||
* @param loginPage
|
||||
* the login page to redirect to if authentication is required
|
||||
* (i.e. "/login")
|
||||
* @return the {@link FormLoginConfigurer} for additional customization
|
||||
*/
|
||||
public FormLoginConfigurer<H> loginPage(String loginPage) {
|
||||
return super.loginPage(loginPage);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* The HTTP parameter to look for the username when performing
|
||||
* authentication. Default is "username".
|
||||
*
|
||||
* @param usernameParameter
|
||||
* the HTTP parameter to look for the username when performing
|
||||
* authentication
|
||||
* @return the {@link FormLoginConfigurer} for additional customization
|
||||
*/
|
||||
public FormLoginConfigurer<H> usernameParameter(String usernameParameter) {
|
||||
getAuthenticationFilter().setUsernameParameter(usernameParameter);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* The HTTP parameter to look for the password when performing
|
||||
* authentication. Default is "password".
|
||||
*
|
||||
* @param passwordParameter
|
||||
* the HTTP parameter to look for the password when performing
|
||||
* authentication
|
||||
* @return the {@link FormLoginConfigurer} for additional customization
|
||||
*/
|
||||
public FormLoginConfigurer<H> passwordParameter(String passwordParameter) {
|
||||
getAuthenticationFilter().setPasswordParameter(passwordParameter);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(H http) throws Exception {
|
||||
super.init(http);
|
||||
initDefaultLoginFilter(http);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the HTTP parameter that is used to submit the username.
|
||||
*
|
||||
* @return the HTTP parameter that is used to submit the username
|
||||
*/
|
||||
private String getUsernameParameter() {
|
||||
return getAuthenticationFilter().getUsernameParameter();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the HTTP parameter that is used to submit the password.
|
||||
*
|
||||
* @return the HTTP parameter that is used to submit the password
|
||||
*/
|
||||
private String getPasswordParameter() {
|
||||
return getAuthenticationFilter().getPasswordParameter();
|
||||
}
|
||||
|
||||
/**
|
||||
* If available, initializes the {@link DefaultLoginPageViewFilter} shared object.
|
||||
*
|
||||
* @param http the {@link HttpSecurityBuilder} to use
|
||||
*/
|
||||
private void initDefaultLoginFilter(H http) {
|
||||
DefaultLoginPageViewFilter loginPageGeneratingFilter = http.getSharedObject(DefaultLoginPageViewFilter.class);
|
||||
if(loginPageGeneratingFilter != null && !isCustomLoginPage()) {
|
||||
loginPageGeneratingFilter.setFormLoginEnabled(true);
|
||||
loginPageGeneratingFilter.setUsernameParameter(getUsernameParameter());
|
||||
loginPageGeneratingFilter.setPasswordParameter(getPasswordParameter());
|
||||
loginPageGeneratingFilter.setLoginPageUrl(getLoginPage());
|
||||
loginPageGeneratingFilter.setFailureUrl(getFailureUrl());
|
||||
loginPageGeneratingFilter.setAuthenticationUrl(getLoginProcessingUrl());
|
||||
}
|
||||
}
|
||||
|
||||
private static UsernamePasswordAuthenticationFilter createUsernamePasswordAuthenticationFilter() {
|
||||
return new UsernamePasswordAuthenticationFilter() {
|
||||
@Override
|
||||
protected boolean requiresAuthentication(HttpServletRequest request, HttpServletResponse response) {
|
||||
return "POST".equals(request.getMethod()) && super.requiresAuthentication(request, response);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
+127
@@ -0,0 +1,127 @@
|
||||
/*
|
||||
* Copyright 2002-2013 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.config.annotation.web.configurers;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.springframework.security.authentication.AuthenticationDetailsSource;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.web.AuthenticationEntryPoint;
|
||||
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
|
||||
import org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint;
|
||||
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
|
||||
|
||||
/**
|
||||
* Adds HTTP basic based authentication. All attributes have reasonable defaults
|
||||
* making all parameters are optional.
|
||||
*
|
||||
* <h2>Security Filters</h2>
|
||||
*
|
||||
* The following Filters are populated
|
||||
*
|
||||
* <ul>
|
||||
* <li>
|
||||
* {@link BasicAuthenticationFilter}
|
||||
* </li>
|
||||
* </ul>
|
||||
*
|
||||
* <h2>Shared Objects Created</h2>
|
||||
*
|
||||
* No shared objects are populated
|
||||
*
|
||||
* <h2>Shared Objects Used</h2>
|
||||
*
|
||||
* The following shared objects are used:
|
||||
*
|
||||
* <ul>
|
||||
* <li>{@link HttpSecurity#getAuthenticationManager()} </li>
|
||||
* </ul>
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @since 3.2
|
||||
*/
|
||||
public final class HttpBasicConfigurer<B extends HttpSecurityBuilder<B>> extends AbstractHttpConfigurer<B> {
|
||||
private static final String DEFAULT_REALM = "Spring Security Application";
|
||||
|
||||
private AuthenticationEntryPoint authenticationEntryPoint;
|
||||
private AuthenticationDetailsSource<HttpServletRequest, ?> authenticationDetailsSource;
|
||||
|
||||
/**
|
||||
* Creates a new instance
|
||||
* @throws Exception
|
||||
* @see {@link HttpSecurity#httpBasic()}
|
||||
*/
|
||||
public HttpBasicConfigurer() throws Exception {
|
||||
realmName(DEFAULT_REALM);
|
||||
}
|
||||
|
||||
/**
|
||||
* Shortcut for {@link #authenticationEntryPoint(AuthenticationEntryPoint)}
|
||||
* specifying a {@link BasicAuthenticationEntryPoint} with the specified
|
||||
* realm name.
|
||||
*
|
||||
* @param realmName
|
||||
* the HTTP Basic realm to use
|
||||
* @return {@link HttpBasicConfigurer} for additional customization
|
||||
* @throws Exception
|
||||
*/
|
||||
public HttpBasicConfigurer<B> realmName(String realmName) throws Exception {
|
||||
BasicAuthenticationEntryPoint basicAuthEntryPoint = new BasicAuthenticationEntryPoint();
|
||||
basicAuthEntryPoint.setRealmName(realmName);
|
||||
basicAuthEntryPoint.afterPropertiesSet();
|
||||
return authenticationEntryPoint(basicAuthEntryPoint);
|
||||
}
|
||||
|
||||
/**
|
||||
* The {@link AuthenticationEntryPoint} to be po pulated on
|
||||
* {@link BasicAuthenticationFilter} in the event that authentication fails.
|
||||
* The default to use {@link BasicAuthenticationEntryPoint} with the realm
|
||||
* "Spring Security Application".
|
||||
*
|
||||
* @param authenticationEntryPoint the {@link AuthenticationEntryPoint} to use
|
||||
* @return {@link HttpBasicConfigurer} for additional customization
|
||||
*/
|
||||
public HttpBasicConfigurer<B> authenticationEntryPoint(AuthenticationEntryPoint authenticationEntryPoint) {
|
||||
this.authenticationEntryPoint = authenticationEntryPoint;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies a custom {@link AuthenticationDetailsSource} to use for basic
|
||||
* authentication. The default is {@link WebAuthenticationDetailsSource}.
|
||||
*
|
||||
* @param authenticationDetailsSource
|
||||
* the custom {@link AuthenticationDetailsSource} to use
|
||||
* @return {@link HttpBasicConfigurer} for additional customization
|
||||
*/
|
||||
public HttpBasicConfigurer<B> authenticationDetailsSource(AuthenticationDetailsSource<HttpServletRequest, ?> authenticationDetailsSource) {
|
||||
this.authenticationDetailsSource = authenticationDetailsSource;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(B http) throws Exception {
|
||||
AuthenticationManager authenticationManager = http.getAuthenticationManager();
|
||||
BasicAuthenticationFilter basicAuthenticationFilter = new BasicAuthenticationFilter(authenticationManager, authenticationEntryPoint);
|
||||
if(authenticationDetailsSource != null) {
|
||||
basicAuthenticationFilter.setAuthenticationDetailsSource(authenticationDetailsSource);
|
||||
}
|
||||
basicAuthenticationFilter = postProcess(basicAuthenticationFilter);
|
||||
http.addFilter(basicAuthenticationFilter);
|
||||
}
|
||||
}
|
||||
+261
@@ -0,0 +1,261 @@
|
||||
/*
|
||||
* Copyright 2002-2013 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.config.annotation.web.configurers;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.core.authority.mapping.SimpleMappableAttributesRetriever;
|
||||
import org.springframework.security.core.userdetails.AuthenticationUserDetailsService;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.security.web.AuthenticationEntryPoint;
|
||||
import org.springframework.security.web.authentication.Http403ForbiddenEntryPoint;
|
||||
import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationProvider;
|
||||
import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken;
|
||||
import org.springframework.security.web.authentication.preauth.PreAuthenticatedGrantedAuthoritiesUserDetailsService;
|
||||
import org.springframework.security.web.authentication.preauth.j2ee.J2eeBasedPreAuthenticatedWebAuthenticationDetailsSource;
|
||||
import org.springframework.security.web.authentication.preauth.j2ee.J2eePreAuthenticatedProcessingFilter;
|
||||
|
||||
/**
|
||||
* Adds support for J2EE pre authentication.
|
||||
*
|
||||
* <h2>Security Filters</h2>
|
||||
*
|
||||
* The following Filters are populated
|
||||
*
|
||||
* <ul>
|
||||
* <li>
|
||||
* {@link J2eePreAuthenticatedProcessingFilter}</li>
|
||||
* </ul>
|
||||
*
|
||||
* <h2>Shared Objects Created</h2>
|
||||
*
|
||||
* <ul>
|
||||
* <li>
|
||||
* {@link AuthenticationEntryPoint}
|
||||
* is populated with an {@link Http403ForbiddenEntryPoint}</li>
|
||||
* <li>A {@link PreAuthenticatedAuthenticationProvider} is populated into
|
||||
* {@link HttpSecurity#authenticationProvider(org.springframework.security.authentication.AuthenticationProvider)}
|
||||
* </li>
|
||||
* </ul>
|
||||
*
|
||||
* <h2>Shared Objects Used</h2>
|
||||
*
|
||||
* The following shared objects are used:
|
||||
*
|
||||
* <ul>
|
||||
* <li>{@link HttpSecurity#getAuthenticationManager()}</li>
|
||||
* </ul>
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @since 3.2
|
||||
*/
|
||||
public final class JeeConfigurer<H extends HttpSecurityBuilder<H>> extends AbstractHttpConfigurer<H> {
|
||||
private J2eePreAuthenticatedProcessingFilter j2eePreAuthenticatedProcessingFilter;
|
||||
private AuthenticationUserDetailsService<PreAuthenticatedAuthenticationToken> authenticationUserDetailsService;
|
||||
private Set<String> mappableRoles = new HashSet<String>();
|
||||
|
||||
/**
|
||||
* Creates a new instance
|
||||
* @see HttpSecurity#jee()
|
||||
*/
|
||||
public JeeConfigurer() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies roles to use map from the {@link HttpServletRequest} to the
|
||||
* {@link UserDetails}. If {@link HttpServletRequest#isUserInRole(String)}
|
||||
* returns true, the role is added to the {@link UserDetails}. This method
|
||||
* is the equivalent of invoking {@link #mappableAuthorities(Set)}. Multiple
|
||||
* invocations of {@link #mappableAuthorities(String...)} will override previous
|
||||
* invocations.
|
||||
*
|
||||
* <p>
|
||||
* There are no default roles that are mapped.
|
||||
* </p>
|
||||
*
|
||||
* @param mappableRoles
|
||||
* the roles to attempt to map to the {@link UserDetails} (i.e.
|
||||
* "ROLE_USER", "ROLE_ADMIN", etc).
|
||||
* @return the {@link JeeConfigurer} for further customizations
|
||||
* @see SimpleMappableAttributesRetriever
|
||||
* @see #mappableRoles(String...)
|
||||
*/
|
||||
public JeeConfigurer<H> mappableAuthorities(String... mappableRoles) {
|
||||
this.mappableRoles.clear();
|
||||
for(String role : mappableRoles) {
|
||||
this.mappableRoles.add(role);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies roles to use map from the {@link HttpServletRequest} to the
|
||||
* {@link UserDetails} and automatically prefixes it with "ROLE_". If
|
||||
* {@link HttpServletRequest#isUserInRole(String)} returns true, the role is
|
||||
* added to the {@link UserDetails}. This method is the equivalent of
|
||||
* invoking {@link #mappableAuthorities(Set)}. Multiple invocations of
|
||||
* {@link #mappableRoles(String...)} will override previous invocations.
|
||||
*
|
||||
* <p>
|
||||
* There are no default roles that are mapped.
|
||||
* </p>
|
||||
*
|
||||
* @param mappableRoles
|
||||
* the roles to attempt to map to the {@link UserDetails} (i.e.
|
||||
* "USER", "ADMIN", etc).
|
||||
* @return the {@link JeeConfigurer} for further customizations
|
||||
* @see SimpleMappableAttributesRetriever
|
||||
* @see #mappableAuthorities(String...)
|
||||
*/
|
||||
public JeeConfigurer<H> mappableRoles(String... mappableRoles) {
|
||||
this.mappableRoles.clear();
|
||||
for(String role : mappableRoles) {
|
||||
this.mappableRoles.add("ROLE_" + role);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies roles to use map from the {@link HttpServletRequest} to the
|
||||
* {@link UserDetails}. If {@link HttpServletRequest#isUserInRole(String)}
|
||||
* returns true, the role is added to the {@link UserDetails}. This is the
|
||||
* equivalent of {@link #mappableRoles(String...)}. Multiple invocations of
|
||||
* {@link #mappableAuthorities(Set)} will override previous invocations.
|
||||
*
|
||||
* <p>
|
||||
* There are no default roles that are mapped.
|
||||
* </p>
|
||||
*
|
||||
* @param mappableRoles
|
||||
* the roles to attempt to map to the {@link UserDetails}.
|
||||
* @return the {@link JeeConfigurer} for further customizations
|
||||
* @see SimpleMappableAttributesRetriever
|
||||
*/
|
||||
public JeeConfigurer<H> mappableAuthorities(Set<String> mappableRoles) {
|
||||
this.mappableRoles = mappableRoles;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies the {@link AuthenticationUserDetailsService} that is used with
|
||||
* the {@link PreAuthenticatedAuthenticationProvider}. The default is a
|
||||
* {@link PreAuthenticatedGrantedAuthoritiesUserDetailsService}.
|
||||
*
|
||||
* @param authenticatedUserDetailsService the {@link AuthenticationUserDetailsService} to use.
|
||||
* @return the {@link JeeConfigurer} for further configuration
|
||||
*/
|
||||
public JeeConfigurer<H> authenticatedUserDetailsService(
|
||||
AuthenticationUserDetailsService<PreAuthenticatedAuthenticationToken> authenticatedUserDetailsService) {
|
||||
this.authenticationUserDetailsService = authenticatedUserDetailsService;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows specifying the {@link J2eePreAuthenticatedProcessingFilter} to
|
||||
* use. If {@link J2eePreAuthenticatedProcessingFilter} is provided, all of its attributes must also be
|
||||
* configured manually (i.e. all attributes populated in the {@link JeeConfigurer} are not used).
|
||||
*
|
||||
* @param j2eePreAuthenticatedProcessingFilter the {@link J2eePreAuthenticatedProcessingFilter} to use.
|
||||
* @return the {@link JeeConfigurer} for further configuration
|
||||
*/
|
||||
public JeeConfigurer<H> j2eePreAuthenticatedProcessingFilter(
|
||||
J2eePreAuthenticatedProcessingFilter j2eePreAuthenticatedProcessingFilter) {
|
||||
this.j2eePreAuthenticatedProcessingFilter = j2eePreAuthenticatedProcessingFilter;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Populates a {@link PreAuthenticatedAuthenticationProvider} into
|
||||
* {@link HttpSecurity#authenticationProvider(org.springframework.security.authentication.AuthenticationProvider)}
|
||||
* and a {@link Http403ForbiddenEntryPoint} into
|
||||
* {@link HttpSecurity#authenticationEntryPoint(org.springframework.security.web.AuthenticationEntryPoint)}
|
||||
*
|
||||
* @see org.springframework.security.config.annotation.SecurityConfigurerAdapter#init(org.springframework.security.config.annotation.SecurityBuilder)
|
||||
*/
|
||||
@Override
|
||||
public void init(H http) throws Exception {
|
||||
PreAuthenticatedAuthenticationProvider authenticationProvider = new PreAuthenticatedAuthenticationProvider();
|
||||
authenticationProvider.setPreAuthenticatedUserDetailsService(getUserDetailsService());
|
||||
authenticationProvider = postProcess(authenticationProvider);
|
||||
|
||||
http
|
||||
.authenticationProvider(authenticationProvider)
|
||||
.setSharedObject(AuthenticationEntryPoint.class,new Http403ForbiddenEntryPoint());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(H http) throws Exception {
|
||||
J2eePreAuthenticatedProcessingFilter filter = getFilter(http
|
||||
.getAuthenticationManager());
|
||||
http.addFilter(filter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the {@link J2eePreAuthenticatedProcessingFilter} or creates a default instance using the properties provided.
|
||||
* @param authenticationManager the {@link AuthenticationManager} to use.
|
||||
* @return the {@link J2eePreAuthenticatedProcessingFilter} to use.
|
||||
*/
|
||||
private J2eePreAuthenticatedProcessingFilter getFilter(
|
||||
AuthenticationManager authenticationManager) {
|
||||
if (j2eePreAuthenticatedProcessingFilter == null) {
|
||||
j2eePreAuthenticatedProcessingFilter = new J2eePreAuthenticatedProcessingFilter();
|
||||
j2eePreAuthenticatedProcessingFilter
|
||||
.setAuthenticationManager(authenticationManager);
|
||||
j2eePreAuthenticatedProcessingFilter
|
||||
.setAuthenticationDetailsSource(createWebAuthenticationDetailsSource());
|
||||
j2eePreAuthenticatedProcessingFilter = postProcess(j2eePreAuthenticatedProcessingFilter);
|
||||
}
|
||||
|
||||
return j2eePreAuthenticatedProcessingFilter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the {@link AuthenticationUserDetailsService} that was specified or
|
||||
* defaults to {@link PreAuthenticatedGrantedAuthoritiesUserDetailsService}.
|
||||
*
|
||||
* @return the {@link AuthenticationUserDetailsService} to use
|
||||
*/
|
||||
private AuthenticationUserDetailsService<PreAuthenticatedAuthenticationToken> getUserDetailsService() {
|
||||
return authenticationUserDetailsService == null ? new PreAuthenticatedGrantedAuthoritiesUserDetailsService()
|
||||
: authenticationUserDetailsService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the
|
||||
* {@link J2eeBasedPreAuthenticatedWebAuthenticationDetailsSource} to set on
|
||||
* the {@link J2eePreAuthenticatedProcessingFilter}. It is populated with a
|
||||
* {@link SimpleMappableAttributesRetriever}.
|
||||
*
|
||||
* @return the
|
||||
* {@link J2eeBasedPreAuthenticatedWebAuthenticationDetailsSource}
|
||||
* to use.
|
||||
*/
|
||||
private J2eeBasedPreAuthenticatedWebAuthenticationDetailsSource createWebAuthenticationDetailsSource() {
|
||||
J2eeBasedPreAuthenticatedWebAuthenticationDetailsSource detailsSource = new J2eeBasedPreAuthenticatedWebAuthenticationDetailsSource();
|
||||
SimpleMappableAttributesRetriever rolesRetriever = new SimpleMappableAttributesRetriever();
|
||||
rolesRetriever.setMappableAttributes(mappableRoles);
|
||||
detailsSource.setMappableRolesRetriever(rolesRetriever);
|
||||
|
||||
detailsSource = postProcess(detailsSource);
|
||||
return detailsSource;
|
||||
}
|
||||
}
|
||||
+243
@@ -0,0 +1,243 @@
|
||||
/*
|
||||
* Copyright 2002-2013 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.config.annotation.web.configurers;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.servlet.http.HttpSession;
|
||||
|
||||
import org.springframework.security.config.annotation.SecurityConfigurer;
|
||||
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.web.authentication.logout.CookieClearingLogoutHandler;
|
||||
import org.springframework.security.web.authentication.logout.LogoutFilter;
|
||||
import org.springframework.security.web.authentication.logout.LogoutHandler;
|
||||
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
|
||||
import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler;
|
||||
import org.springframework.security.web.authentication.logout.SimpleUrlLogoutSuccessHandler;
|
||||
import org.springframework.security.web.authentication.ui.DefaultLoginPageViewFilter;
|
||||
|
||||
/**
|
||||
* Adds logout support. Other {@link SecurityConfigurer} instances may invoke
|
||||
* {@link #addLogoutHandler(LogoutHandler)} in the
|
||||
* {@link #init(HttpSecurity)} phase.
|
||||
*
|
||||
* <h2>Security Filters</h2>
|
||||
*
|
||||
* The following Filters are populated
|
||||
*
|
||||
* <ul>
|
||||
* <li>
|
||||
* {@link LogoutFilter}</li>
|
||||
* </ul>
|
||||
*
|
||||
* <h2>Shared Objects Created</h2>
|
||||
*
|
||||
* No shared Objects are created
|
||||
*
|
||||
* <h2>Shared Objects Used</h2>
|
||||
*
|
||||
* No shared objects are used.
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @since 3.2
|
||||
* @see RememberMeConfigurer
|
||||
*/
|
||||
public final class LogoutConfigurer<H extends HttpSecurityBuilder<H>> extends AbstractHttpConfigurer<H> {
|
||||
private List<LogoutHandler> logoutHandlers = new ArrayList<LogoutHandler>();
|
||||
private SecurityContextLogoutHandler contextLogoutHandler = new SecurityContextLogoutHandler();
|
||||
private String logoutSuccessUrl = "/login?logout";
|
||||
private LogoutSuccessHandler logoutSuccessHandler;
|
||||
private String logoutUrl = "/logout";
|
||||
private boolean permitAll;
|
||||
private boolean customLogoutSuccess;
|
||||
|
||||
/**
|
||||
* Creates a new instance
|
||||
* @see HttpSecurity#logout()
|
||||
*/
|
||||
public LogoutConfigurer() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a {@link LogoutHandler}. The {@link SecurityContextLogoutHandler} is
|
||||
* added as the last {@link LogoutHandler} by default.
|
||||
*
|
||||
* @param logoutHandler the {@link LogoutHandler} to add
|
||||
* @return the {@link LogoutConfigurer} for further customization
|
||||
*/
|
||||
public LogoutConfigurer<H> addLogoutHandler(LogoutHandler logoutHandler) {
|
||||
this.logoutHandlers.add(logoutHandler);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures {@link SecurityContextLogoutHandler} to invalidate the {@link HttpSession} at the time of logout.
|
||||
* @param invalidateHttpSession true if the {@link HttpSession} should be invalidated (default), or false otherwise.
|
||||
* @return the {@link LogoutConfigurer} for further customization
|
||||
*/
|
||||
public LogoutConfigurer<H> invalidateHttpSession(boolean invalidateHttpSession) {
|
||||
contextLogoutHandler.setInvalidateHttpSession(invalidateHttpSession);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* The URL that triggers logout to occur. The default is "/logout"
|
||||
* @param logoutUrl the URL that will invoke logout.
|
||||
* @return the {@link LogoutConfigurer} for further customization
|
||||
*/
|
||||
public LogoutConfigurer<H> logoutUrl(String logoutUrl) {
|
||||
this.logoutUrl = logoutUrl;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* The URL to redirect to after logout has occurred. The default is
|
||||
* "/login?logout". This is a shortcut for invoking
|
||||
* {@link #logoutSuccessHandler(LogoutSuccessHandler)} with a
|
||||
* {@link SimpleUrlLogoutSuccessHandler}.
|
||||
*
|
||||
* @param logoutSuccessUrl
|
||||
* the URL to redirect to after logout occurred
|
||||
* @return the {@link LogoutConfigurer} for further customization
|
||||
*/
|
||||
public LogoutConfigurer<H> logoutSuccessUrl(String logoutSuccessUrl) {
|
||||
this.customLogoutSuccess = true;
|
||||
this.logoutSuccessUrl = logoutSuccessUrl;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* A shortcut for {@link #permitAll(boolean)} with <code>true</code> as an argument.
|
||||
* @return the {@link LogoutConfigurer} for further customizations
|
||||
*/
|
||||
public LogoutConfigurer<H> permitAll() {
|
||||
return permitAll(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows specifying the names of cookies to be removed on logout success.
|
||||
* This is a shortcut to easily invoke
|
||||
* {@link #addLogoutHandler(LogoutHandler)} with a
|
||||
* {@link CookieClearingLogoutHandler}.
|
||||
*
|
||||
* @param cookieNamesToClear the names of cookies to be removed on logout success.
|
||||
* @return the {@link LogoutConfigurer} for further customization
|
||||
*/
|
||||
public LogoutConfigurer<H> deleteCookies(String... cookieNamesToClear) {
|
||||
return addLogoutHandler(new CookieClearingLogoutHandler(cookieNamesToClear));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the {@link LogoutSuccessHandler} to use. If this is specified,
|
||||
* {@link #logoutSuccessUrl(String)} is ignored.
|
||||
*
|
||||
* @param logoutSuccessHandler
|
||||
* the {@link LogoutSuccessHandler} to use after a user has been
|
||||
* logged out.
|
||||
* @return the {@link LogoutConfigurer} for further customizations
|
||||
*/
|
||||
public LogoutConfigurer<H> logoutSuccessHandler(LogoutSuccessHandler logoutSuccessHandler) {
|
||||
this.logoutSuccessUrl = null;
|
||||
this.customLogoutSuccess = true;
|
||||
this.logoutSuccessHandler = logoutSuccessHandler;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Grants access to the {@link #logoutSuccessUrl(String)} and the {@link #logoutUrl(String)} for every user.
|
||||
*
|
||||
* @param permitAll if true grants access, else nothing is done
|
||||
* @return the {@link LogoutConfigurer} for further customization.
|
||||
*/
|
||||
public LogoutConfigurer<H> permitAll(boolean permitAll) {
|
||||
this.permitAll = permitAll;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the {@link LogoutSuccessHandler} if not null, otherwise creates a
|
||||
* new {@link SimpleUrlLogoutSuccessHandler} using the
|
||||
* {@link #logoutSuccessUrl(String)}.
|
||||
*
|
||||
* @return the {@link LogoutSuccessHandler} to use
|
||||
*/
|
||||
private LogoutSuccessHandler getLogoutSuccessHandler() {
|
||||
if(logoutSuccessHandler != null) {
|
||||
return logoutSuccessHandler;
|
||||
}
|
||||
SimpleUrlLogoutSuccessHandler logoutSuccessHandler = new SimpleUrlLogoutSuccessHandler();
|
||||
logoutSuccessHandler.setDefaultTargetUrl(logoutSuccessUrl);
|
||||
return logoutSuccessHandler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(H http) throws Exception {
|
||||
if(permitAll) {
|
||||
PermitAllSupport.permitAll(http, this.logoutUrl, this.logoutSuccessUrl);
|
||||
}
|
||||
|
||||
DefaultLoginPageViewFilter loginPageGeneratingFilter = http.getSharedObject(DefaultLoginPageViewFilter.class);
|
||||
if(loginPageGeneratingFilter != null && !isCustomLogoutSuccess()) {
|
||||
loginPageGeneratingFilter.setLogoutSuccessUrl(getLogoutSuccessUrl());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(H http) throws Exception {
|
||||
LogoutFilter logoutFilter = createLogoutFilter();
|
||||
http.addFilter(logoutFilter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the logout success has been customized via
|
||||
* {@link #logoutSuccessUrl(String)} or
|
||||
* {@link #logoutSuccessHandler(LogoutSuccessHandler)}.
|
||||
*
|
||||
* @return true if logout success handling has been customized, else false
|
||||
*/
|
||||
private boolean isCustomLogoutSuccess() {
|
||||
return customLogoutSuccess;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the logoutSuccesUrl or null if a
|
||||
* {@link #logoutSuccessHandler(LogoutSuccessHandler)} was configured.
|
||||
*
|
||||
* @return the logoutSuccessUrl
|
||||
*/
|
||||
private String getLogoutSuccessUrl() {
|
||||
return logoutSuccessUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the {@link LogoutFilter} using the {@link LogoutHandler}
|
||||
* instances, the {@link #logoutSuccessHandler(LogoutSuccessHandler)} and
|
||||
* the {@link #logoutUrl(String)}.
|
||||
*
|
||||
* @return the {@link LogoutFilter} to use.
|
||||
* @throws Exception
|
||||
*/
|
||||
private LogoutFilter createLogoutFilter() throws Exception {
|
||||
logoutHandlers.add(contextLogoutHandler);
|
||||
LogoutHandler[] handlers = logoutHandlers.toArray(new LogoutHandler[logoutHandlers.size()]);
|
||||
LogoutFilter result = new LogoutFilter(getLogoutSuccessHandler(), handlers);
|
||||
result.setFilterProcessesUrl(logoutUrl);
|
||||
result = postProcess(result);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
+73
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright 2002-2013 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.config.annotation.web.configurers;
|
||||
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.springframework.security.access.SecurityConfig;
|
||||
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
|
||||
import org.springframework.security.config.annotation.web.configurers.AbstractRequestMatcherMappingConfigurer.UrlMapping;
|
||||
import org.springframework.security.web.util.RequestMatcher;
|
||||
|
||||
|
||||
/**
|
||||
* Configures non-null URL's to grant access to every URL
|
||||
* @author Rob Winch
|
||||
* @since 3.2
|
||||
*/
|
||||
final class PermitAllSupport {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static void permitAll(HttpSecurityBuilder<? extends HttpSecurityBuilder<?>> http, String... urls) {
|
||||
ExpressionUrlAuthorizationConfigurer<?> configurer = http.getConfigurer(ExpressionUrlAuthorizationConfigurer.class);
|
||||
|
||||
if(configurer == null) {
|
||||
throw new IllegalStateException("permitAll only works with HttpSecurity.authorizeUrls()");
|
||||
}
|
||||
|
||||
for(String url : urls) {
|
||||
if(url != null) {
|
||||
configurer.addMapping(0, new UrlMapping(new ExactUrlRequestMatcher(url), SecurityConfig.createList(ExpressionUrlAuthorizationConfigurer.permitAll)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private final static class ExactUrlRequestMatcher implements RequestMatcher {
|
||||
private String processUrl;
|
||||
|
||||
private ExactUrlRequestMatcher(String processUrl) {
|
||||
this.processUrl = processUrl;
|
||||
}
|
||||
|
||||
public boolean matches(HttpServletRequest request) {
|
||||
String uri = request.getRequestURI();
|
||||
String query = request.getQueryString();
|
||||
|
||||
if(query != null) {
|
||||
uri += "?" + query;
|
||||
}
|
||||
|
||||
if ("".equals(request.getContextPath())) {
|
||||
return uri.equals(processUrl);
|
||||
}
|
||||
|
||||
return uri.equals(request.getContextPath() + processUrl);
|
||||
}
|
||||
}
|
||||
|
||||
private PermitAllSupport() {}
|
||||
}
|
||||
+115
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
* Copyright 2002-2013 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.config.annotation.web.configurers;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.security.config.annotation.SecurityConfigurerAdapter;
|
||||
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.web.DefaultSecurityFilterChain;
|
||||
import org.springframework.security.web.PortMapper;
|
||||
import org.springframework.security.web.PortMapperImpl;
|
||||
|
||||
/**
|
||||
* Allows configuring a shared {@link PortMapper} instance used to determine the
|
||||
* ports when redirecting between HTTP and HTTPS. The {@link PortMapper} can be
|
||||
* obtained from {@link HttpSecurity#getSharedObject(Class)}.
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @since 3.2
|
||||
*/
|
||||
public final class PortMapperConfigurer<H extends HttpSecurityBuilder<H>> extends SecurityConfigurerAdapter<DefaultSecurityFilterChain,H> {
|
||||
private PortMapper portMapper;
|
||||
private Map<String, String> httpsPortMappings = new HashMap<String,String>();
|
||||
|
||||
/**
|
||||
* Creates a new instance
|
||||
*/
|
||||
public PortMapperConfigurer() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows specifying the {@link PortMapper} instance.
|
||||
* @param portMapper
|
||||
* @return
|
||||
*/
|
||||
public PortMapperConfigurer<H> portMapper(PortMapper portMapper) {
|
||||
this.portMapper = portMapper;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a port mapping
|
||||
* @param httpPort the HTTP port that maps to a specific HTTPS port.
|
||||
* @return {@link HttpPortMapping} to define the HTTPS port
|
||||
*/
|
||||
public HttpPortMapping http(int httpPort) {
|
||||
return new HttpPortMapping(httpPort);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(H http) throws Exception {
|
||||
http.setSharedObject(PortMapper.class, getPortMapper());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the {@link PortMapper} to use. If {@link #portMapper(PortMapper)}
|
||||
* was not invoked, builds a {@link PortMapperImpl} using the port mappings
|
||||
* specified with {@link #http(int)}.
|
||||
*
|
||||
* @return the {@link PortMapper} to use
|
||||
*/
|
||||
private PortMapper getPortMapper() {
|
||||
if(portMapper == null) {
|
||||
PortMapperImpl portMapper = new PortMapperImpl();
|
||||
portMapper.setPortMappings(httpsPortMappings);
|
||||
this.portMapper = portMapper;
|
||||
}
|
||||
return portMapper;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows specifying the HTTPS port for a given HTTP port when redirecting
|
||||
* between HTTP and HTTPS.
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @since 3.2
|
||||
*/
|
||||
public final class HttpPortMapping {
|
||||
private final int httpPort;
|
||||
|
||||
/**
|
||||
* Creates a new instance
|
||||
* @param httpPort
|
||||
* @see PortMapperConfigurer#http(int)
|
||||
*/
|
||||
private HttpPortMapping(int httpPort) {
|
||||
this.httpPort = httpPort;
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps the given HTTP port to the provided HTTPS port and vice versa.
|
||||
* @param httpsPort the HTTPS port to map to
|
||||
* @return the {@link PortMapperConfigurer} for further customization
|
||||
*/
|
||||
public PortMapperConfigurer<H> mapsTo(int httpsPort) {
|
||||
httpsPortMappings.put(String.valueOf(httpPort), String.valueOf(httpsPort));
|
||||
return PortMapperConfigurer.this;
|
||||
}
|
||||
}
|
||||
}
|
||||
+352
@@ -0,0 +1,352 @@
|
||||
/*
|
||||
* Copyright 2002-2013 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.config.annotation.web.configurers;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import org.springframework.security.authentication.RememberMeAuthenticationProvider;
|
||||
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
|
||||
import org.springframework.security.web.authentication.RememberMeServices;
|
||||
import org.springframework.security.web.authentication.logout.LogoutHandler;
|
||||
import org.springframework.security.web.authentication.rememberme.AbstractRememberMeServices;
|
||||
import org.springframework.security.web.authentication.rememberme.PersistentTokenBasedRememberMeServices;
|
||||
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;
|
||||
import org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationFilter;
|
||||
import org.springframework.security.web.authentication.rememberme.TokenBasedRememberMeServices;
|
||||
import org.springframework.security.web.authentication.ui.DefaultLoginPageViewFilter;
|
||||
|
||||
/**
|
||||
* Configures Remember Me authentication. This typically involves the user
|
||||
* checking a box when they enter their username and password that states to
|
||||
* "Remember Me".
|
||||
*
|
||||
* <h2>Security Filters</h2>
|
||||
*
|
||||
* The following Filters are populated
|
||||
*
|
||||
* <ul>
|
||||
* <li>
|
||||
* {@link RememberMeAuthenticationFilter}</li>
|
||||
* </ul>
|
||||
*
|
||||
* <h2>Shared Objects Created</h2>
|
||||
*
|
||||
* The following shared objects are populated
|
||||
*
|
||||
* <ul>
|
||||
* <li>
|
||||
* {@link HttpSecurity#authenticationProvider(org.springframework.security.authentication.AuthenticationProvider)}
|
||||
* is populated with a {@link RememberMeAuthenticationProvider}</li>
|
||||
* <li>{@link RememberMeServices} is populated as a shared object and available on {@link HttpSecurity#getSharedObject(Class)}</li>
|
||||
* <li>{@link LogoutConfigurer#addLogoutHandler(LogoutHandler)} is used to add a logout handler to clean up the remember me authentication.</li>
|
||||
* </ul>
|
||||
*
|
||||
* <h2>Shared Objects Used</h2>
|
||||
*
|
||||
* The following shared objects are used:
|
||||
*
|
||||
* <ul>
|
||||
* <li>{@link HttpSecurity#getAuthenticationManager()}</li>
|
||||
* <li>{@link UserDetailsService} if no {@link #userDetailsService(UserDetailsService)} was specified.</li>
|
||||
* <li> {@link DefaultLoginPageViewFilter} - if present will be populated with information from the configuration</li>
|
||||
* </ul>
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @since 3.2
|
||||
*/
|
||||
public final class RememberMeConfigurer<H extends HttpSecurityBuilder<H>> extends AbstractHttpConfigurer<H> {
|
||||
private AuthenticationSuccessHandler authenticationSuccessHandler;
|
||||
private String key;
|
||||
private RememberMeServices rememberMeServices;
|
||||
private LogoutHandler logoutHandler;
|
||||
private String rememberMeParameter = "remember-me";
|
||||
private String rememberMeCookieName = "remember-me";
|
||||
private PersistentTokenRepository tokenRepository;
|
||||
private UserDetailsService userDetailsService;
|
||||
private Integer tokenValiditySeconds;
|
||||
private Boolean useSecureCookie;
|
||||
|
||||
/**
|
||||
* Creates a new instance
|
||||
*/
|
||||
public RememberMeConfigurer() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows specifying how long (in seconds) a token is valid for
|
||||
*
|
||||
* @param tokenValiditySeconds
|
||||
* @return {@link RememberMeConfigurer} for further customization
|
||||
* @see AbstractRememberMeServices#setTokenValiditySeconds(int)
|
||||
*/
|
||||
public RememberMeConfigurer<H> tokenValiditySeconds(int tokenValiditySeconds) {
|
||||
this.tokenValiditySeconds = tokenValiditySeconds;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
*Whether the cookie should be flagged as secure or not. Secure cookies can only be sent over an HTTPS connection
|
||||
* and thus cannot be accidentally submitted over HTTP where they could be intercepted.
|
||||
* <p>
|
||||
* By default the cookie will be secure if the request is secure. If you only want to use remember-me over
|
||||
* HTTPS (recommended) you should set this property to {@code true}.
|
||||
*
|
||||
* @param useSecureCookie set to {@code true} to always user secure cookies, {@code false} to disable their use.
|
||||
* @return the {@link RememberMeConfigurer} for further customization
|
||||
* @see AbstractRememberMeServices#setUseSecureCookie(boolean)
|
||||
*/
|
||||
public RememberMeConfigurer<H> useSecureCookie(boolean useSecureCookie) {
|
||||
this.useSecureCookie = useSecureCookie;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies the {@link UserDetailsService} used to look up the
|
||||
* {@link UserDetails} when a remember me token is valid. The default is to
|
||||
* use the {@link UserDetailsService} found by invoking
|
||||
* {@link HttpSecurity#getSharedObject(Class)} which is set when using
|
||||
* {@link WebSecurityConfigurerAdapter#registerAuthentication(org.springframework.security.config.annotation.authentication.AuthenticationManagerBuilder)}.
|
||||
* Alternatively, one can populate {@link #rememberMeServices(RememberMeServices)}.
|
||||
*
|
||||
* @param userDetailsService
|
||||
* the {@link UserDetailsService} to configure
|
||||
* @return the {@link RememberMeConfigurer} for further customization
|
||||
* @see AbstractRememberMeServices
|
||||
*/
|
||||
public RememberMeConfigurer<H> userDetailsService(UserDetailsService userDetailsService) {
|
||||
this.userDetailsService = userDetailsService;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies the {@link PersistentTokenRepository} to use. The default is to
|
||||
* use {@link TokenBasedRememberMeServices} instead.
|
||||
*
|
||||
* @param tokenRepository
|
||||
* the {@link PersistentTokenRepository} to use
|
||||
* @return the {@link RememberMeConfigurer} for further customization
|
||||
*/
|
||||
public RememberMeConfigurer<H> tokenRepository(PersistentTokenRepository tokenRepository) {
|
||||
this.tokenRepository = tokenRepository;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the key to identify tokens created for remember me authentication. Default is a secure randomly generated
|
||||
* key.
|
||||
*
|
||||
* @param key the key to identify tokens created for remember me authentication
|
||||
* @return the {@link RememberMeConfigurer} for further customization
|
||||
*/
|
||||
public RememberMeConfigurer<H> key(String key) {
|
||||
this.key = key;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows control over the destination a remembered user is sent to when they are successfully authenticated.
|
||||
* By default, the filter will just allow the current request to proceed, but if an
|
||||
* {@code AuthenticationSuccessHandler} is set, it will be invoked and the {@code doFilter()} method will return
|
||||
* immediately, thus allowing the application to redirect the user to a specific URL, regardless of what the original
|
||||
* request was for.
|
||||
*
|
||||
* @param authenticationSuccessHandler the strategy to invoke immediately before returning from {@code doFilter()}.
|
||||
* @return {@link RememberMeConfigurer} for further customization
|
||||
* @see RememberMeAuthenticationFilter#setAuthenticationSuccessHandler(AuthenticationSuccessHandler)
|
||||
*/
|
||||
public RememberMeConfigurer<H> authenticationSuccessHandler(AuthenticationSuccessHandler authenticationSuccessHandler) {
|
||||
this.authenticationSuccessHandler = authenticationSuccessHandler;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify the {@link RememberMeServices} to use.
|
||||
* @param rememberMeServices the {@link RememberMeServices} to use
|
||||
* @return the {@link RememberMeConfigurer} for further customizations
|
||||
* @see RememberMeServices
|
||||
*/
|
||||
public RememberMeConfigurer<H> rememberMeServices(RememberMeServices rememberMeServices) {
|
||||
this.rememberMeServices = rememberMeServices;
|
||||
return this;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public void init(H http) throws Exception {
|
||||
String key = getKey();
|
||||
RememberMeServices rememberMeServices = getRememberMeServices(http, key);
|
||||
http.setSharedObject(RememberMeServices.class, rememberMeServices);
|
||||
LogoutConfigurer<H> logoutConfigurer = http.getConfigurer(LogoutConfigurer.class);
|
||||
if(logoutConfigurer != null) {
|
||||
logoutConfigurer.addLogoutHandler(logoutHandler);
|
||||
}
|
||||
|
||||
RememberMeAuthenticationProvider authenticationProvider = new RememberMeAuthenticationProvider(
|
||||
key);
|
||||
authenticationProvider = postProcess(authenticationProvider);
|
||||
http.authenticationProvider(authenticationProvider);
|
||||
|
||||
initDefaultLoginFilter(http);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(H http) throws Exception {
|
||||
RememberMeAuthenticationFilter rememberMeFilter = new RememberMeAuthenticationFilter(
|
||||
http.getAuthenticationManager(), rememberMeServices);
|
||||
if (authenticationSuccessHandler != null) {
|
||||
rememberMeFilter
|
||||
.setAuthenticationSuccessHandler(authenticationSuccessHandler);
|
||||
}
|
||||
rememberMeFilter = postProcess(rememberMeFilter);
|
||||
http.addFilter(rememberMeFilter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the HTTP parameter used to indicate to remember the user at time of login.
|
||||
* @return the HTTP parameter used to indicate to remember the user
|
||||
*/
|
||||
private String getRememberMeParameter() {
|
||||
return rememberMeParameter;
|
||||
}
|
||||
|
||||
/**
|
||||
* If available, initializes the {@link DefaultLoginPageViewFilter} shared object.
|
||||
*
|
||||
* @param http the {@link HttpSecurityBuilder} to use
|
||||
*/
|
||||
private void initDefaultLoginFilter(H http) {
|
||||
DefaultLoginPageViewFilter loginPageGeneratingFilter = http.getSharedObject(DefaultLoginPageViewFilter.class);
|
||||
if(loginPageGeneratingFilter != null) {
|
||||
loginPageGeneratingFilter.setRememberMeParameter(getRememberMeParameter());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the {@link RememberMeServices} or creates the {@link RememberMeServices}.
|
||||
* @param http the {@link HttpSecurity} to lookup shared objects
|
||||
* @param key the {@link #key(String)}
|
||||
* @return the {@link RememberMeServices} to use
|
||||
* @throws Exception
|
||||
*/
|
||||
private RememberMeServices getRememberMeServices(H http,
|
||||
String key) throws Exception {
|
||||
if (rememberMeServices != null) {
|
||||
if (rememberMeServices instanceof LogoutHandler
|
||||
&& logoutHandler == null) {
|
||||
this.logoutHandler = (LogoutHandler) rememberMeServices;
|
||||
}
|
||||
return rememberMeServices;
|
||||
}
|
||||
AbstractRememberMeServices tokenRememberMeServices = createRememberMeServices(
|
||||
http, key);
|
||||
tokenRememberMeServices.setParameter(rememberMeParameter);
|
||||
tokenRememberMeServices.setCookieName(rememberMeCookieName);
|
||||
if (tokenValiditySeconds != null) {
|
||||
tokenRememberMeServices
|
||||
.setTokenValiditySeconds(tokenValiditySeconds);
|
||||
}
|
||||
if (useSecureCookie != null) {
|
||||
tokenRememberMeServices.setUseSecureCookie(useSecureCookie);
|
||||
}
|
||||
tokenRememberMeServices.afterPropertiesSet();
|
||||
logoutHandler = tokenRememberMeServices;
|
||||
rememberMeServices = tokenRememberMeServices;
|
||||
return tokenRememberMeServices;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the {@link RememberMeServices} to use when none is provided. The
|
||||
* result is either {@link PersistentTokenRepository} (if a
|
||||
* {@link PersistentTokenRepository} is specified, else
|
||||
* {@link TokenBasedRememberMeServices}.
|
||||
*
|
||||
* @param http the {@link HttpSecurity} to lookup shared objects
|
||||
* @param key the {@link #key(String)}
|
||||
* @return the {@link RememberMeServices} to use
|
||||
* @throws Exception
|
||||
*/
|
||||
private AbstractRememberMeServices createRememberMeServices(
|
||||
H http, String key) throws Exception {
|
||||
return tokenRepository == null ? createTokenBasedRememberMeServices(
|
||||
http, key) : createPersistentRememberMeServices(http, key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates {@link TokenBasedRememberMeServices}
|
||||
*
|
||||
* @param http the {@link HttpSecurity} to lookup shared objects
|
||||
* @param key the {@link #key(String)}
|
||||
* @return the {@link TokenBasedRememberMeServices}
|
||||
*/
|
||||
private AbstractRememberMeServices createTokenBasedRememberMeServices(
|
||||
H http, String key) {
|
||||
UserDetailsService userDetailsService = getUserDetailsService(http);
|
||||
return new TokenBasedRememberMeServices(key, userDetailsService);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates {@link PersistentTokenBasedRememberMeServices}
|
||||
*
|
||||
* @param http the {@link HttpSecurity} to lookup shared objects
|
||||
* @param key the {@link #key(String)}
|
||||
* @return the {@link PersistentTokenBasedRememberMeServices}
|
||||
*/
|
||||
private AbstractRememberMeServices createPersistentRememberMeServices(
|
||||
H http, String key) {
|
||||
UserDetailsService userDetailsService = getUserDetailsService(http);
|
||||
return new PersistentTokenBasedRememberMeServices(key,
|
||||
userDetailsService, tokenRepository);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the {@link UserDetailsService} to use. Either the explicitly
|
||||
* configure {@link UserDetailsService} from
|
||||
* {@link #userDetailsService(UserDetailsService)} or a shared object from
|
||||
* {@link HttpSecurity#getSharedObject(Class)}.
|
||||
*
|
||||
* @param http {@link HttpSecurity} to get the shared {@link UserDetailsService}
|
||||
* @return the {@link UserDetailsService} to use
|
||||
*/
|
||||
private UserDetailsService getUserDetailsService(H http) {
|
||||
if(userDetailsService == null) {
|
||||
userDetailsService = http.getSharedObject(UserDetailsService.class);
|
||||
}
|
||||
if(userDetailsService == null) {
|
||||
throw new IllegalStateException("userDetailsService cannot be null. Invoke "
|
||||
+ RememberMeConfigurer.class.getSimpleName() + "#userDetailsService(UserDetailsService) or see its javadoc for alternative approaches.");
|
||||
}
|
||||
return userDetailsService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the key to use for validating remember me tokens. Either the value
|
||||
* passed into {@link #key(String)}, or a secure random string if none was
|
||||
* specified.
|
||||
*
|
||||
* @return the remember me key to use
|
||||
*/
|
||||
private String getKey() {
|
||||
if (key == null) {
|
||||
key = UUID.randomUUID().toString();
|
||||
}
|
||||
return key;
|
||||
}
|
||||
}
|
||||
+98
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Copyright 2002-2013 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.config.annotation.web.configurers;
|
||||
|
||||
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.web.savedrequest.HttpSessionRequestCache;
|
||||
import org.springframework.security.web.savedrequest.RequestCache;
|
||||
import org.springframework.security.web.savedrequest.RequestCacheAwareFilter;
|
||||
|
||||
/**
|
||||
* Adds request cache for Spring Security. Specifically this ensures that
|
||||
* requests that are saved (i.e. after authentication is required) are later
|
||||
* replayed. All properties have reasonable defaults, so no additional
|
||||
* configuration is required other than applying this
|
||||
* {@link org.springframework.security.config.annotation.SecurityConfigurer}.
|
||||
*
|
||||
* <h2>Security Filters</h2>
|
||||
*
|
||||
* The following Filters are populated
|
||||
*
|
||||
* <ul>
|
||||
* <li>{@link RequestCacheAwareFilter}</li>
|
||||
* </ul>
|
||||
*
|
||||
* <h2>Shared Objects Created</h2>
|
||||
*
|
||||
* No shared objects are created.
|
||||
*
|
||||
* <h2>Shared Objects Used</h2>
|
||||
*
|
||||
* The following shared objects are used:
|
||||
*
|
||||
* <ul>
|
||||
* <li>If no explicit {@link RequestCache}, is provided a {@link RequestCache}
|
||||
* shared object is used to replay the request after authentication is
|
||||
* successful</li>
|
||||
* </ul>
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @since 3.2
|
||||
* @see RequestCache
|
||||
*/
|
||||
public final class RequestCacheConfigurer<H extends HttpSecurityBuilder<H>> extends AbstractHttpConfigurer<H> {
|
||||
|
||||
public RequestCacheConfigurer() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows explicit configuration of the {@link RequestCache} to be used. Defaults to try finding a
|
||||
* {@link RequestCache} as a shared object. Then falls back to a {@link HttpSessionRequestCache}.
|
||||
*
|
||||
* @param requestCache the explicit {@link RequestCache} to use
|
||||
* @return the {@link RequestCacheConfigurer} for further customization
|
||||
*/
|
||||
public RequestCacheConfigurer<H> requestCache(RequestCache requestCache) {
|
||||
getBuilder().setSharedObject(RequestCache.class, requestCache);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(H http) throws Exception {
|
||||
RequestCache requestCache = getRequestCache(http);
|
||||
RequestCacheAwareFilter requestCacheFilter = new RequestCacheAwareFilter(requestCache);
|
||||
requestCacheFilter = postProcess(requestCacheFilter);
|
||||
http.addFilter(requestCacheFilter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the {@link RequestCache} to use. If one is defined using
|
||||
* {@link #requestCache(org.springframework.security.web.savedrequest.RequestCache)}, then it is used. Otherwise, an
|
||||
* attempt to find a {@link RequestCache} shared object is made. If that fails, an {@link HttpSessionRequestCache}
|
||||
* is used
|
||||
*
|
||||
* @param http the {@link HttpSecurity} to attempt to fined the shared object
|
||||
* @return the {@link RequestCache} to use
|
||||
*/
|
||||
private RequestCache getRequestCache(H http) {
|
||||
RequestCache result = http.getSharedObject(RequestCache.class);
|
||||
if(result != null) {
|
||||
return result;
|
||||
}
|
||||
return new HttpSessionRequestCache();
|
||||
}
|
||||
}
|
||||
+95
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* Copyright 2002-2013 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.config.annotation.web.configurers;
|
||||
|
||||
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.core.context.SecurityContext;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.web.context.SecurityContextPersistenceFilter;
|
||||
import org.springframework.security.web.context.SecurityContextRepository;
|
||||
|
||||
/**
|
||||
* Allows persisting and restoring of the {@link SecurityContext} found on the
|
||||
* {@link SecurityContextHolder} for each request by configuring the
|
||||
* {@link SecurityContextPersistenceFilter}. All properties have reasonable
|
||||
* defaults, so no additional configuration is required other than applying this
|
||||
* {@link org.springframework.security.config.annotation.SecurityConfigurer}.
|
||||
*
|
||||
* <h2>Security Filters</h2>
|
||||
*
|
||||
* The following Filters are populated
|
||||
*
|
||||
* <ul>
|
||||
* <li>{@link SecurityContextPersistenceFilter}</li>
|
||||
* </ul>
|
||||
*
|
||||
* <h2>Shared Objects Created</h2>
|
||||
*
|
||||
* No shared objects are created.
|
||||
*
|
||||
* <h2>Shared Objects Used</h2>
|
||||
*
|
||||
* The following shared objects are used:
|
||||
*
|
||||
* <ul>
|
||||
* <li>If {@link SessionManagementConfigurer}, is provided and set to always,
|
||||
* then the
|
||||
* {@link SecurityContextPersistenceFilter#setForceEagerSessionCreation(boolean)}
|
||||
* will be set to true.</li>
|
||||
* <li>{@link SecurityContextRepository} must be set and is used on
|
||||
* {@link SecurityContextPersistenceFilter}.</li>
|
||||
* </ul>
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @since 3.2
|
||||
*/
|
||||
public final class SecurityContextConfigurer<H extends HttpSecurityBuilder<H>> extends AbstractHttpConfigurer<H> {
|
||||
|
||||
/**
|
||||
* Creates a new instance
|
||||
* @see HttpSecurity#securityContext()
|
||||
*/
|
||||
public SecurityContextConfigurer() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies the shared {@link SecurityContextRepository} that is to be used
|
||||
* @param securityContextRepository the {@link SecurityContextRepository} to use
|
||||
* @return the {@link HttpSecurity} for further customizations
|
||||
*/
|
||||
public SecurityContextConfigurer<H> securityContextRepository(SecurityContextRepository securityContextRepository) {
|
||||
getBuilder().setSharedObject(SecurityContextRepository.class, securityContextRepository);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public void configure(H http) throws Exception {
|
||||
|
||||
SecurityContextRepository securityContextRepository = http.getSharedObject(SecurityContextRepository.class);
|
||||
SecurityContextPersistenceFilter securityContextFilter = new SecurityContextPersistenceFilter(
|
||||
securityContextRepository);
|
||||
SessionManagementConfigurer<?> sessionManagement = http.getConfigurer(SessionManagementConfigurer.class);
|
||||
SessionCreationPolicy sessionCreationPolicy = sessionManagement == null ? null
|
||||
: sessionManagement.getSessionCreationPolicy();
|
||||
if (SessionCreationPolicy.always == sessionCreationPolicy) {
|
||||
securityContextFilter.setForceEagerSessionCreation(true);
|
||||
}
|
||||
securityContextFilter = postProcess(securityContextFilter);
|
||||
http.addFilter(securityContextFilter);
|
||||
}
|
||||
}
|
||||
+75
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright 2002-2013 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.config.annotation.web.configurers;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.core.context.SecurityContext;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter;
|
||||
|
||||
/**
|
||||
* Implements select methods from the {@link HttpServletRequest} using the {@link SecurityContext} from the {@link SecurityContextHolder}.
|
||||
*
|
||||
* <h2>Security Filters</h2>
|
||||
*
|
||||
* The following Filters are populated
|
||||
*
|
||||
* <ul>
|
||||
* <li>{@link SecurityContextHolderAwareRequestFilter}</li>
|
||||
* </ul>
|
||||
*
|
||||
* <h2>Shared Objects Created</h2>
|
||||
*
|
||||
* No shared objects are created.
|
||||
*
|
||||
* <h2>Shared Objects Used</h2>
|
||||
*
|
||||
* No shared Objects are used.
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @since 3.2
|
||||
*/
|
||||
public final class ServletApiConfigurer<H extends HttpSecurityBuilder<H>> extends AbstractHttpConfigurer<H> {
|
||||
private SecurityContextHolderAwareRequestFilter securityContextRequestFilter = new SecurityContextHolderAwareRequestFilter();
|
||||
|
||||
/**
|
||||
* Creates a new instance
|
||||
* @see HttpSecurity#servletApi()
|
||||
*/
|
||||
public ServletApiConfigurer() {
|
||||
}
|
||||
|
||||
public ServletApiConfigurer<H> rolePrefix(String rolePrefix) {
|
||||
securityContextRequestFilter.setRolePrefix(rolePrefix);
|
||||
return this;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public H disable() {
|
||||
getBuilder().removeConfigurer(getClass());
|
||||
return getBuilder();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(H builder)
|
||||
throws Exception {
|
||||
securityContextRequestFilter = postProcess(securityContextRequestFilter);
|
||||
builder.addFilter(securityContextRequestFilter);
|
||||
}
|
||||
}
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright 2002-2013 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.config.annotation.web.configurers;
|
||||
|
||||
import javax.servlet.http.HttpSession;
|
||||
|
||||
import org.springframework.security.core.context.SecurityContext;
|
||||
|
||||
/**
|
||||
* Specifies the various session creation policies for Spring Security.
|
||||
*
|
||||
* FIXME this should be removed once {@link org.springframework.security.config.http.SessionCreationPolicy} is made public.
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @since 3.2
|
||||
*/
|
||||
public enum SessionCreationPolicy {
|
||||
/** Always create an {@link HttpSession} */
|
||||
always,
|
||||
/** Spring Security will never create an {@link HttpSession}, but will use the {@link HttpSession} if it already exists */
|
||||
never,
|
||||
/** Spring Security will only create an {@link HttpSession} if required */
|
||||
ifRequired,
|
||||
/** Spring Security will never create an {@link HttpSession} and it will never use it to obtain the {@link SecurityContext} */
|
||||
stateless
|
||||
}
|
||||
+331
@@ -0,0 +1,331 @@
|
||||
/*
|
||||
* Copyright 2002-2013 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.config.annotation.web.configurers;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.core.session.SessionRegistry;
|
||||
import org.springframework.security.core.session.SessionRegistryImpl;
|
||||
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;
|
||||
import org.springframework.security.web.authentication.session.ConcurrentSessionControlStrategy;
|
||||
import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy;
|
||||
import org.springframework.security.web.authentication.session.SessionFixationProtectionStrategy;
|
||||
import org.springframework.security.web.context.HttpSessionSecurityContextRepository;
|
||||
import org.springframework.security.web.context.NullSecurityContextRepository;
|
||||
import org.springframework.security.web.context.SecurityContextRepository;
|
||||
import org.springframework.security.web.savedrequest.NullRequestCache;
|
||||
import org.springframework.security.web.savedrequest.RequestCache;
|
||||
import org.springframework.security.web.session.ConcurrentSessionFilter;
|
||||
import org.springframework.security.web.session.SessionManagementFilter;
|
||||
import org.springframework.security.web.session.SimpleRedirectInvalidSessionStrategy;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Allows configuring session management.
|
||||
*
|
||||
* <h2>Security Filters</h2>
|
||||
*
|
||||
* The following Filters are populated
|
||||
*
|
||||
* <ul>
|
||||
* <li>{@link SessionManagementFilter}</li>
|
||||
* <li>{@link ConcurrentSessionFilter} if there are restrictions on how many concurrent sessions a user can have</li>
|
||||
* </ul>
|
||||
*
|
||||
* <h2>Shared Objects Created</h2>
|
||||
*
|
||||
* The following shared objects are created:
|
||||
*
|
||||
* <ul>
|
||||
* <li>{@link RequestCache}</li>
|
||||
* <li>{@link SecurityContextRepository}</li>
|
||||
* <li>{@link SessionManagementConfigurer}</li>
|
||||
* </ul>
|
||||
*
|
||||
* <h2>Shared Objects Used</h2>
|
||||
*
|
||||
* <ul>
|
||||
* <li>{@link SecurityContextRepository}</li>
|
||||
* </ul>
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @since 3.2
|
||||
* @see SessionManagementFilter
|
||||
* @see ConcurrentSessionFilter
|
||||
*/
|
||||
public final class SessionManagementConfigurer<H extends HttpSecurityBuilder<H>> extends AbstractHttpConfigurer<H> {
|
||||
private SessionAuthenticationStrategy sessionAuthenticationStrategy = new SessionFixationProtectionStrategy();
|
||||
private SessionRegistry sessionRegistry = new SessionRegistryImpl();
|
||||
private Integer maximumSessions;
|
||||
private String expiredUrl;
|
||||
private boolean maxSessionsPreventsLogin;
|
||||
private SessionCreationPolicy sessionPolicy = SessionCreationPolicy.ifRequired;
|
||||
private boolean enableSessionUrlRewriting;
|
||||
private String invalidSessionUrl;
|
||||
private String sessionAuthenticationErrorUrl;
|
||||
|
||||
/**
|
||||
* Creates a new instance
|
||||
* @see HttpSecurity#sessionManagement()
|
||||
*/
|
||||
public SessionManagementConfigurer() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Setting this attribute will inject the {@link SessionManagementFilter} with a
|
||||
* {@link SimpleRedirectInvalidSessionStrategy} configured with the attribute value.
|
||||
* When an invalid session ID is submitted, the strategy will be invoked,
|
||||
* redirecting to the configured URL.
|
||||
*
|
||||
* @param invalidSessionUrl the URL to redirect to when an invalid session is detected
|
||||
* @return the {@link SessionManagementConfigurer} for further customization
|
||||
*/
|
||||
public SessionManagementConfigurer<H> invalidSessionUrl(String invalidSessionUrl) {
|
||||
this.invalidSessionUrl = invalidSessionUrl;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines the URL of the error page which should be shown when the
|
||||
* SessionAuthenticationStrategy raises an exception. If not set, an
|
||||
* unauthorized (402) error code will be returned to the client. Note that
|
||||
* this attribute doesn't apply if the error occurs during a form-based
|
||||
* login, where the URL for authentication failure will take precedence.
|
||||
*
|
||||
* @param sessionAuthenticationErrorUrl
|
||||
* the URL to redirect to
|
||||
* @return the {@link SessionManagementConfigurer} for further customization
|
||||
*/
|
||||
public SessionManagementConfigurer<H> sessionAuthenticationErrorUrl(String sessionAuthenticationErrorUrl) {
|
||||
this.sessionAuthenticationErrorUrl = sessionAuthenticationErrorUrl;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* If set to true, allows HTTP sessions to be rewritten in the URLs when
|
||||
* using {@link HttpServletResponse#encodeRedirectURL(String)} or
|
||||
* {@link HttpServletResponse#encodeURL(String)}, otherwise disallows HTTP
|
||||
* sessions to be included in the URL. This prevents leaking information to
|
||||
* external domains.
|
||||
*
|
||||
* @param enableSessionUrlRewriting true if should allow the JSESSIONID to be rewritten into the URLs, else false (default)
|
||||
* @return the {@link SessionManagementConfigurer} for further customization
|
||||
* @see HttpSessionSecurityContextRepository#setDisableUrlRewriting(boolean)
|
||||
*/
|
||||
public SessionManagementConfigurer<H> enableSessionUrlRewriting(boolean enableSessionUrlRewriting) {
|
||||
this.enableSessionUrlRewriting = enableSessionUrlRewriting;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows specifying the {@link SessionCreationPolicy}
|
||||
* @param sessionCreationPolicy the {@link SessionCreationPolicy} to use. Cannot be null.
|
||||
* @return the {@link SessionManagementConfigurer} for further customizations
|
||||
* @see SessionCreationPolicy
|
||||
* @throws IllegalArgumentException if {@link SessionCreationPolicy} is null.
|
||||
*/
|
||||
public SessionManagementConfigurer<H> sessionCreationPolicy(SessionCreationPolicy sessionCreationPolicy) {
|
||||
Assert.notNull(sessionCreationPolicy, "sessionCreationPolicy cannot be null");
|
||||
this.sessionPolicy = sessionCreationPolicy;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows explicitly specifying the {@link SessionAuthenticationStrategy}.
|
||||
* The default is to use {@link SessionFixationProtectionStrategy}. If
|
||||
* restricting the maximum number of sessions is configured,
|
||||
* {@link ConcurrentSessionControlStrategy} will be used.
|
||||
*
|
||||
* @param sessionAuthenticationStrategy
|
||||
* @return the {@link SessionManagementConfigurer} for further customizations
|
||||
*/
|
||||
public SessionManagementConfigurer<H> sessionAuthenticationStrategy(SessionAuthenticationStrategy sessionAuthenticationStrategy) {
|
||||
this.sessionAuthenticationStrategy = sessionAuthenticationStrategy;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Controls the maximum number of sessions for a user. The default is to allow any number of users.
|
||||
* @param maximumSessions the maximum number of sessions for a user
|
||||
* @return the {@link SessionManagementConfigurer} for further customizations
|
||||
*/
|
||||
public ConcurrencyControlConfigurer maximumSessions(int maximumSessions) {
|
||||
this.maximumSessions = maximumSessions;
|
||||
this.sessionAuthenticationStrategy = null;
|
||||
return new ConcurrencyControlConfigurer();
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows configuring controlling of multiple sessions.
|
||||
*
|
||||
* @author Rob Winch
|
||||
*/
|
||||
public final class ConcurrencyControlConfigurer {
|
||||
|
||||
/**
|
||||
* The URL to redirect to if a user tries to access a resource and their
|
||||
* session has been expired due to too many sessions for the current user.
|
||||
* The default is to write a simple error message to the response.
|
||||
*
|
||||
* @param expiredUrl the URL to redirect to
|
||||
* @return the {@link ConcurrencyControlConfigurer} for further customizations
|
||||
*/
|
||||
public ConcurrencyControlConfigurer expiredUrl(String expiredUrl) {
|
||||
SessionManagementConfigurer.this.expiredUrl = expiredUrl;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* If true, prevents a user from authenticating when the
|
||||
* {@link #maximumSessions(int)} has been reached. Otherwise (default), the user who
|
||||
* authenticates is allowed access and an existing user's session is
|
||||
* expired. The user's who's session is forcibly expired is sent to
|
||||
* {@link #expiredUrl(String)}. The advantage of this approach is if a user
|
||||
* accidentally does not log out, there is no need for an administrator to
|
||||
* intervene or wait till their session expires.
|
||||
*
|
||||
* @param maxSessionsPreventsLogin true to have an error at time of authentication, else false (default)
|
||||
* @return the {@link ConcurrencyControlConfigurer} for further customizations
|
||||
*/
|
||||
public ConcurrencyControlConfigurer maxSessionsPreventsLogin(boolean maxSessionsPreventsLogin) {
|
||||
SessionManagementConfigurer.this.maxSessionsPreventsLogin = maxSessionsPreventsLogin;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Controls the {@link SessionRegistry} implementation used. The default
|
||||
* is {@link SessionRegistryImpl} which is an in memory implementation.
|
||||
*
|
||||
* @param sessionRegistry the {@link SessionRegistry} to use
|
||||
* @return the {@link ConcurrencyControlConfigurer} for further customizations
|
||||
*/
|
||||
public ConcurrencyControlConfigurer sessionRegistry(SessionRegistry sessionRegistry) {
|
||||
SessionManagementConfigurer.this.sessionRegistry = sessionRegistry;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to chain back to the {@link SessionManagementConfigurer}
|
||||
*
|
||||
* @return the {@link SessionManagementConfigurer} for further customizations
|
||||
*/
|
||||
public SessionManagementConfigurer<H> and() {
|
||||
return SessionManagementConfigurer.this;
|
||||
}
|
||||
|
||||
private ConcurrencyControlConfigurer() {}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(H builder) throws Exception {
|
||||
SecurityContextRepository securityContextRepository = builder.getSharedObject(SecurityContextRepository.class);
|
||||
boolean stateless = isStateless();
|
||||
|
||||
if(securityContextRepository == null) {
|
||||
if(stateless) {
|
||||
builder.setSharedObject(SecurityContextRepository.class, new NullSecurityContextRepository());
|
||||
} else {
|
||||
HttpSessionSecurityContextRepository httpSecurityRepository = new HttpSessionSecurityContextRepository();
|
||||
httpSecurityRepository.setDisableUrlRewriting(!enableSessionUrlRewriting);
|
||||
httpSecurityRepository.setAllowSessionCreation(isAllowSessionCreation());
|
||||
builder.setSharedObject(SecurityContextRepository.class, httpSecurityRepository);
|
||||
}
|
||||
}
|
||||
|
||||
RequestCache requestCache = builder.getSharedObject(RequestCache.class);
|
||||
if(requestCache == null) {
|
||||
if(stateless) {
|
||||
builder.setSharedObject(RequestCache.class, new NullRequestCache());
|
||||
}
|
||||
}
|
||||
builder.setSharedObject(SessionAuthenticationStrategy.class, getSessionAuthenticationStrategy());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(H http) throws Exception {
|
||||
SecurityContextRepository securityContextRepository = http.getSharedObject(SecurityContextRepository.class);
|
||||
SessionManagementFilter sessionManagementFilter = new SessionManagementFilter(securityContextRepository, getSessionAuthenticationStrategy());
|
||||
if(sessionAuthenticationErrorUrl != null) {
|
||||
sessionManagementFilter.setAuthenticationFailureHandler(new SimpleUrlAuthenticationFailureHandler(sessionAuthenticationErrorUrl));
|
||||
}
|
||||
if(invalidSessionUrl != null) {
|
||||
sessionManagementFilter.setInvalidSessionStrategy(new SimpleRedirectInvalidSessionStrategy(invalidSessionUrl));
|
||||
}
|
||||
sessionManagementFilter = postProcess(sessionManagementFilter);
|
||||
|
||||
http.addFilter(sessionManagementFilter);
|
||||
if(isConcurrentSessionControlEnabled()) {
|
||||
ConcurrentSessionFilter concurrentSessionFilter = new ConcurrentSessionFilter(sessionRegistry, expiredUrl);
|
||||
concurrentSessionFilter = postProcess(concurrentSessionFilter);
|
||||
http.addFilter(concurrentSessionFilter);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the {@link SessionCreationPolicy}. Can not be null.
|
||||
* @return the {@link SessionCreationPolicy}
|
||||
*/
|
||||
SessionCreationPolicy getSessionCreationPolicy() {
|
||||
return sessionPolicy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the {@link SessionCreationPolicy} allows session creation, else false
|
||||
* @return true if the {@link SessionCreationPolicy} allows session creation
|
||||
*/
|
||||
private boolean isAllowSessionCreation() {
|
||||
return SessionCreationPolicy.always == sessionPolicy || SessionCreationPolicy.ifRequired == sessionPolicy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the {@link SessionCreationPolicy} is stateless
|
||||
* @return
|
||||
*/
|
||||
private boolean isStateless() {
|
||||
return SessionCreationPolicy.stateless == sessionPolicy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the customized {@link SessionAuthenticationStrategy} if
|
||||
* {@link #sessionAuthenticationStrategy(SessionAuthenticationStrategy)} was
|
||||
* specified. Otherwise creates a default
|
||||
* {@link SessionAuthenticationStrategy}.
|
||||
*
|
||||
* @return the {@link SessionAuthenticationStrategy} to use
|
||||
*/
|
||||
private SessionAuthenticationStrategy getSessionAuthenticationStrategy() {
|
||||
if(sessionAuthenticationStrategy != null) {
|
||||
return sessionAuthenticationStrategy;
|
||||
}
|
||||
if(isConcurrentSessionControlEnabled()) {
|
||||
ConcurrentSessionControlStrategy concurrentSessionControlStrategy = new ConcurrentSessionControlStrategy(sessionRegistry);
|
||||
concurrentSessionControlStrategy.setMaximumSessions(maximumSessions);
|
||||
concurrentSessionControlStrategy.setExceptionIfMaximumExceeded(maxSessionsPreventsLogin);
|
||||
sessionAuthenticationStrategy = concurrentSessionControlStrategy;
|
||||
}
|
||||
return sessionAuthenticationStrategy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the number of concurrent sessions per user should be restricted.
|
||||
* @return
|
||||
*/
|
||||
private boolean isConcurrentSessionControlEnabled() {
|
||||
return maximumSessions != null;
|
||||
}
|
||||
}
|
||||
+241
@@ -0,0 +1,241 @@
|
||||
/*
|
||||
* Copyright 2002-2013 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.config.annotation.web.configurers;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.security.access.AccessDecisionManager;
|
||||
import org.springframework.security.access.AccessDecisionVoter;
|
||||
import org.springframework.security.access.ConfigAttribute;
|
||||
import org.springframework.security.access.SecurityConfig;
|
||||
import org.springframework.security.access.vote.AuthenticatedVoter;
|
||||
import org.springframework.security.access.vote.RoleVoter;
|
||||
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
|
||||
import org.springframework.security.web.access.intercept.DefaultFilterInvocationSecurityMetadataSource;
|
||||
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
|
||||
import org.springframework.security.web.util.RequestMatcher;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
|
||||
/**
|
||||
* Adds URL based authorization using {@link DefaultFilterInvocationSecurityMetadataSource}. At least one
|
||||
* {@link org.springframework.web.bind.annotation.RequestMapping} needs to be mapped to {@link ConfigAttribute}'s for
|
||||
* this {@link SecurityContextConfigurer} to have meaning.
|
||||
* <h2>Security Filters</h2>
|
||||
*
|
||||
* The following Filters are populated
|
||||
*
|
||||
* <ul>
|
||||
* <li>{@link org.springframework.security.web.access.intercept.FilterSecurityInterceptor}</li>
|
||||
* </ul>
|
||||
*
|
||||
* <h2>Shared Objects Created</h2>
|
||||
*
|
||||
* The following shared objects are populated to allow other {@link org.springframework.security.config.annotation.SecurityConfigurer}'s to customize:
|
||||
* <ul>
|
||||
* <li>{@link org.springframework.security.web.access.intercept.FilterSecurityInterceptor}</li>
|
||||
* </ul>
|
||||
*
|
||||
* <h2>Shared Objects Used</h2>
|
||||
*
|
||||
* The following shared objects are used:
|
||||
*
|
||||
* <ul>
|
||||
* <li>{@link org.springframework.security.config.annotation.web.builders.HttpSecurity#getAuthenticationManager()}</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param <H> the type of {@link HttpSecurityBuilder} that is being configured
|
||||
* @param <C> the type of object that is being chained
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @since 3.2
|
||||
* @see ExpressionUrlAuthorizationConfigurer
|
||||
*/
|
||||
public final class UrlAuthorizationConfigurer<H extends HttpSecurityBuilder<H>, C> extends AbstractInterceptUrlConfigurer<H,C,UrlAuthorizationConfigurer<H,C>.AuthorizedUrl> {
|
||||
|
||||
/**
|
||||
* Creates the default {@link AccessDecisionVoter} instances used if an
|
||||
* {@link AccessDecisionManager} was not specified using
|
||||
* {@link #accessDecisionManager(AccessDecisionManager)}.
|
||||
*/
|
||||
@Override
|
||||
@SuppressWarnings("rawtypes")
|
||||
final List<AccessDecisionVoter> getDecisionVoters() {
|
||||
List<AccessDecisionVoter> decisionVoters = new ArrayList<AccessDecisionVoter>();
|
||||
decisionVoters.add(new RoleVoter());
|
||||
decisionVoters.add(new AuthenticatedVoter());
|
||||
return decisionVoters;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the {@link FilterInvocationSecurityMetadataSource} to use. The
|
||||
* implementation is a {@link DefaultFilterInvocationSecurityMetadataSource}
|
||||
* .
|
||||
*/
|
||||
@Override
|
||||
FilterInvocationSecurityMetadataSource createMetadataSource() {
|
||||
return new DefaultFilterInvocationSecurityMetadataSource(createRequestMap());
|
||||
}
|
||||
|
||||
/**
|
||||
* Chains the {@link RequestMatcher} creation to the {@link AuthorizedUrl} class.
|
||||
*/
|
||||
@Override
|
||||
protected AuthorizedUrl chainRequestMatchersInternal(List<RequestMatcher> requestMatchers) {
|
||||
return new AuthorizedUrl(requestMatchers);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a mapping of the {@link RequestMatcher} instances to the {@link ConfigAttribute} instances.
|
||||
* @param requestMatchers the {@link RequestMatcher} instances that should map to the provided {@link ConfigAttribute} instances
|
||||
* @param configAttributes the {@link ConfigAttribute} instances that should be mapped by the {@link RequestMatcher} instances
|
||||
* @return the {@link UrlAuthorizationConfigurer} for further customizations
|
||||
*/
|
||||
private UrlAuthorizationConfigurer<H,C> addMapping(Iterable<? extends RequestMatcher> requestMatchers, Collection<ConfigAttribute> configAttributes) {
|
||||
for(RequestMatcher requestMatcher : requestMatchers) {
|
||||
addMapping(new UrlMapping(requestMatcher, configAttributes));
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a String for specifying a user requires a role.
|
||||
*
|
||||
* @param role
|
||||
* the role that should be required which is prepended with ROLE_
|
||||
* automatically (i.e. USER, ADMIN, etc). It should not start
|
||||
* with ROLE_
|
||||
* @return the {@link ConfigAttribute} expressed as a String
|
||||
*/
|
||||
private static String hasRole(String role) {
|
||||
Assert.isTrue(
|
||||
!role.startsWith("ROLE_"),
|
||||
role
|
||||
+ " should not start with ROLE_ since ROLE_ is automatically prepended when using hasRole. Consider using hasAuthority or access instead.");
|
||||
return "ROLE_" + role;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a String for specifying that a user requires one of many roles.
|
||||
*
|
||||
* @param roles
|
||||
* the roles that the user should have at least one of (i.e.
|
||||
* ADMIN, USER, etc). Each role should not start with ROLE_ since
|
||||
* it is automatically prepended already.
|
||||
* @return the {@link ConfigAttribute} expressed as a String
|
||||
*/
|
||||
private static String[] hasAnyRole(String... roles) {
|
||||
for(int i=0;i<roles.length;i++) {
|
||||
roles[i] = "ROLE_" + roles[i];
|
||||
}
|
||||
return roles;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a String for specifying that a user requires one of many authorities
|
||||
* @param authorities the authorities that the user should have at least one of (i.e. ROLE_USER, ROLE_ADMIN, etc).
|
||||
* @return the {@link ConfigAttribute} expressed as a String.
|
||||
*/
|
||||
private static String[] hasAnyAuthority(String... authorities) {
|
||||
return authorities;
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps the specified {@link RequestMatcher} instances to {@link ConfigAttribute} instances.
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @since 3.2
|
||||
*/
|
||||
public final class AuthorizedUrl {
|
||||
private final List<RequestMatcher> requestMatchers;
|
||||
|
||||
/**
|
||||
* Creates a new instance
|
||||
* @param requestMatchers the {@link RequestMatcher} instances to map to some {@link ConfigAttribute} instances.
|
||||
* @see UrlAuthorizationConfigurer#chainRequestMatchers(List)
|
||||
*/
|
||||
private AuthorizedUrl(List<RequestMatcher> requestMatchers) {
|
||||
Assert.notEmpty(requestMatchers, "requestMatchers must contain at least one value");
|
||||
this.requestMatchers = requestMatchers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies a user requires a role.
|
||||
*
|
||||
* @param role
|
||||
* the role that should be required which is prepended with ROLE_
|
||||
* automatically (i.e. USER, ADMIN, etc). It should not start
|
||||
* with ROLE_
|
||||
* the {@link UrlAuthorizationConfigurer} for further customization
|
||||
*/
|
||||
public UrlAuthorizationConfigurer<H,C> hasRole(String role) {
|
||||
return access(UrlAuthorizationConfigurer.hasRole(role));
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies that a user requires one of many roles.
|
||||
*
|
||||
* @param roles
|
||||
* the roles that the user should have at least one of (i.e.
|
||||
* ADMIN, USER, etc). Each role should not start with ROLE_ since
|
||||
* it is automatically prepended already.
|
||||
* @return the {@link UrlAuthorizationConfigurer} for further customization
|
||||
*/
|
||||
public UrlAuthorizationConfigurer<H,C> hasAnyRole(String... roles) {
|
||||
return access(UrlAuthorizationConfigurer.hasAnyRole(roles));
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies a user requires an authority.
|
||||
*
|
||||
* @param authority
|
||||
* the authority that should be required
|
||||
* @return the {@link UrlAuthorizationConfigurer} for further customization
|
||||
*/
|
||||
public UrlAuthorizationConfigurer<H,C> hasAuthority(String authority) {
|
||||
return access(authority);
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies that a user requires one of many authorities
|
||||
* @param authorities the authorities that the user should have at least one of (i.e. ROLE_USER, ROLE_ADMIN, etc).
|
||||
* @return the {@link UrlAuthorizationConfigurer} for further customization
|
||||
*/
|
||||
public UrlAuthorizationConfigurer<H,C> hasAnyAuthority(String... authorities) {
|
||||
return access(UrlAuthorizationConfigurer.hasAnyAuthority(authorities));
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies that an anonymous user is allowed access
|
||||
* @return the {@link UrlAuthorizationConfigurer} for further customization
|
||||
*/
|
||||
public UrlAuthorizationConfigurer<H,C> anonymous() {
|
||||
return hasRole("ROLE_ANONYMOUS");
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies that the user must have the specified {@link ConfigAttribute}'s
|
||||
* @param attributes the {@link ConfigAttribute}'s that restrict access to a URL
|
||||
* @return the {@link UrlAuthorizationConfigurer} for further customization
|
||||
*/
|
||||
public UrlAuthorizationConfigurer<H,C> access(String... attributes) {
|
||||
addMapping(requestMatchers, SecurityConfig.createList(attributes));
|
||||
return UrlAuthorizationConfigurer.this;
|
||||
}
|
||||
}
|
||||
}
|
||||
+196
@@ -0,0 +1,196 @@
|
||||
/*
|
||||
* Copyright 2002-2013 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.config.annotation.web.configurers;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.springframework.security.authentication.AuthenticationDetailsSource;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.userdetails.AuthenticationUserDetailsService;
|
||||
import org.springframework.security.core.userdetails.UserDetailsByNameServiceWrapper;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
import org.springframework.security.web.AuthenticationEntryPoint;
|
||||
import org.springframework.security.web.authentication.Http403ForbiddenEntryPoint;
|
||||
import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationProvider;
|
||||
import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken;
|
||||
import org.springframework.security.web.authentication.preauth.PreAuthenticatedGrantedAuthoritiesWebAuthenticationDetails;
|
||||
import org.springframework.security.web.authentication.preauth.x509.SubjectDnX509PrincipalExtractor;
|
||||
import org.springframework.security.web.authentication.preauth.x509.X509AuthenticationFilter;
|
||||
|
||||
/**
|
||||
* Adds X509 based pre authentication to an application. Since validating the
|
||||
* certificate happens when the client connects, the requesting and validation
|
||||
* of the client certificate should be performed by the container. Spring Security
|
||||
* will then use the certificate to look up the {@link Authentication} for the user.
|
||||
*
|
||||
* <h2>Security Filters</h2>
|
||||
*
|
||||
* The following Filters are populated
|
||||
*
|
||||
* <ul>
|
||||
* <li>{@link X509AuthenticationFilter}</li>
|
||||
* </ul>
|
||||
*
|
||||
* <h2>Shared Objects Created</h2>
|
||||
*
|
||||
* The following shared objects are created
|
||||
*
|
||||
* <ul>
|
||||
* <li>
|
||||
* {@link AuthenticationEntryPoint}
|
||||
* is populated with an {@link Http403ForbiddenEntryPoint}</li>
|
||||
* <li>A {@link PreAuthenticatedAuthenticationProvider} is populated into
|
||||
* {@link HttpSecurity#authenticationProvider(org.springframework.security.authentication.AuthenticationProvider)}
|
||||
* </li>
|
||||
* </ul>
|
||||
*
|
||||
* <h2>Shared Objects Used</h2>
|
||||
*
|
||||
* The following shared objects are used:
|
||||
*
|
||||
* <ul>
|
||||
* <li>A {@link UserDetailsService} shared object is used if no {@link AuthenticationUserDetailsService} is specified</li>
|
||||
* </ul>
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @since 3.2
|
||||
*/
|
||||
public final class X509Configurer<H extends HttpSecurityBuilder<H>> extends AbstractHttpConfigurer<H> {
|
||||
private X509AuthenticationFilter x509AuthenticationFilter;
|
||||
private AuthenticationUserDetailsService<PreAuthenticatedAuthenticationToken> authenticationUserDetailsService;
|
||||
private String subjectPrincipalRegex;
|
||||
private AuthenticationDetailsSource<HttpServletRequest, PreAuthenticatedGrantedAuthoritiesWebAuthenticationDetails> authenticationDetailsSource;
|
||||
|
||||
/**
|
||||
* Creates a new instance
|
||||
* @see HttpSecurity#x509()
|
||||
*/
|
||||
public X509Configurer() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows specifying the entire {@link X509AuthenticationFilter}. If this is
|
||||
* specified, the properties on {@link X509Configurer} will not be
|
||||
* populated on the {@link X509AuthenticationFilter}.
|
||||
*
|
||||
* @param x509AuthenticationFilter the {@link X509AuthenticationFilter} to use
|
||||
* @return the {@link X509Configurer} for further customizations
|
||||
*/
|
||||
public X509Configurer<H> x509AuthenticationFilter(
|
||||
X509AuthenticationFilter x509AuthenticationFilter) {
|
||||
this.x509AuthenticationFilter = x509AuthenticationFilter;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies the {@link AuthenticationDetailsSource}
|
||||
*
|
||||
* @param authenticationDetailsSource the {@link AuthenticationDetailsSource} to use
|
||||
* @return the {@link X509Configurer} to use
|
||||
*/
|
||||
public X509Configurer<H> authenticationDetailsSource(AuthenticationDetailsSource<HttpServletRequest, PreAuthenticatedGrantedAuthoritiesWebAuthenticationDetails> authenticationDetailsSource) {
|
||||
this.authenticationDetailsSource = authenticationDetailsSource;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Shortcut for invoking {@link #authenticationUserDetailsService(AuthenticationUserDetailsService)} with a {@link UserDetailsByNameServiceWrapper}.
|
||||
*
|
||||
* @param userDetailsService the {@link UserDetailsService} to use
|
||||
* @return the {@link X509Configurer} for further customizations
|
||||
*/
|
||||
public X509Configurer<H> userDetailsService(
|
||||
UserDetailsService userDetailsService) {
|
||||
UserDetailsByNameServiceWrapper<PreAuthenticatedAuthenticationToken> authenticationUserDetailsService = new UserDetailsByNameServiceWrapper<PreAuthenticatedAuthenticationToken>();
|
||||
authenticationUserDetailsService.setUserDetailsService(userDetailsService);
|
||||
return authenticationUserDetailsService(authenticationUserDetailsService);
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies the {@link AuthenticationUserDetailsService} to use. If not
|
||||
* specified, the shared {@link UserDetailsService} will be used to create a
|
||||
* {@link UserDetailsByNameServiceWrapper}.
|
||||
*
|
||||
* @param authenticationUserDetailsService the {@link AuthenticationUserDetailsService} to use
|
||||
* @return the {@link X509Configurer} for further customizations
|
||||
*/
|
||||
public X509Configurer<H> authenticationUserDetailsService(
|
||||
AuthenticationUserDetailsService<PreAuthenticatedAuthenticationToken> authenticationUserDetailsService) {
|
||||
this.authenticationUserDetailsService = authenticationUserDetailsService;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies the regex to extract the principal from the certificate. If not
|
||||
* specified, the default expression from
|
||||
* {@link SubjectDnX509PrincipalExtractor} is used.
|
||||
*
|
||||
* @param subjectPrincipalRegex
|
||||
* the regex to extract the user principal from the certificate
|
||||
* (i.e. "CN=(.*?)(?:,|$)").
|
||||
* @return the {@link X509Configurer} for further customizations
|
||||
*/
|
||||
public X509Configurer<H> subjectPrincipalRegex(String subjectPrincipalRegex) {
|
||||
this.subjectPrincipalRegex = subjectPrincipalRegex;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(H http) throws Exception {
|
||||
PreAuthenticatedAuthenticationProvider authenticationProvider = new PreAuthenticatedAuthenticationProvider();
|
||||
authenticationProvider.setPreAuthenticatedUserDetailsService(getAuthenticationUserDetailsService(http));
|
||||
|
||||
http
|
||||
.authenticationProvider(authenticationProvider)
|
||||
.setSharedObject(AuthenticationEntryPoint.class,new Http403ForbiddenEntryPoint());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(H http) throws Exception {
|
||||
X509AuthenticationFilter filter = getFilter(http.getAuthenticationManager());
|
||||
http.addFilter(filter);
|
||||
}
|
||||
|
||||
private X509AuthenticationFilter getFilter(
|
||||
AuthenticationManager authenticationManager) {
|
||||
if (x509AuthenticationFilter == null) {
|
||||
x509AuthenticationFilter = new X509AuthenticationFilter();
|
||||
x509AuthenticationFilter.setAuthenticationManager(authenticationManager);
|
||||
if(subjectPrincipalRegex != null) {
|
||||
SubjectDnX509PrincipalExtractor principalExtractor = new SubjectDnX509PrincipalExtractor();
|
||||
principalExtractor.setSubjectDnRegex(subjectPrincipalRegex);
|
||||
x509AuthenticationFilter.setPrincipalExtractor(principalExtractor);
|
||||
}
|
||||
if(authenticationDetailsSource != null) {
|
||||
x509AuthenticationFilter.setAuthenticationDetailsSource(authenticationDetailsSource);
|
||||
}
|
||||
x509AuthenticationFilter = postProcess(x509AuthenticationFilter);
|
||||
}
|
||||
|
||||
return x509AuthenticationFilter;
|
||||
}
|
||||
|
||||
private AuthenticationUserDetailsService<PreAuthenticatedAuthenticationToken> getAuthenticationUserDetailsService(H http) {
|
||||
if(authenticationUserDetailsService == null) {
|
||||
userDetailsService(http.getSharedObject(UserDetailsService.class));
|
||||
}
|
||||
return authenticationUserDetailsService;
|
||||
}
|
||||
|
||||
}
|
||||
+463
@@ -0,0 +1,463 @@
|
||||
/*
|
||||
* Copyright 2002-2013 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.config.annotation.web.configurers.openid;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.openid4java.consumer.ConsumerException;
|
||||
import org.openid4java.consumer.ConsumerManager;
|
||||
import org.springframework.security.authentication.AuthenticationDetailsSource;
|
||||
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
import org.springframework.security.config.annotation.web.configurers.AbstractAuthenticationFilterConfigurer;
|
||||
import org.springframework.security.config.annotation.web.configurers.FormLoginConfigurer;
|
||||
import org.springframework.security.config.annotation.web.configurers.RememberMeConfigurer;
|
||||
import org.springframework.security.config.annotation.web.configurers.SessionManagementConfigurer;
|
||||
import org.springframework.security.config.annotation.web.configurers.openid.OpenIDLoginConfigurer;
|
||||
import org.springframework.security.core.userdetails.AuthenticationUserDetailsService;
|
||||
import org.springframework.security.core.userdetails.UserDetailsByNameServiceWrapper;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
import org.springframework.security.openid.AxFetchListFactory;
|
||||
import org.springframework.security.openid.OpenID4JavaConsumer;
|
||||
import org.springframework.security.openid.OpenIDAttribute;
|
||||
import org.springframework.security.openid.OpenIDAuthenticationFilter;
|
||||
import org.springframework.security.openid.OpenIDAuthenticationProvider;
|
||||
import org.springframework.security.openid.OpenIDAuthenticationToken;
|
||||
import org.springframework.security.openid.OpenIDConsumer;
|
||||
import org.springframework.security.openid.RegexBasedAxFetchListFactory;
|
||||
import org.springframework.security.web.AuthenticationEntryPoint;
|
||||
import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint;
|
||||
import org.springframework.security.web.authentication.RememberMeServices;
|
||||
import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy;
|
||||
import org.springframework.security.web.authentication.ui.DefaultLoginPageViewFilter;
|
||||
|
||||
/**
|
||||
* Adds support for OpenID based authentication.
|
||||
*
|
||||
* <h2>Example Configuration</h2>
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
* @Configuration
|
||||
* @EnableWebSecurity
|
||||
* public class OpenIDLoginConfig extends WebSecurityConfigurerAdapter {
|
||||
*
|
||||
* @Override
|
||||
* protected void configure(HttpSecurity http) {
|
||||
* http
|
||||
* .authorizeUrls()
|
||||
* .antMatchers("/**").hasRole("USER")
|
||||
* .and()
|
||||
* .openidLogin()
|
||||
* .permitAll();
|
||||
* }
|
||||
*
|
||||
* @Override
|
||||
* protected void registerAuthentication(
|
||||
* AuthenticationManagerBuilder auth) throws Exception {
|
||||
* auth
|
||||
* .inMemoryAuthentication()
|
||||
* .withUser("https://www.google.com/accounts/o8/id?id=lmkCn9xzPdsxVwG7pjYMuDgNNdASFmobNkcRPaWU")
|
||||
* .password("password")
|
||||
* .roles("USER");
|
||||
* }
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* <h2>Security Filters</h2>
|
||||
*
|
||||
* The following Filters are populated
|
||||
*
|
||||
* <ul>
|
||||
* <li>
|
||||
* {@link OpenIDAuthenticationFilter}</li>
|
||||
* </ul>
|
||||
*
|
||||
* <h2>Shared Objects Created</h2>
|
||||
*
|
||||
* <ul>
|
||||
* <li>
|
||||
* {@link AuthenticationEntryPoint}
|
||||
* is populated with a {@link LoginUrlAuthenticationEntryPoint}</li>
|
||||
* <li>A {@link OpenIDAuthenticationProvider} is populated into
|
||||
* {@link HttpSecurity#authenticationProvider(org.springframework.security.authentication.AuthenticationProvider)}
|
||||
* </li>
|
||||
* </ul>
|
||||
*
|
||||
* <h2>Shared Objects Used</h2>
|
||||
*
|
||||
* The following shared objects are used:
|
||||
*
|
||||
* <ul>
|
||||
* <li>{@link HttpSecurity#getAuthenticationManager()}</li>
|
||||
* <li>{@link RememberMeServices} - is optionally used. See
|
||||
* {@link RememberMeConfigurer}</li>
|
||||
* <li>{@link SessionAuthenticationStrategy} - is optionally used. See
|
||||
* {@link SessionManagementConfigurer}</li>
|
||||
* </ul>
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @since 3.2
|
||||
*/
|
||||
public final class OpenIDLoginConfigurer<H extends HttpSecurityBuilder<H>> extends AbstractAuthenticationFilterConfigurer<H,OpenIDLoginConfigurer<H>,OpenIDAuthenticationFilter> {
|
||||
private OpenIDConsumer openIDConsumer;
|
||||
private ConsumerManager consumerManager;
|
||||
private AuthenticationUserDetailsService<OpenIDAuthenticationToken> authenticationUserDetailsService;
|
||||
private List<AttributeExchangeConfigurer> attributeExchangeConfigurers = new ArrayList<AttributeExchangeConfigurer>();
|
||||
|
||||
/**
|
||||
* Creates a new instance
|
||||
*/
|
||||
public OpenIDLoginConfigurer() {
|
||||
super(new OpenIDAuthenticationFilter(),"/login/openid");
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up OpenID attribute exchange for OpenID's matching the specified
|
||||
* pattern.
|
||||
*
|
||||
* @param identifierPattern
|
||||
* the regular expression for matching on OpenID's (i.e.
|
||||
* "https://www.google.com/.*", ".*yahoo.com.*", etc)
|
||||
* @return a {@link AttributeExchangeConfigurer} for further customizations of the attribute exchange
|
||||
*/
|
||||
public AttributeExchangeConfigurer attributeExchange(String identifierPattern) {
|
||||
AttributeExchangeConfigurer attributeExchangeConfigurer = new AttributeExchangeConfigurer(identifierPattern);
|
||||
this.attributeExchangeConfigurers .add(attributeExchangeConfigurer);
|
||||
return attributeExchangeConfigurer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows specifying the {@link OpenIDConsumer} to be used. The default is
|
||||
* using an {@link OpenID4JavaConsumer}.
|
||||
*
|
||||
* @param consumer
|
||||
* the {@link OpenIDConsumer} to be used
|
||||
* @return the {@link OpenIDLoginConfigurer} for further customizations
|
||||
*/
|
||||
public OpenIDLoginConfigurer<H> consumer(OpenIDConsumer consumer) {
|
||||
this.openIDConsumer = consumer;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows specifying the {@link ConsumerManager} to be used. If specified,
|
||||
* will be populated into an {@link OpenID4JavaConsumer}.
|
||||
*
|
||||
* <p>
|
||||
* This is a shortcut for specifying the {@link OpenID4JavaConsumer} with a
|
||||
* specific {@link ConsumerManager} on {@link #consumer(OpenIDConsumer)}.
|
||||
* </p>
|
||||
*
|
||||
* @param consumerManager the {@link ConsumerManager} to use. Cannot be null.
|
||||
* @return the {@link OpenIDLoginConfigurer} for further customizations
|
||||
*/
|
||||
public OpenIDLoginConfigurer<H> consumerManager(ConsumerManager consumerManager) {
|
||||
this.consumerManager = consumerManager;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* The {@link AuthenticationUserDetailsService} to use. By default a
|
||||
* {@link UserDetailsByNameServiceWrapper} is used with the
|
||||
* {@link UserDetailsService} shared object found with
|
||||
* {@link HttpSecurity#getSharedObject(Class)}.
|
||||
*
|
||||
* @param authenticationUserDetailsService the {@link AuthenticationDetailsSource} to use
|
||||
* @return the {@link OpenIDLoginConfigurer} for further customizations
|
||||
*/
|
||||
public OpenIDLoginConfigurer<H> authenticationUserDetailsService(AuthenticationUserDetailsService<OpenIDAuthenticationToken> authenticationUserDetailsService) {
|
||||
this.authenticationUserDetailsService = authenticationUserDetailsService;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies the URL used to authenticate OpenID requests. If the {@link HttpServletRequest}
|
||||
* matches this URL the {@link OpenIDAuthenticationFilter} will attempt to
|
||||
* authenticate the request. The default is "/login/openid".
|
||||
*
|
||||
* @param loginUrl
|
||||
* the URL used to perform authentication
|
||||
* @return the {@link OpenIDLoginConfigurer} for additional customization
|
||||
*/
|
||||
public OpenIDLoginConfigurer<H> loginProcessingUrl(String loginProcessingUrl) {
|
||||
return super.loginProcessingUrl(loginProcessingUrl);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Specifies the URL to send users to if login is required. If used with
|
||||
* {@link WebSecurityConfigurerAdapter} a default login page will be
|
||||
* generated when this attribute is not specified.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* If a URL is specified or this is not being used in conjuction with
|
||||
* {@link WebSecurityConfigurerAdapter}, users are required to process the
|
||||
* specified URL to generate a login page.
|
||||
* </p>
|
||||
*
|
||||
* <ul>
|
||||
* <li>It must be an HTTP POST</li>
|
||||
* <li>It must be submitted to {@link #loginProcessingUrl(String)}</li>
|
||||
* <li>It should include the OpenID as an HTTP parameter by the name of
|
||||
* {@link OpenIDAuthenticationFilter#DEFAULT_CLAIMED_IDENTITY_FIELD}</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param loginPage the login page to redirect to if authentication is required (i.e. "/login")
|
||||
* @return the {@link FormLoginConfigurer} for additional customization
|
||||
*/
|
||||
public OpenIDLoginConfigurer<H> loginPage(String loginPage) {
|
||||
return super.loginPage(loginPage);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(H http) throws Exception {
|
||||
super.init(http);
|
||||
|
||||
OpenIDAuthenticationProvider authenticationProvider = new OpenIDAuthenticationProvider();
|
||||
authenticationProvider.setAuthenticationUserDetailsService(getAuthenticationUserDetailsService(http));
|
||||
authenticationProvider = postProcess(authenticationProvider);
|
||||
http.authenticationProvider(authenticationProvider);
|
||||
|
||||
initDefaultLoginFilter(http);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(H http) throws Exception {
|
||||
getAuthenticationFilter().setConsumer(getConsumer());
|
||||
super.configure(http);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the {@link OpenIDConsumer} that was configured or defaults to an {@link OpenID4JavaConsumer}.
|
||||
* @return the {@link OpenIDConsumer} to use
|
||||
* @throws ConsumerException
|
||||
*/
|
||||
private OpenIDConsumer getConsumer() throws ConsumerException {
|
||||
if(openIDConsumer == null) {
|
||||
openIDConsumer = new OpenID4JavaConsumer(getConsumerManager(), attributesToFetchFactory());
|
||||
}
|
||||
return openIDConsumer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the {@link ConsumerManager} that was configured or defaults to using a {@link ConsumerManager} with the default constructor.
|
||||
* @return the {@link ConsumerManager} to use
|
||||
*/
|
||||
private ConsumerManager getConsumerManager() {
|
||||
if(this.consumerManager != null) {
|
||||
return this.consumerManager;
|
||||
}
|
||||
return new ConsumerManager();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an {@link RegexBasedAxFetchListFactory} using the attributes
|
||||
* populated by {@link AttributeExchangeConfigurer}
|
||||
*
|
||||
* @return the {@link AxFetchListFactory} to use
|
||||
*/
|
||||
private AxFetchListFactory attributesToFetchFactory() {
|
||||
Map<String,List<OpenIDAttribute>> identityToAttrs = new HashMap<String,List<OpenIDAttribute>>();
|
||||
for(AttributeExchangeConfigurer conf : attributeExchangeConfigurers) {
|
||||
identityToAttrs.put(conf.identifier, conf.getAttributes());
|
||||
}
|
||||
return new RegexBasedAxFetchListFactory(identityToAttrs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the {@link AuthenticationUserDetailsService} that was configured or
|
||||
* defaults to {@link UserDetailsByNameServiceWrapper} that uses a
|
||||
* {@link UserDetailsService} looked up using
|
||||
* {@link HttpSecurity#getSharedObject(Class)}
|
||||
*
|
||||
* @param http the current {@link HttpSecurity}
|
||||
* @return the {@link AuthenticationUserDetailsService}.
|
||||
*/
|
||||
private AuthenticationUserDetailsService<OpenIDAuthenticationToken> getAuthenticationUserDetailsService(
|
||||
H http) {
|
||||
if(authenticationUserDetailsService != null) {
|
||||
return authenticationUserDetailsService;
|
||||
}
|
||||
return new UserDetailsByNameServiceWrapper<OpenIDAuthenticationToken>(http.getSharedObject(UserDetailsService.class));
|
||||
}
|
||||
|
||||
/**
|
||||
* If available, initializes the {@link DefaultLoginPageViewFilter} shared object.
|
||||
*
|
||||
* @param http the {@link HttpSecurityBuilder} to use
|
||||
*/
|
||||
private void initDefaultLoginFilter(H http) {
|
||||
DefaultLoginPageViewFilter loginPageGeneratingFilter = http.getSharedObject(DefaultLoginPageViewFilter.class);
|
||||
if(loginPageGeneratingFilter != null && !isCustomLoginPage()) {
|
||||
loginPageGeneratingFilter.setOpenIdEnabled(true);
|
||||
loginPageGeneratingFilter.setOpenIDauthenticationUrl(getLoginProcessingUrl());
|
||||
String loginPageUrl = loginPageGeneratingFilter.getLoginPageUrl();
|
||||
if(loginPageUrl == null) {
|
||||
loginPageGeneratingFilter.setLoginPageUrl(getLoginPage());
|
||||
loginPageGeneratingFilter.setFailureUrl(getFailureUrl());
|
||||
}
|
||||
loginPageGeneratingFilter.setOpenIDusernameParameter(OpenIDAuthenticationFilter.DEFAULT_CLAIMED_IDENTITY_FIELD);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A class used to add OpenID attributes to look up
|
||||
*
|
||||
* @author Rob Winch
|
||||
*/
|
||||
public final class AttributeExchangeConfigurer {
|
||||
private final String identifier;
|
||||
private List<OpenIDAttribute> attributes = new ArrayList<OpenIDAttribute>();
|
||||
private List<AttributeConfigurer> attributeConfigurers = new ArrayList<AttributeConfigurer>();
|
||||
|
||||
/**
|
||||
* Creates a new instance
|
||||
* @param identifierPattern the pattern that attempts to match on the OpenID
|
||||
* @see OpenIDLoginConfigurer#attributeExchange(String)
|
||||
*/
|
||||
private AttributeExchangeConfigurer(String identifierPattern) {
|
||||
this.identifier = identifierPattern;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the {@link OpenIDLoginConfigurer} to customize the OpenID configuration further
|
||||
* @return the {@link OpenIDLoginConfigurer}
|
||||
*/
|
||||
public OpenIDLoginConfigurer<H> and() {
|
||||
return OpenIDLoginConfigurer.this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an {@link OpenIDAttribute} to be obtained for the configured OpenID pattern.
|
||||
* @param attribute the {@link OpenIDAttribute} to obtain
|
||||
* @return the {@link AttributeExchangeConfigurer} for further customization of attribute exchange
|
||||
*/
|
||||
public AttributeExchangeConfigurer attribute(OpenIDAttribute attribute) {
|
||||
this.attributes.add(attribute);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an {@link OpenIDAttribute} with the given name
|
||||
* @param name the name of the {@link OpenIDAttribute} to create
|
||||
* @return an {@link AttributeConfigurer} to further configure the {@link OpenIDAttribute} that should be obtained.
|
||||
*/
|
||||
public AttributeConfigurer attribute(String name) {
|
||||
AttributeConfigurer attributeConfigurer = new AttributeConfigurer(name);
|
||||
this.attributeConfigurers.add(attributeConfigurer);
|
||||
return attributeConfigurer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the {@link OpenIDAttribute}'s for the configured OpenID pattern
|
||||
* @return
|
||||
*/
|
||||
private List<OpenIDAttribute> getAttributes() {
|
||||
for(AttributeConfigurer config : attributeConfigurers) {
|
||||
attributes.add(config.build());
|
||||
}
|
||||
attributeConfigurers.clear();
|
||||
return attributes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures an {@link OpenIDAttribute}
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @since 3.2
|
||||
*/
|
||||
public final class AttributeConfigurer {
|
||||
private String name;
|
||||
private int count = 1;
|
||||
private boolean required = false;
|
||||
private String type;
|
||||
|
||||
/**
|
||||
* Creates a new instance
|
||||
* @param name the name of the attribute
|
||||
* @see AttributeExchangeConfigurer#attribute(String)
|
||||
*/
|
||||
private AttributeConfigurer(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies the number of attribute values to request. Default is 1.
|
||||
* @param count the number of attributes to request.
|
||||
* @return the {@link AttributeConfigurer} for further customization
|
||||
*/
|
||||
public AttributeConfigurer count(int count) {
|
||||
this.count = count;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies that this attribute is required. The default is
|
||||
* <code>false</code>. Note that as outlined in the OpenID
|
||||
* specification, required attributes are not validated by the
|
||||
* OpenID Provider. Developers should perform any validation in
|
||||
* custom code.
|
||||
*
|
||||
* @param required specifies the attribute is required
|
||||
* @return the {@link AttributeConfigurer} for further customization
|
||||
*/
|
||||
public AttributeConfigurer required(boolean required) {
|
||||
this.required = required;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* The OpenID attribute type.
|
||||
* @param type
|
||||
* @return
|
||||
*/
|
||||
public AttributeConfigurer type(String type) {
|
||||
this.type = type;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the {@link AttributeExchangeConfigurer} for further
|
||||
* customization of the attributes
|
||||
*
|
||||
* @return the {@link AttributeConfigurer}
|
||||
*/
|
||||
public AttributeExchangeConfigurer and() {
|
||||
return AttributeExchangeConfigurer.this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the {@link OpenIDAttribute}.
|
||||
* @return
|
||||
*/
|
||||
private OpenIDAttribute build() {
|
||||
OpenIDAttribute attribute = new OpenIDAttribute(name, type);
|
||||
attribute.setCount(count);
|
||||
attribute.setRequired(required);
|
||||
return attribute;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+12
-4
@@ -19,6 +19,7 @@ import org.springframework.security.authentication.encoding.PasswordEncoder;
|
||||
import org.springframework.security.authentication.encoding.PlaintextPasswordEncoder;
|
||||
import org.springframework.security.authentication.encoding.ShaPasswordEncoder;
|
||||
import org.springframework.security.config.Elements;
|
||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.util.xml.DomUtils;
|
||||
import org.w3c.dom.Element;
|
||||
@@ -34,6 +35,7 @@ public class PasswordEncoderParser {
|
||||
static final String ATT_REF = "ref";
|
||||
public static final String ATT_HASH = "hash";
|
||||
static final String ATT_BASE_64 = "base64";
|
||||
static final String OPT_HASH_BCRYPT = "bcrypt";
|
||||
static final String OPT_HASH_PLAINTEXT = "plaintext";
|
||||
static final String OPT_HASH_SHA = "sha";
|
||||
static final String OPT_HASH_SHA256 = "sha-256";
|
||||
@@ -42,11 +44,12 @@ public class PasswordEncoderParser {
|
||||
static final String OPT_HASH_LDAP_SHA = "{sha}";
|
||||
static final String OPT_HASH_LDAP_SSHA = "{ssha}";
|
||||
|
||||
private static final Map<String, Class<? extends PasswordEncoder>> ENCODER_CLASSES;
|
||||
private static final Map<String, Class<?>> ENCODER_CLASSES;
|
||||
|
||||
static {
|
||||
ENCODER_CLASSES = new HashMap<String, Class<? extends PasswordEncoder>>();
|
||||
ENCODER_CLASSES = new HashMap<String, Class<?>>();
|
||||
ENCODER_CLASSES.put(OPT_HASH_PLAINTEXT, PlaintextPasswordEncoder.class);
|
||||
ENCODER_CLASSES.put(OPT_HASH_BCRYPT, BCryptPasswordEncoder.class);
|
||||
ENCODER_CLASSES.put(OPT_HASH_SHA, ShaPasswordEncoder.class);
|
||||
ENCODER_CLASSES.put(OPT_HASH_SHA256, ShaPasswordEncoder.class);
|
||||
ENCODER_CLASSES.put(OPT_HASH_MD4, Md4PasswordEncoder.class);
|
||||
@@ -84,12 +87,17 @@ public class PasswordEncoderParser {
|
||||
Element saltSourceElt = DomUtils.getChildElementByTagName(element, Elements.SALT_SOURCE);
|
||||
|
||||
if (saltSourceElt != null) {
|
||||
saltSource = new SaltSourceBeanDefinitionParser().parse(saltSourceElt, parserContext);
|
||||
if (OPT_HASH_BCRYPT.equals(hash)) {
|
||||
parserContext.getReaderContext().error(Elements.SALT_SOURCE + " isn't compatible with bcrypt",
|
||||
parserContext.extractSource(saltSourceElt));
|
||||
} else {
|
||||
saltSource = new SaltSourceBeanDefinitionParser().parse(saltSourceElt, parserContext);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static BeanDefinition createPasswordEncoderBeanDefinition(String hash, boolean useBase64) {
|
||||
Class<? extends PasswordEncoder> beanClass = ENCODER_CLASSES.get(hash);
|
||||
Class<?> beanClass = ENCODER_CLASSES.get(hash);
|
||||
BeanDefinitionBuilder beanBldr = BeanDefinitionBuilder.rootBeanDefinition(beanClass);
|
||||
|
||||
if (OPT_HASH_SHA256.equals(hash)) {
|
||||
|
||||
+8
-2
@@ -115,6 +115,7 @@ final class AuthenticationConfigBuilder {
|
||||
private BeanDefinition jeeFilter;
|
||||
private BeanReference jeeProviderRef;
|
||||
private RootBeanDefinition preAuthEntryPoint;
|
||||
private BeanMetadataElement mainEntryPoint;
|
||||
|
||||
private BeanDefinition logoutFilter;
|
||||
@SuppressWarnings("rawtypes")
|
||||
@@ -499,6 +500,10 @@ final class AuthenticationConfigBuilder {
|
||||
return logoutHandlers;
|
||||
}
|
||||
|
||||
BeanMetadataElement getEntryPointBean() {
|
||||
return mainEntryPoint;
|
||||
}
|
||||
|
||||
void createAnonymousFilter() {
|
||||
Element anonymousElt = DomUtils.getChildElementByTagName(httpElt, Elements.ANONYMOUS);
|
||||
|
||||
@@ -534,7 +539,7 @@ final class AuthenticationConfigBuilder {
|
||||
anonymousFilter = new RootBeanDefinition(AnonymousAuthenticationFilter.class);
|
||||
anonymousFilter.getConstructorArgumentValues().addIndexedArgumentValue(0, key);
|
||||
anonymousFilter.getConstructorArgumentValues().addIndexedArgumentValue(1, username);
|
||||
anonymousFilter.getConstructorArgumentValues().addIndexedArgumentValue(2, AuthorityUtils.createAuthorityList(grantedAuthority));
|
||||
anonymousFilter.getConstructorArgumentValues().addIndexedArgumentValue(2, AuthorityUtils.commaSeparatedStringToAuthorityList(grantedAuthority));
|
||||
anonymousFilter.setSource(source);
|
||||
|
||||
RootBeanDefinition anonymousProviderBean = new RootBeanDefinition(AnonymousAuthenticationProvider.class);
|
||||
@@ -556,7 +561,8 @@ final class AuthenticationConfigBuilder {
|
||||
BeanDefinitionBuilder etfBuilder = BeanDefinitionBuilder.rootBeanDefinition(ExceptionTranslationFilter.class);
|
||||
etfBuilder.addPropertyValue("accessDeniedHandler", createAccessDeniedHandler(httpElt, pc));
|
||||
assert requestCache != null;
|
||||
etfBuilder.addConstructorArgValue(selectEntryPoint());
|
||||
mainEntryPoint = selectEntryPoint();
|
||||
etfBuilder.addConstructorArgValue(mainEntryPoint);
|
||||
etfBuilder.addConstructorArgValue(requestCache);
|
||||
|
||||
etf = etfBuilder.getBeanDefinition();
|
||||
|
||||
+34
-5
@@ -21,6 +21,9 @@ import static org.springframework.security.config.http.SecurityFilters.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.servlet.ServletRequest;
|
||||
|
||||
import org.springframework.beans.BeanMetadataElement;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.BeanReference;
|
||||
import org.springframework.beans.factory.config.RuntimeBeanReference;
|
||||
@@ -53,6 +56,7 @@ import org.springframework.security.web.authentication.session.SessionFixationPr
|
||||
import org.springframework.security.web.context.HttpSessionSecurityContextRepository;
|
||||
import org.springframework.security.web.context.NullSecurityContextRepository;
|
||||
import org.springframework.security.web.context.SecurityContextPersistenceFilter;
|
||||
import org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter;
|
||||
import org.springframework.security.web.jaasapi.JaasApiIntegrationFilter;
|
||||
import org.springframework.security.web.savedrequest.HttpSessionRequestCache;
|
||||
import org.springframework.security.web.savedrequest.NullRequestCache;
|
||||
@@ -61,6 +65,7 @@ import org.springframework.security.web.servletapi.SecurityContextHolderAwareReq
|
||||
import org.springframework.security.web.session.ConcurrentSessionFilter;
|
||||
import org.springframework.security.web.session.SessionManagementFilter;
|
||||
import org.springframework.security.web.session.SimpleRedirectInvalidSessionStrategy;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.util.xml.DomUtils;
|
||||
import org.w3c.dom.Element;
|
||||
@@ -102,6 +107,7 @@ class HttpConfigurationBuilder {
|
||||
private BeanReference contextRepoRef;
|
||||
private BeanReference sessionRegistryRef;
|
||||
private BeanDefinition concurrentSessionFilter;
|
||||
private BeanDefinition webAsyncManagerFilter;
|
||||
private BeanDefinition requestCacheAwareFilter;
|
||||
private BeanReference sessionStrategyRef;
|
||||
private RootBeanDefinition sfpf;
|
||||
@@ -114,7 +120,6 @@ class HttpConfigurationBuilder {
|
||||
|
||||
public HttpConfigurationBuilder(Element element, ParserContext pc,
|
||||
BeanReference portMapper, BeanReference portResolver, BeanReference authenticationManager) {
|
||||
|
||||
this.httpElt = element;
|
||||
this.pc = pc;
|
||||
this.portMapper = portMapper;
|
||||
@@ -140,8 +145,9 @@ class HttpConfigurationBuilder {
|
||||
|
||||
createSecurityContextPersistenceFilter();
|
||||
createSessionManagementFilters();
|
||||
createWebAsyncManagerFilter();
|
||||
createRequestCacheFilter();
|
||||
createServletApiFilter();
|
||||
createServletApiFilter(authenticationManager);
|
||||
createJaasApiFilter();
|
||||
createChannelProcessingFilter();
|
||||
createFilterSecurityInterceptor(authenticationManager);
|
||||
@@ -149,8 +155,19 @@ class HttpConfigurationBuilder {
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
void setLogoutHandlers(ManagedList logoutHandlers) {
|
||||
if(logoutHandlers != null && concurrentSessionFilter != null) {
|
||||
concurrentSessionFilter.getPropertyValues().add("logoutHandlers", logoutHandlers);
|
||||
if(logoutHandlers != null) {
|
||||
if(concurrentSessionFilter != null) {
|
||||
concurrentSessionFilter.getPropertyValues().add("logoutHandlers", logoutHandlers);
|
||||
}
|
||||
if(servApiFilter != null) {
|
||||
servApiFilter.getPropertyValues().add("logoutHandlers", logoutHandlers);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void setEntryPoint(BeanMetadataElement entryPoint) {
|
||||
if(servApiFilter != null) {
|
||||
servApiFilter.getPropertyValues().add("authenticationEntryPoint", entryPoint);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -350,8 +367,15 @@ class HttpConfigurationBuilder {
|
||||
sessionRegistryRef = new RuntimeBeanReference(sessionRegistryId);
|
||||
}
|
||||
|
||||
private void createWebAsyncManagerFilter() {
|
||||
boolean asyncSupported = ClassUtils.hasMethod(ServletRequest.class, "startAsync");
|
||||
if(asyncSupported) {
|
||||
webAsyncManagerFilter = new RootBeanDefinition(WebAsyncManagerIntegrationFilter.class);
|
||||
}
|
||||
}
|
||||
|
||||
// Adds the servlet-api integration filter if required
|
||||
private void createServletApiFilter() {
|
||||
private void createServletApiFilter(BeanReference authenticationManager) {
|
||||
final String ATT_SERVLET_API_PROVISION = "servlet-api-provision";
|
||||
final String DEF_SERVLET_API_PROVISION = "true";
|
||||
|
||||
@@ -362,6 +386,7 @@ class HttpConfigurationBuilder {
|
||||
|
||||
if ("true".equals(provideServletApi)) {
|
||||
servApiFilter = new RootBeanDefinition(SecurityContextHolderAwareRequestFilter.class);
|
||||
servApiFilter.getPropertyValues().add("authenticationManager", authenticationManager);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -552,6 +577,10 @@ class HttpConfigurationBuilder {
|
||||
filters.add(new OrderDecorator(concurrentSessionFilter, CONCURRENT_SESSION_FILTER));
|
||||
}
|
||||
|
||||
if (webAsyncManagerFilter != null) {
|
||||
filters.add(new OrderDecorator(webAsyncManagerFilter, WEB_ASYNC_MANAGER_FILTER));
|
||||
}
|
||||
|
||||
filters.add(new OrderDecorator(securityContextPersistenceFilter, SECURITY_CONTEXT_FILTER));
|
||||
|
||||
if (servApiFilter != null) {
|
||||
|
||||
+1
@@ -140,6 +140,7 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
|
||||
httpBldr.getSessionStrategy(), portMapper, portResolver);
|
||||
|
||||
httpBldr.setLogoutHandlers(authBldr.getLogoutHandlers());
|
||||
httpBldr.setEntryPoint(authBldr.getEntryPointBean());
|
||||
|
||||
authenticationProviders.addAll(authBldr.getProviders());
|
||||
|
||||
|
||||
+16
-5
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 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.
|
||||
@@ -38,6 +38,7 @@ import org.w3c.dom.Element;
|
||||
* @author Luke Taylor
|
||||
* @author Ben Alex
|
||||
* @author Rob Winch
|
||||
* @author Oliver Becker
|
||||
*/
|
||||
class RememberMeBeanDefinitionParser implements BeanDefinitionParser {
|
||||
static final String ATT_DATA_SOURCE = "data-source-ref";
|
||||
@@ -48,6 +49,7 @@ class RememberMeBeanDefinitionParser implements BeanDefinitionParser {
|
||||
static final String ATT_SUCCESS_HANDLER_REF = "authentication-success-handler-ref";
|
||||
static final String ATT_TOKEN_VALIDITY = "token-validity-seconds";
|
||||
static final String ATT_SECURE_COOKIE = "use-secure-cookie";
|
||||
static final String ATT_FORM_REMEMBERME_PARAMETER = "remember-me-parameter";
|
||||
|
||||
protected final Log logger = LogFactory.getLog(getClass());
|
||||
private final String key;
|
||||
@@ -70,6 +72,8 @@ class RememberMeBeanDefinitionParser implements BeanDefinitionParser {
|
||||
String successHandlerRef = element.getAttribute(ATT_SUCCESS_HANDLER_REF);
|
||||
String rememberMeServicesRef = element.getAttribute(ATT_SERVICES_REF);
|
||||
String tokenValiditySeconds = element.getAttribute(ATT_TOKEN_VALIDITY);
|
||||
String useSecureCookie = element.getAttribute(ATT_SECURE_COOKIE);
|
||||
String remembermeParameter = element.getAttribute(ATT_FORM_REMEMBERME_PARAMETER);
|
||||
Object source = pc.extractSource(element);
|
||||
|
||||
RootBeanDefinition services = null;
|
||||
@@ -78,11 +82,14 @@ class RememberMeBeanDefinitionParser implements BeanDefinitionParser {
|
||||
boolean tokenRepoSet = StringUtils.hasText(tokenRepository);
|
||||
boolean servicesRefSet = StringUtils.hasText(rememberMeServicesRef);
|
||||
boolean userServiceSet = StringUtils.hasText(userServiceRef);
|
||||
boolean useSecureCookieSet = StringUtils.hasText(useSecureCookie);
|
||||
boolean tokenValiditySet = StringUtils.hasText(tokenValiditySeconds);
|
||||
boolean remembermeParameterSet = StringUtils.hasText(remembermeParameter);
|
||||
|
||||
if (servicesRefSet && (dataSourceSet || tokenRepoSet || userServiceSet || tokenValiditySet)) {
|
||||
if (servicesRefSet && (dataSourceSet || tokenRepoSet || userServiceSet || tokenValiditySet || useSecureCookieSet || remembermeParameterSet)) {
|
||||
pc.getReaderContext().error(ATT_SERVICES_REF + " can't be used in combination with attributes "
|
||||
+ ATT_TOKEN_REPOSITORY + "," + ATT_DATA_SOURCE + ", " + ATT_USER_SERVICE_REF + " or " + ATT_TOKEN_VALIDITY, source);
|
||||
+ ATT_TOKEN_REPOSITORY + "," + ATT_DATA_SOURCE + ", " + ATT_USER_SERVICE_REF + ", " + ATT_TOKEN_VALIDITY
|
||||
+ ", " + ATT_SECURE_COOKIE + " or " + ATT_FORM_REMEMBERME_PARAMETER, source);
|
||||
}
|
||||
|
||||
if (dataSourceSet && tokenRepoSet) {
|
||||
@@ -120,8 +127,7 @@ class RememberMeBeanDefinitionParser implements BeanDefinitionParser {
|
||||
services.getConstructorArgumentValues().addGenericArgumentValue(uds);
|
||||
// tokenRepo is already added if it is a PersistentTokenBasedRememberMeServices
|
||||
|
||||
String useSecureCookie = element.getAttribute(ATT_SECURE_COOKIE);
|
||||
if (StringUtils.hasText(useSecureCookie)) {
|
||||
if (useSecureCookieSet) {
|
||||
services.getPropertyValues().addPropertyValue("useSecureCookie", Boolean.valueOf(useSecureCookie));
|
||||
}
|
||||
|
||||
@@ -133,6 +139,11 @@ class RememberMeBeanDefinitionParser implements BeanDefinitionParser {
|
||||
}
|
||||
services.getPropertyValues().addPropertyValue("tokenValiditySeconds", tokenValidity);
|
||||
}
|
||||
|
||||
if (remembermeParameterSet) {
|
||||
services.getPropertyValues().addPropertyValue("parameter", remembermeParameter);
|
||||
}
|
||||
|
||||
services.setSource(source);
|
||||
servicesName = pc.getReaderContext().generateBeanName(services);
|
||||
pc.registerBeanComponent(new BeanComponentDefinition(services, servicesName));
|
||||
|
||||
@@ -1,17 +1,34 @@
|
||||
/*
|
||||
* Copyright 2002-2012 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.config.http;
|
||||
|
||||
import org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter;
|
||||
|
||||
|
||||
/**
|
||||
* Stores the default order numbers of all Spring Security filters for use in configuration.
|
||||
*
|
||||
* @author Luke Taylor
|
||||
* @author Rob Winch
|
||||
*/
|
||||
|
||||
enum SecurityFilters {
|
||||
FIRST (Integer.MIN_VALUE),
|
||||
CHANNEL_FILTER,
|
||||
CONCURRENT_SESSION_FILTER,
|
||||
SECURITY_CONTEXT_FILTER,
|
||||
CONCURRENT_SESSION_FILTER,
|
||||
/** {@link WebAsyncManagerIntegrationFilter} */
|
||||
WEB_ASYNC_MANAGER_FILTER,
|
||||
LOGOUT_FILTER,
|
||||
X509_FILTER,
|
||||
PRE_AUTH_FILTER,
|
||||
|
||||
+62
-4
@@ -1,3 +1,18 @@
|
||||
/*
|
||||
* Copyright 2002-2013 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.config.method;
|
||||
|
||||
import static org.springframework.security.config.Elements.*;
|
||||
@@ -10,6 +25,8 @@ import java.util.Map;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.aop.config.AopNamespaceUtils;
|
||||
import org.springframework.aop.framework.ProxyFactoryBean;
|
||||
import org.springframework.aop.target.LazyInitTargetSource;
|
||||
import org.springframework.beans.BeanMetadataElement;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
@@ -17,15 +34,19 @@ import org.springframework.beans.factory.BeanFactoryAware;
|
||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.BeanReference;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.beans.factory.config.RuntimeBeanReference;
|
||||
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
|
||||
import org.springframework.beans.factory.parsing.CompositeComponentDefinition;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
|
||||
import org.springframework.beans.factory.support.ManagedList;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.beans.factory.xml.BeanDefinitionParser;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.security.access.ConfigAttribute;
|
||||
import org.springframework.security.access.PermissionEvaluator;
|
||||
import org.springframework.security.access.SecurityConfig;
|
||||
import org.springframework.security.access.annotation.Jsr250MethodSecurityMetadataSource;
|
||||
import org.springframework.security.access.annotation.Jsr250Voter;
|
||||
@@ -34,6 +55,7 @@ import org.springframework.security.access.expression.method.DefaultMethodSecuri
|
||||
import org.springframework.security.access.expression.method.ExpressionBasedAnnotationAttributeFactory;
|
||||
import org.springframework.security.access.expression.method.ExpressionBasedPostInvocationAdvice;
|
||||
import org.springframework.security.access.expression.method.ExpressionBasedPreInvocationAdvice;
|
||||
import org.springframework.security.access.expression.method.MethodSecurityExpressionHandler;
|
||||
import org.springframework.security.access.intercept.AfterInvocationProviderManager;
|
||||
import org.springframework.security.access.intercept.aopalliance.MethodSecurityInterceptor;
|
||||
import org.springframework.security.access.intercept.aopalliance.MethodSecurityMetadataSourceAdvisor;
|
||||
@@ -47,7 +69,6 @@ import org.springframework.security.access.vote.AffirmativeBased;
|
||||
import org.springframework.security.access.vote.AuthenticatedVoter;
|
||||
import org.springframework.security.access.vote.RoleVoter;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.authentication.ProviderManager;
|
||||
import org.springframework.security.config.BeanIds;
|
||||
import org.springframework.security.config.Elements;
|
||||
import org.springframework.security.config.authentication.AuthenticationManagerFactoryBean;
|
||||
@@ -63,6 +84,7 @@ import org.w3c.dom.Element;
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @author Luke Taylor
|
||||
* @author Rob Winch
|
||||
* @since 2.0
|
||||
*/
|
||||
public class GlobalMethodSecurityBeanDefinitionParser implements BeanDefinitionParser {
|
||||
@@ -139,6 +161,20 @@ public class GlobalMethodSecurityBeanDefinitionParser implements BeanDefinitionP
|
||||
|
||||
if (StringUtils.hasText(expressionHandlerRef)) {
|
||||
logger.info("Using bean '" + expressionHandlerRef + "' as method ExpressionHandler implementation");
|
||||
RootBeanDefinition lazyInitPP = new RootBeanDefinition(LazyInitBeanDefinitionRegistryPostProcessor.class);
|
||||
lazyInitPP.getConstructorArgumentValues().addGenericArgumentValue(expressionHandlerRef);
|
||||
pc.getReaderContext().registerWithGeneratedName(lazyInitPP);
|
||||
|
||||
BeanDefinitionBuilder lazyMethodSecurityExpressionHandlerBldr = BeanDefinitionBuilder.rootBeanDefinition(LazyInitTargetSource.class);
|
||||
lazyMethodSecurityExpressionHandlerBldr.addPropertyValue("targetBeanName", expressionHandlerRef);
|
||||
|
||||
BeanDefinitionBuilder expressionHandlerProxyBldr = BeanDefinitionBuilder.rootBeanDefinition(ProxyFactoryBean.class);
|
||||
expressionHandlerProxyBldr.addPropertyValue("targetSource", lazyMethodSecurityExpressionHandlerBldr.getBeanDefinition());
|
||||
expressionHandlerProxyBldr.addPropertyValue("proxyInterfaces", MethodSecurityExpressionHandler.class);
|
||||
|
||||
expressionHandlerRef = pc.getReaderContext().generateBeanName(expressionHandlerProxyBldr.getBeanDefinition());
|
||||
|
||||
pc.registerBeanComponent(new BeanComponentDefinition(expressionHandlerProxyBldr.getBeanDefinition(), expressionHandlerRef));
|
||||
} else {
|
||||
BeanDefinition expressionHandler = new RootBeanDefinition(DefaultMethodSecurityExpressionHandler.class);
|
||||
expressionHandlerRef = pc.getReaderContext().generateBeanName(expressionHandler);
|
||||
@@ -234,7 +270,7 @@ public class GlobalMethodSecurityBeanDefinitionParser implements BeanDefinitionP
|
||||
* expression voter if expression-based access control is enabled.
|
||||
* @return
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
private String registerAccessManager(ParserContext pc, boolean jsr250Enabled, BeanDefinition expressionVoter) {
|
||||
|
||||
BeanDefinitionBuilder accessMgrBuilder = BeanDefinitionBuilder.rootBeanDefinition(AffirmativeBased.class);
|
||||
@@ -259,7 +295,7 @@ public class GlobalMethodSecurityBeanDefinitionParser implements BeanDefinitionP
|
||||
return id;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@SuppressWarnings("rawtypes")
|
||||
private BeanReference registerDelegatingMethodSecurityMetadataSource(ParserContext pc, ManagedList delegates, Object source) {
|
||||
RootBeanDefinition delegatingMethodSecurityMetadataSource = new RootBeanDefinition(DelegatingMethodSecurityMetadataSource.class);
|
||||
delegatingMethodSecurityMetadataSource.setSource(source);
|
||||
@@ -383,7 +419,7 @@ public class GlobalMethodSecurityBeanDefinitionParser implements BeanDefinitionP
|
||||
if (delegate == null) {
|
||||
Assert.state(beanFactory != null, "BeanFactory must be set to resolve " + authMgrBean);
|
||||
try {
|
||||
delegate = beanFactory.getBean(authMgrBean, ProviderManager.class);
|
||||
delegate = beanFactory.getBean(authMgrBean, AuthenticationManager.class);
|
||||
} catch (NoSuchBeanDefinitionException e) {
|
||||
if (BeanIds.AUTHENTICATION_MANAGER.equals(e.getBeanName())) {
|
||||
throw new NoSuchBeanDefinitionException(BeanIds.AUTHENTICATION_MANAGER,
|
||||
@@ -401,4 +437,26 @@ public class GlobalMethodSecurityBeanDefinitionParser implements BeanDefinitionP
|
||||
this.beanFactory = beanFactory;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delays setting a bean of a given name to be lazyily initialized until after all the beans are registered.
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @since 3.2
|
||||
*/
|
||||
private static final class LazyInitBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {
|
||||
private final String beanName;
|
||||
|
||||
private LazyInitBeanDefinitionRegistryPostProcessor(String beanName) {
|
||||
this.beanName = beanName;
|
||||
}
|
||||
|
||||
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
|
||||
BeanDefinition beanDefinition = registry.getBeanDefinition(beanName);
|
||||
beanDefinition.setLazyInit(true);
|
||||
}
|
||||
|
||||
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+24
-15
@@ -51,6 +51,7 @@ final class ProtectPointcutPostProcessor implements BeanPostProcessor {
|
||||
private final PointcutParser parser;
|
||||
private final Set<String> processedBeans = new HashSet<String>();
|
||||
|
||||
|
||||
public ProtectPointcutPostProcessor(MapBasedMethodSecurityMetadataSource mapBasedMethodSecurityMetadataSource) {
|
||||
Assert.notNull(mapBasedMethodSecurityMetadataSource, "MapBasedMethodSecurityMetadataSource to populate is required");
|
||||
this.mapBasedMethodSecurityMetadataSource = mapBasedMethodSecurityMetadataSource;
|
||||
@@ -80,26 +81,34 @@ final class ProtectPointcutPostProcessor implements BeanPostProcessor {
|
||||
return bean;
|
||||
}
|
||||
|
||||
// Obtain methods for the present bean
|
||||
Method[] methods;
|
||||
try {
|
||||
methods = bean.getClass().getMethods();
|
||||
} catch (Exception e) {
|
||||
throw new IllegalStateException(e.getMessage());
|
||||
}
|
||||
synchronized(processedBeans) {
|
||||
// check again synchronized this time
|
||||
if (processedBeans.contains(beanName)) {
|
||||
return bean;
|
||||
}
|
||||
|
||||
// Check to see if any of those methods are compatible with our pointcut expressions
|
||||
for (Method method : methods) {
|
||||
for (PointcutExpression expression : pointCutExpressions) {
|
||||
// Try for the bean class directly
|
||||
if (attemptMatch(bean.getClass(), method, expression, beanName)) {
|
||||
// We've found the first expression that matches this method, so move onto the next method now
|
||||
break; // the "while" loop, not the "for" loop
|
||||
// Obtain methods for the present bean
|
||||
Method[] methods;
|
||||
try {
|
||||
methods = bean.getClass().getMethods();
|
||||
} catch (Exception e) {
|
||||
throw new IllegalStateException(e.getMessage());
|
||||
}
|
||||
|
||||
// Check to see if any of those methods are compatible with our pointcut expressions
|
||||
for (Method method : methods) {
|
||||
for (PointcutExpression expression : pointCutExpressions) {
|
||||
// Try for the bean class directly
|
||||
if (attemptMatch(bean.getClass(), method, expression, beanName)) {
|
||||
// We've found the first expression that matches this method, so move onto the next method now
|
||||
break; // the "while" loop, not the "for" loop
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
processedBeans.add(beanName);
|
||||
}
|
||||
|
||||
processedBeans.add(beanName);
|
||||
|
||||
return bean;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
http\://www.springframework.org/schema/security/spring-security.xsd=org/springframework/security/config/spring-security-3.1.xsd
|
||||
http\://www.springframework.org/schema/security/spring-security.xsd=org/springframework/security/config/spring-security-3.2.xsd
|
||||
http\://www.springframework.org/schema/security/spring-security-3.2.xsd=org/springframework/security/config/spring-security-3.2.xsd
|
||||
http\://www.springframework.org/schema/security/spring-security-3.1.xsd=org/springframework/security/config/spring-security-3.1.xsd
|
||||
http\://www.springframework.org/schema/security/spring-security-3.0.3.xsd=org/springframework/security/config/spring-security-3.0.3.xsd
|
||||
http\://www.springframework.org/schema/security/spring-security-3.0.xsd=org/springframework/security/config/spring-security-3.0.xsd
|
||||
|
||||
+2
-2
@@ -553,7 +553,7 @@ remember-me =
|
||||
## Sets up remember-me authentication. If used with the "key" attribute (or no attributes) the cookie-only implementation will be used. Specifying "token-repository-ref" or "remember-me-data-source-ref" will use the more secure, persisten token approach.
|
||||
element remember-me {remember-me.attlist}
|
||||
remember-me.attlist &=
|
||||
## The "key" used to identify cookies from a specific token-based remember-me application. You should set this to a unique value for your application.
|
||||
## The "key" used to identify cookies from a specific token-based remember-me application. You should set this to a unique value for your application. If unset, it will default to a random value generated by SecureRandom.
|
||||
attribute key {xsd:token}?
|
||||
|
||||
remember-me.attlist &=
|
||||
@@ -593,7 +593,7 @@ anonymous =
|
||||
## Adds support for automatically granting all anonymous web requests a particular principal identity and a corresponding granted authority.
|
||||
element anonymous {anonymous.attlist}
|
||||
anonymous.attlist &=
|
||||
## The key shared between the provider and filter. This generally does not need to be set. If unset, it will default to "doesNotMatter".
|
||||
## The key shared between the provider and filter. This generally does not need to be set. If unset, it will default to a random value generated by SecureRandom.
|
||||
attribute key {xsd:token}?
|
||||
anonymous.attlist &=
|
||||
## The username that should be assigned to the anonymous request. This allows the principal to be identified, which may be important for logging and auditing. if unset, defaults to "anonymousUser".
|
||||
|
||||
+2145
-1484
File diff suppressed because it is too large
Load Diff
+744
@@ -0,0 +1,744 @@
|
||||
namespace a = "http://relaxng.org/ns/compatibility/annotations/1.0"
|
||||
datatypes xsd = "http://www.w3.org/2001/XMLSchema-datatypes"
|
||||
|
||||
default namespace = "http://www.springframework.org/schema/security"
|
||||
|
||||
start = http | ldap-server | authentication-provider | ldap-authentication-provider | any-user-service | ldap-server | ldap-authentication-provider
|
||||
|
||||
hash =
|
||||
## Defines the hashing algorithm used on user passwords. Bcrypt is recommended.
|
||||
attribute hash {"bcrypt" | "plaintext" | "sha" | "sha-256" | "md5" | "md4" | "{sha}" | "{ssha}"}
|
||||
base64 =
|
||||
## Whether a string should be base64 encoded
|
||||
attribute base64 {xsd:boolean}
|
||||
request-matcher =
|
||||
## Supersedes the 'path-type' attribute. Defines the strategy use for matching incoming requests. Currently the options are 'ant' (for ant path patterns), 'regex' for regular expressions and 'ciRegex' for case-insensitive regular expressions.
|
||||
attribute request-matcher {"ant" | "regex" | "ciRegex"}
|
||||
path-type =
|
||||
## Deprecated. Use request-matcher instead.
|
||||
attribute path-type {"ant" | "regex"}
|
||||
port =
|
||||
## Specifies an IP port number. Used to configure an embedded LDAP server, for example.
|
||||
attribute port { xsd:positiveInteger }
|
||||
url =
|
||||
## Specifies a URL.
|
||||
attribute url { xsd:token }
|
||||
id =
|
||||
## A bean identifier, used for referring to the bean elsewhere in the context.
|
||||
attribute id {xsd:token}
|
||||
name =
|
||||
## A bean identifier, used for referring to the bean elsewhere in the context.
|
||||
attribute name {xsd:token}
|
||||
ref =
|
||||
## Defines a reference to a Spring bean Id.
|
||||
attribute ref {xsd:token}
|
||||
|
||||
cache-ref =
|
||||
## Defines a reference to a cache for use with a UserDetailsService.
|
||||
attribute cache-ref {xsd:token}
|
||||
|
||||
user-service-ref =
|
||||
## A reference to a user-service (or UserDetailsService bean) Id
|
||||
attribute user-service-ref {xsd:token}
|
||||
|
||||
authentication-manager-ref =
|
||||
## A reference to an AuthenticationManager bean
|
||||
attribute authentication-manager-ref {xsd:token}
|
||||
|
||||
data-source-ref =
|
||||
## A reference to a DataSource bean
|
||||
attribute data-source-ref {xsd:token}
|
||||
|
||||
|
||||
|
||||
debug =
|
||||
## Enables Spring Security debugging infrastructure. This will provide human-readable (multi-line) debugging information to monitor requests coming into the security filters. This may include sensitive information, such as request parameters or headers, and should only be used in a development environment.
|
||||
element debug {empty}
|
||||
|
||||
password-encoder =
|
||||
## element which defines a password encoding strategy. Used by an authentication provider to convert submitted passwords to hashed versions, for example.
|
||||
element password-encoder {password-encoder.attlist, salt-source?}
|
||||
password-encoder.attlist &=
|
||||
ref | (hash? & base64?)
|
||||
|
||||
salt-source =
|
||||
## Password salting strategy. A system-wide constant or a property from the UserDetails object can be used.
|
||||
element salt-source {user-property | system-wide | ref}
|
||||
user-property =
|
||||
## A property of the UserDetails object which will be used as salt by a password encoder. Typically something like "username" might be used.
|
||||
attribute user-property {xsd:token}
|
||||
system-wide =
|
||||
## A single value that will be used as the salt for a password encoder.
|
||||
attribute system-wide {xsd:token}
|
||||
|
||||
role-prefix =
|
||||
## A non-empty string prefix that will be added to role strings loaded from persistent storage (e.g. "ROLE_"). Use the value "none" for no prefix in cases where the default is non-empty.
|
||||
attribute role-prefix {xsd:token}
|
||||
|
||||
use-expressions =
|
||||
## Enables the use of expressions in the 'access' attributes in <intercept-url> elements rather than the traditional list of configuration attributes. Defaults to 'false'. If enabled, each attribute should contain a single boolean expression. If the expression evaluates to 'true', access will be granted.
|
||||
attribute use-expressions {xsd:boolean}
|
||||
|
||||
ldap-server =
|
||||
## Defines an LDAP server location or starts an embedded server. The url indicates the location of a remote server. If no url is given, an embedded server will be started, listening on the supplied port number. The port is optional and defaults to 33389. A Spring LDAP ContextSource bean will be registered for the server with the id supplied.
|
||||
element ldap-server {ldap-server.attlist}
|
||||
ldap-server.attlist &= id?
|
||||
ldap-server.attlist &= (url | port)?
|
||||
ldap-server.attlist &=
|
||||
## Username (DN) of the "manager" user identity which will be used to authenticate to a (non-embedded) LDAP server. If omitted, anonymous access will be used.
|
||||
attribute manager-dn {xsd:string}?
|
||||
ldap-server.attlist &=
|
||||
## The password for the manager DN. This is required if the manager-dn is specified.
|
||||
attribute manager-password {xsd:string}?
|
||||
ldap-server.attlist &=
|
||||
## Explicitly specifies an ldif file resource to load into an embedded LDAP server. The default is classpath*:*.ldiff
|
||||
attribute ldif { xsd:string }?
|
||||
ldap-server.attlist &=
|
||||
## Optional root suffix for the embedded LDAP server. Default is "dc=springframework,dc=org"
|
||||
attribute root { xsd:string }?
|
||||
|
||||
ldap-server-ref-attribute =
|
||||
## The optional server to use. If omitted, and a default LDAP server is registered (using <ldap-server> with no Id), that server will be used.
|
||||
attribute server-ref {xsd:token}
|
||||
|
||||
|
||||
group-search-filter-attribute =
|
||||
## Group search filter. Defaults to (uniqueMember={0}). The substituted parameter is the DN of the user.
|
||||
attribute group-search-filter {xsd:token}
|
||||
group-search-base-attribute =
|
||||
## Search base for group membership searches. Defaults to "" (searching from the root).
|
||||
attribute group-search-base {xsd:token}
|
||||
user-search-filter-attribute =
|
||||
## The LDAP filter used to search for users (optional). For example "(uid={0})". The substituted parameter is the user's login name.
|
||||
attribute user-search-filter {xsd:token}
|
||||
user-search-base-attribute =
|
||||
## Search base for user searches. Defaults to "". Only used with a 'user-search-filter'.
|
||||
attribute user-search-base {xsd:token}
|
||||
group-role-attribute-attribute =
|
||||
## The LDAP attribute name which contains the role name which will be used within Spring Security. Defaults to "cn".
|
||||
attribute group-role-attribute {xsd:token}
|
||||
user-details-class-attribute =
|
||||
## Allows the objectClass of the user entry to be specified. If set, the framework will attempt to load standard attributes for the defined class into the returned UserDetails object
|
||||
attribute user-details-class {"person" | "inetOrgPerson"}
|
||||
user-context-mapper-attribute =
|
||||
## Allows explicit customization of the loaded user object by specifying a UserDetailsContextMapper bean which will be called with the context information from the user's directory entry
|
||||
attribute user-context-mapper-ref {xsd:token}
|
||||
|
||||
|
||||
ldap-user-service =
|
||||
## This element configures a LdapUserDetailsService which is a combination of a FilterBasedLdapUserSearch and a DefaultLdapAuthoritiesPopulator.
|
||||
element ldap-user-service {ldap-us.attlist}
|
||||
ldap-us.attlist &= id?
|
||||
ldap-us.attlist &=
|
||||
ldap-server-ref-attribute?
|
||||
ldap-us.attlist &=
|
||||
user-search-filter-attribute?
|
||||
ldap-us.attlist &=
|
||||
user-search-base-attribute?
|
||||
ldap-us.attlist &=
|
||||
group-search-filter-attribute?
|
||||
ldap-us.attlist &=
|
||||
group-search-base-attribute?
|
||||
ldap-us.attlist &=
|
||||
group-role-attribute-attribute?
|
||||
ldap-us.attlist &=
|
||||
cache-ref?
|
||||
ldap-us.attlist &=
|
||||
role-prefix?
|
||||
ldap-us.attlist &=
|
||||
(user-details-class-attribute | user-context-mapper-attribute)?
|
||||
|
||||
ldap-authentication-provider =
|
||||
## Sets up an ldap authentication provider
|
||||
element ldap-authentication-provider {ldap-ap.attlist, password-compare-element?}
|
||||
ldap-ap.attlist &=
|
||||
ldap-server-ref-attribute?
|
||||
ldap-ap.attlist &=
|
||||
user-search-base-attribute?
|
||||
ldap-ap.attlist &=
|
||||
user-search-filter-attribute?
|
||||
ldap-ap.attlist &=
|
||||
group-search-base-attribute?
|
||||
ldap-ap.attlist &=
|
||||
group-search-filter-attribute?
|
||||
ldap-ap.attlist &=
|
||||
group-role-attribute-attribute?
|
||||
ldap-ap.attlist &=
|
||||
## A specific pattern used to build the user's DN, for example "uid={0},ou=people". The key "{0}" must be present and will be substituted with the username.
|
||||
attribute user-dn-pattern {xsd:token}?
|
||||
ldap-ap.attlist &=
|
||||
role-prefix?
|
||||
ldap-ap.attlist &=
|
||||
(user-details-class-attribute | user-context-mapper-attribute)?
|
||||
|
||||
password-compare-element =
|
||||
## Specifies that an LDAP provider should use an LDAP compare operation of the user's password to authenticate the user
|
||||
element password-compare {password-compare.attlist, password-encoder?}
|
||||
|
||||
password-compare.attlist &=
|
||||
## The attribute in the directory which contains the user password. Defaults to "userPassword".
|
||||
attribute password-attribute {xsd:token}?
|
||||
password-compare.attlist &=
|
||||
hash?
|
||||
|
||||
intercept-methods =
|
||||
## Can be used inside a bean definition to add a security interceptor to the bean and set up access configuration attributes for the bean's methods
|
||||
element intercept-methods {intercept-methods.attlist, protect+}
|
||||
intercept-methods.attlist &=
|
||||
## Optional AccessDecisionManager bean ID to be used by the created method security interceptor.
|
||||
attribute access-decision-manager-ref {xsd:token}?
|
||||
|
||||
|
||||
protect =
|
||||
## Defines a protected method and the access control configuration attributes that apply to it. We strongly advise you NOT to mix "protect" declarations with any services provided "global-method-security".
|
||||
element protect {protect.attlist, empty}
|
||||
protect.attlist &=
|
||||
## A method name
|
||||
attribute method {xsd:token}
|
||||
protect.attlist &=
|
||||
## Access configuration attributes list that applies to the method, e.g. "ROLE_A,ROLE_B".
|
||||
attribute access {xsd:token}
|
||||
|
||||
method-security-metadata-source =
|
||||
## Creates a MethodSecurityMetadataSource instance
|
||||
element method-security-metadata-source {msmds.attlist, protect+}
|
||||
msmds.attlist &= id?
|
||||
|
||||
msmds.attlist &= use-expressions?
|
||||
|
||||
global-method-security =
|
||||
## Provides method security for all beans registered in the Spring application context. Specifically, beans will be scanned for matches with the ordered list of "protect-pointcut" sub-elements, Spring Security annotations and/or. Where there is a match, the beans will automatically be proxied and security authorization applied to the methods accordingly. If you use and enable all four sources of method security metadata (ie "protect-pointcut" declarations, expression annotations, @Secured and also JSR250 security annotations), the metadata sources will be queried in that order. In practical terms, this enables you to use XML to override method security metadata expressed in annotations. If using annotations, the order of precedence is EL-based (@PreAuthorize etc.), @Secured and finally JSR-250.
|
||||
element global-method-security {global-method-security.attlist, (pre-post-annotation-handling | expression-handler)?, protect-pointcut*, after-invocation-provider*}
|
||||
global-method-security.attlist &=
|
||||
## Specifies whether the use of Spring Security's pre and post invocation annotations (@PreFilter, @PreAuthorize, @PostFilter, @PostAuthorize) should be enabled for this application context. Defaults to "disabled".
|
||||
attribute pre-post-annotations {"disabled" | "enabled" }?
|
||||
global-method-security.attlist &=
|
||||
## Specifies whether the use of Spring Security's @Secured annotations should be enabled for this application context. Defaults to "disabled".
|
||||
attribute secured-annotations {"disabled" | "enabled" }?
|
||||
global-method-security.attlist &=
|
||||
## Specifies whether JSR-250 style attributes are to be used (for example "RolesAllowed"). This will require the javax.annotation.security classes on the classpath. Defaults to "disabled".
|
||||
attribute jsr250-annotations {"disabled" | "enabled" }?
|
||||
global-method-security.attlist &=
|
||||
## Optional AccessDecisionManager bean ID to override the default used for method security.
|
||||
attribute access-decision-manager-ref {xsd:token}?
|
||||
global-method-security.attlist &=
|
||||
## Optional RunAsmanager implementation which will be used by the configured MethodSecurityInterceptor
|
||||
attribute run-as-manager-ref {xsd:token}?
|
||||
global-method-security.attlist &=
|
||||
## Allows the advice "order" to be set for the method security interceptor.
|
||||
attribute order {xsd:token}?
|
||||
global-method-security.attlist &=
|
||||
## If true, class based proxying will be used instead of interface based proxying.
|
||||
attribute proxy-target-class {xsd:boolean}?
|
||||
global-method-security.attlist &=
|
||||
## Can be used to specify that AspectJ should be used instead of the default Spring AOP. If set, secured classes must be woven with the AnnotationSecurityAspect from the spring-security-aspects module.
|
||||
attribute mode {"aspectj"}?
|
||||
global-method-security.attlist &=
|
||||
## An external MethodSecurityMetadataSource instance can be supplied which will take priority over other sources (such as the default annotations).
|
||||
attribute metadata-source-ref {xsd:token}?
|
||||
global-method-security.attlist &=
|
||||
authentication-manager-ref?
|
||||
|
||||
|
||||
after-invocation-provider =
|
||||
## Allows addition of extra AfterInvocationProvider beans which should be called by the MethodSecurityInterceptor created by global-method-security.
|
||||
element after-invocation-provider {ref}
|
||||
|
||||
pre-post-annotation-handling =
|
||||
## Allows the default expression-based mechanism for handling Spring Security's pre and post invocation annotations (@PreFilter, @PreAuthorize, @PostFilter, @PostAuthorize) to be replace entirely. Only applies if these annotations are enabled.
|
||||
element pre-post-annotation-handling {invocation-attribute-factory, pre-invocation-advice, post-invocation-advice}
|
||||
|
||||
invocation-attribute-factory =
|
||||
## Defines the PrePostInvocationAttributeFactory instance which is used to generate pre and post invocation metadata from the annotated methods.
|
||||
element invocation-attribute-factory {ref}
|
||||
|
||||
pre-invocation-advice =
|
||||
## Customizes the PreInvocationAuthorizationAdviceVoter with the ref as the PreInvocationAuthorizationAdviceVoter for the <pre-post-annotation-handling> element.
|
||||
element pre-invocation-advice {ref}
|
||||
|
||||
post-invocation-advice =
|
||||
## Customizes the PostInvocationAdviceProvider with the ref as the PostInvocationAuthorizationAdvice for the <pre-post-annotation-handling> element.
|
||||
element post-invocation-advice {ref}
|
||||
|
||||
|
||||
expression-handler =
|
||||
## Defines the SecurityExpressionHandler instance which will be used if expression-based access-control is enabled. A default implementation (with no ACL support) will be used if not supplied.
|
||||
element expression-handler {ref}
|
||||
|
||||
protect-pointcut =
|
||||
## Defines a protected pointcut and the access control configuration attributes that apply to it. Every bean registered in the Spring application context that provides a method that matches the pointcut will receive security authorization.
|
||||
element protect-pointcut {protect-pointcut.attlist, empty}
|
||||
protect-pointcut.attlist &=
|
||||
## An AspectJ expression, including the 'execution' keyword. For example, 'execution(int com.foo.TargetObject.countLength(String))' (without the quotes).
|
||||
attribute expression {xsd:string}
|
||||
protect-pointcut.attlist &=
|
||||
## Access configuration attributes list that applies to all methods matching the pointcut, e.g. "ROLE_A,ROLE_B"
|
||||
attribute access {xsd:token}
|
||||
|
||||
http-firewall =
|
||||
## Allows a custom instance of HttpFirewall to be injected into the FilterChainProxy created by the namespace.
|
||||
element http-firewall {ref}
|
||||
|
||||
http =
|
||||
## Container element for HTTP security configuration. Multiple elements can now be defined, each with a specific pattern to which the enclosed security configuration applies. A pattern can also be configured to bypass Spring Security's filters completely by setting the "secured" attribute to "false".
|
||||
element http {http.attlist, (intercept-url* & access-denied-handler? & form-login? & openid-login? & x509? & jee? & http-basic? & logout? & session-management & remember-me? & anonymous? & port-mappings & custom-filter* & request-cache? & expression-handler?) }
|
||||
http.attlist &=
|
||||
## The request URL pattern which will be mapped to the filter chain created by this <http> element. If omitted, the filter chain will match all requests.
|
||||
attribute pattern {xsd:token}?
|
||||
http.attlist &=
|
||||
## When set to 'none', requests matching the pattern attribute will be ignored by Spring Security. No security filters will be applied and no SecurityContext will be available. If set, the <http> element must be empty, with no children.
|
||||
attribute security {"none"}?
|
||||
http.attlist &=
|
||||
## Allows a RequestMatcher instance to be used, as an alternative to pattern-matching.
|
||||
attribute request-matcher-ref { xsd:token }?
|
||||
http.attlist &=
|
||||
## A legacy attribute which automatically registers a login form, BASIC authentication and a logout URL and logout services. If unspecified, defaults to "false". We'd recommend you avoid using this and instead explicitly configure the services you require.
|
||||
attribute auto-config {xsd:boolean}?
|
||||
http.attlist &=
|
||||
use-expressions?
|
||||
http.attlist &=
|
||||
## Controls the eagerness with which an HTTP session is created by Spring Security classes. If not set, defaults to "ifRequired". If "stateless" is used, this implies that the application guarantees that it will not create a session. This differs from the use of "never" which mans that Spring Security will not create a session, but will make use of one if the application does.
|
||||
attribute create-session {"ifRequired" | "always" | "never" | "stateless"}?
|
||||
http.attlist &=
|
||||
## A reference to a SecurityContextRepository bean. This can be used to customize how the SecurityContext is stored between requests.
|
||||
attribute security-context-repository-ref {xsd:token}?
|
||||
http.attlist &=
|
||||
request-matcher?
|
||||
http.attlist &=
|
||||
## Deprecated. Use request-matcher instead.
|
||||
path-type?
|
||||
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 {xsd:boolean}?
|
||||
http.attlist &=
|
||||
## If available, runs the request as the Subject acquired from the JaasAuthenticationToken. Defaults to "false".
|
||||
attribute jaas-api-provision {xsd: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}?
|
||||
http.attlist &=
|
||||
## Optional attribute specifying the realm name that will be used for all authentication features that require a realm name (eg BASIC and Digest authentication). If unspecified, defaults to "Spring Security Application".
|
||||
attribute realm {xsd:token}?
|
||||
http.attlist &=
|
||||
## Allows a customized AuthenticationEntryPoint to be set on the ExceptionTranslationFilter.
|
||||
attribute entry-point-ref {xsd:token}?
|
||||
http.attlist &=
|
||||
## Corresponds to the observeOncePerRequest property of FilterSecurityInterceptor. Defaults to "true"
|
||||
attribute once-per-request {xsd:boolean}?
|
||||
http.attlist &=
|
||||
## Deprecated in favour of the access-denied-handler element.
|
||||
attribute access-denied-page {xsd:token}?
|
||||
http.attlist &=
|
||||
## Prevents the jsessionid parameter from being added to rendered URLs.
|
||||
attribute disable-url-rewriting {xsd:boolean}?
|
||||
http.attlist &=
|
||||
## Exposes the list of filters defined by this configuration under this bean name in the application context.
|
||||
name?
|
||||
http.attlist &=
|
||||
authentication-manager-ref?
|
||||
|
||||
access-denied-handler =
|
||||
## Defines the access-denied strategy that should be used. An access denied page can be defined or a reference to an AccessDeniedHandler instance.
|
||||
element access-denied-handler {access-denied-handler.attlist, empty}
|
||||
access-denied-handler.attlist &= (ref | access-denied-handler-page)
|
||||
|
||||
access-denied-handler-page =
|
||||
## The access denied page that an authenticated user will be redirected to if they request a page which they don't have the authority to access.
|
||||
attribute error-page {xsd:token}
|
||||
|
||||
intercept-url =
|
||||
## Specifies the access attributes and/or filter list for a particular set of URLs.
|
||||
element intercept-url {intercept-url.attlist, empty}
|
||||
intercept-url.attlist &=
|
||||
## The pattern which defines the URL path. The content will depend on the type set in the containing http element, so will default to ant path syntax.
|
||||
attribute pattern {xsd:token}
|
||||
intercept-url.attlist &=
|
||||
## The access configuration attributes that apply for the configured path.
|
||||
attribute access {xsd:token}?
|
||||
intercept-url.attlist &=
|
||||
## The HTTP Method for which the access configuration attributes should apply. If not specified, the attributes will apply to any method.
|
||||
attribute method {"GET" | "DELETE" | "HEAD" | "OPTIONS" | "POST" | "PUT" | "TRACE"}?
|
||||
|
||||
intercept-url.attlist &=
|
||||
## The filter list for the path. Currently can be set to "none" to remove a path from having any filters applied. The full filter stack (consisting of all filters created by the namespace configuration, and any added using 'custom-filter'), will be applied to any other paths.
|
||||
attribute filters {"none"}?
|
||||
intercept-url.attlist &=
|
||||
## Used to specify that a URL must be accessed over http or https, or that there is no preference. The value should be "http", "https" or "any", respectively.
|
||||
attribute requires-channel {xsd:token}?
|
||||
|
||||
logout =
|
||||
## Incorporates a logout processing filter. Most web applications require a logout filter, although you may not require one if you write a controller to provider similar logic.
|
||||
element logout {logout.attlist, empty}
|
||||
logout.attlist &=
|
||||
## Specifies the URL that will cause a logout. Spring Security will initialize a filter that responds to this particular URL. Defaults to /j_spring_security_logout if unspecified.
|
||||
attribute logout-url {xsd:token}?
|
||||
logout.attlist &=
|
||||
## Specifies the URL to display once the user has logged out. If not specified, defaults to /.
|
||||
attribute logout-success-url {xsd:token}?
|
||||
logout.attlist &=
|
||||
## Specifies whether a logout also causes HttpSession invalidation, which is generally desirable. If unspecified, defaults to true.
|
||||
attribute invalidate-session {xsd:boolean}?
|
||||
logout.attlist &=
|
||||
## A reference to a LogoutSuccessHandler implementation which will be used to determine the destination to which the user is taken after logging out.
|
||||
attribute success-handler-ref {xsd:token}?
|
||||
logout.attlist &=
|
||||
## A comma-separated list of the names of cookies which should be deleted when the user logs out
|
||||
attribute delete-cookies {xsd:token}?
|
||||
|
||||
request-cache =
|
||||
## Allow the RequestCache used for saving requests during the login process to be set
|
||||
element request-cache {ref}
|
||||
|
||||
form-login =
|
||||
## Sets up a form login configuration for authentication with a username and password
|
||||
element form-login {form-login.attlist, empty}
|
||||
form-login.attlist &=
|
||||
## The URL that the login form is posted to. If unspecified, it defaults to /j_spring_security_check.
|
||||
attribute login-processing-url {xsd:token}?
|
||||
form-login.attlist &=
|
||||
## The name of the request parameter which contains the username. Defaults to 'j_username'.
|
||||
attribute username-parameter {xsd:token}?
|
||||
form-login.attlist &=
|
||||
## The name of the request parameter which contains the password. Defaults to 'j_password'.
|
||||
attribute password-parameter {xsd:token}?
|
||||
form-login.attlist &=
|
||||
## The URL that will be redirected to after successful authentication, if the user's previous action could not be resumed. This generally happens if the user visits a login page without having first requested a secured operation that triggers authentication. If unspecified, defaults to the root of the application.
|
||||
attribute default-target-url {xsd:token}?
|
||||
form-login.attlist &=
|
||||
## Whether the user should always be redirected to the default-target-url after login.
|
||||
attribute always-use-default-target {xsd:boolean}?
|
||||
form-login.attlist &=
|
||||
## The URL for the login page. If no login URL is specified, Spring Security will automatically create a login URL at /spring_security_login and a corresponding filter to render that login URL when requested.
|
||||
attribute login-page {xsd:token}?
|
||||
form-login.attlist &=
|
||||
## The URL for the login failure page. If no login failure URL is specified, Spring Security will automatically create a failure login URL at /spring_security_login?login_error and a corresponding filter to render that login failure URL when requested.
|
||||
attribute authentication-failure-url {xsd:token}?
|
||||
form-login.attlist &=
|
||||
## Reference to an AuthenticationSuccessHandler bean which should be used to handle a successful authentication request. Should not be used in combination with default-target-url (or always-use-default-target-url) as the implementation should always deal with navigation to the subsequent destination
|
||||
attribute authentication-success-handler-ref {xsd:token}?
|
||||
form-login.attlist &=
|
||||
## Reference to an AuthenticationFailureHandler bean which should be used to handle a failed authentication request. Should not be used in combination with authentication-failure-url as the implementation should always deal with navigation to the subsequent destination
|
||||
attribute authentication-failure-handler-ref {xsd:token}?
|
||||
form-login.attlist &=
|
||||
## Reference to an AuthenticationDetailsSource which will be used by the authentication filter
|
||||
attribute authentication-details-source-ref {xsd:token}?
|
||||
|
||||
|
||||
openid-login =
|
||||
## Sets up form login for authentication with an Open ID identity
|
||||
element openid-login {form-login.attlist, user-service-ref?, attribute-exchange*}
|
||||
|
||||
attribute-exchange =
|
||||
## Sets up an attribute exchange configuration to request specified attributes from the OpenID identity provider. When multiple elements are used, each must have an identifier-attribute attribute. Each configuration will be matched in turn against the supplied login identifier until a match is found.
|
||||
element attribute-exchange {attribute-exchange.attlist, openid-attribute+}
|
||||
|
||||
attribute-exchange.attlist &=
|
||||
## A regular expression which will be compared against the claimed identity, when deciding which attribute-exchange configuration to use during authentication.
|
||||
attribute identifier-match {xsd:token}?
|
||||
|
||||
openid-attribute =
|
||||
## Attributes used when making an OpenID AX Fetch Request
|
||||
element openid-attribute {openid-attribute.attlist}
|
||||
|
||||
openid-attribute.attlist &=
|
||||
## Specifies the name of the attribute that you wish to get back. For example, email.
|
||||
attribute name {xsd:token}
|
||||
openid-attribute.attlist &=
|
||||
## Specifies the attribute type. For example, http://axschema.org/contact/email. See your OP's documentation for valid attribute types.
|
||||
attribute type {xsd:token}
|
||||
openid-attribute.attlist &=
|
||||
## Specifies if this attribute is required to the OP, but does not error out if the OP does not return the attribute. Default is false.
|
||||
attribute required {xsd:boolean}?
|
||||
openid-attribute.attlist &=
|
||||
## Specifies the number of attributes that you wish to get back. For example, return 3 emails. The default value is 1.
|
||||
attribute count {xsd:int}?
|
||||
|
||||
|
||||
filter-chain-map =
|
||||
## Used to explicitly configure a FilterChainProxy instance with a FilterChainMap
|
||||
element filter-chain-map {filter-chain-map.attlist, filter-chain+}
|
||||
filter-chain-map.attlist &=
|
||||
## Deprecated. Use request-matcher instead.
|
||||
path-type?
|
||||
filter-chain-map.attlist &=
|
||||
request-matcher?
|
||||
|
||||
filter-chain =
|
||||
## Used within to define a specific URL pattern and the list of filters which apply to the URLs matching that pattern. When multiple filter-chain elements are assembled in a list in order to configure a FilterChainProxy, the most specific patterns must be placed at the top of the list, with most general ones at the bottom.
|
||||
element filter-chain {filter-chain.attlist, empty}
|
||||
filter-chain.attlist &=
|
||||
(pattern | request-matcher-ref)
|
||||
filter-chain.attlist &=
|
||||
## A comma separated list of bean names that implement Filter that should be processed for this FilterChain. If the value is none, then no Filters will be used for this FilterChain.
|
||||
attribute filters {xsd:token}
|
||||
|
||||
pattern =
|
||||
## The request URL pattern which will be mapped to the FilterChain.
|
||||
attribute pattern {xsd:token}
|
||||
request-matcher-ref =
|
||||
## Allows a RequestMatcher instance to be used, as an alternative to pattern-matching.
|
||||
attribute request-matcher-ref {xsd:token}
|
||||
|
||||
filter-security-metadata-source =
|
||||
## Used to explicitly configure a FilterSecurityMetadataSource bean for use with a FilterSecurityInterceptor. Usually only needed if you are configuring a FilterChainProxy explicitly, rather than using the <http> element. The intercept-url elements used should only contain pattern, method and access attributes. Any others will result in a configuration error.
|
||||
element filter-security-metadata-source {fsmds.attlist, intercept-url+}
|
||||
fsmds.attlist &=
|
||||
use-expressions?
|
||||
fsmds.attlist &=
|
||||
id?
|
||||
fsmds.attlist &=
|
||||
## Compare after forcing to lowercase
|
||||
attribute lowercase-comparisons {xsd:boolean}?
|
||||
fsmds.attlist &=
|
||||
## Deprecate. Use request-matcher instead.
|
||||
path-type?
|
||||
fsmds.attlist &=
|
||||
request-matcher?
|
||||
|
||||
filter-invocation-definition-source =
|
||||
## Deprecated synonym for filter-security-metadata-source
|
||||
element filter-invocation-definition-source {fsmds.attlist, intercept-url+}
|
||||
|
||||
http-basic =
|
||||
## Adds support for basic authentication
|
||||
element http-basic {http-basic.attlist, empty}
|
||||
|
||||
http-basic.attlist &=
|
||||
## Sets the AuthenticationEntryPoint which is used by the BasicAuthenticationFilter.
|
||||
attribute entry-point-ref {xsd:token}?
|
||||
http-basic.attlist &=
|
||||
## Reference to an AuthenticationDetailsSource which will be used by the authentication filter
|
||||
attribute authentication-details-source-ref {xsd:token}?
|
||||
|
||||
session-management =
|
||||
## Session-management related functionality is implemented by the addition of a SessionManagementFilter to the filter stack.
|
||||
element session-management {session-management.attlist, concurrency-control?}
|
||||
|
||||
session-management.attlist &=
|
||||
## Indicates whether an existing session should be invalidated when a user authenticates and a new session started. If set to "none" no change will be made. "newSession" will create a new empty session. "migrateSession" will create a new session and copy the session attributes to the new session. Defaults to "migrateSession".
|
||||
attribute session-fixation-protection {"none" | "newSession" | "migrateSession" }?
|
||||
session-management.attlist &=
|
||||
## The URL to which a user will be redirected if they submit an invalid session indentifier. Typically used to detect session timeouts.
|
||||
attribute invalid-session-url {xsd:token}?
|
||||
session-management.attlist &=
|
||||
## Allows injection of the SessionAuthenticationStrategy instance used by the SessionManagementFilter
|
||||
attribute session-authentication-strategy-ref {xsd:token}?
|
||||
session-management.attlist &=
|
||||
## Defines the URL of the error page which should be shown when the SessionAuthenticationStrategy raises an exception. If not set, an unauthorized (402) error code will be returned to the client. Note that this attribute doesn't apply if the error occurs during a form-based login, where the URL for authentication failure will take precedence.
|
||||
attribute session-authentication-error-url {xsd:token}?
|
||||
|
||||
|
||||
concurrency-control =
|
||||
## Enables concurrent session control, limiting the number of authenticated sessions a user may have at the same time.
|
||||
element concurrency-control {concurrency-control.attlist, empty}
|
||||
|
||||
concurrency-control.attlist &=
|
||||
## The maximum number of sessions a single authenticated user can have open at the same time. Defaults to "1".
|
||||
attribute max-sessions {xsd:positiveInteger}?
|
||||
concurrency-control.attlist &=
|
||||
## The URL a user will be redirected to if they attempt to use a session which has been "expired" because they have logged in again.
|
||||
attribute expired-url {xsd:token}?
|
||||
concurrency-control.attlist &=
|
||||
## Specifies that an unauthorized error should be reported when a user attempts to login when they already have the maximum configured sessions open. The default behaviour is to expire the original session. If the session-authentication-error-url attribute is set on the session-management URL, the user will be redirected to this URL.
|
||||
attribute error-if-maximum-exceeded {xsd:boolean}?
|
||||
concurrency-control.attlist &=
|
||||
## Allows you to define an alias for the SessionRegistry bean in order to access it in your own configuration.
|
||||
attribute session-registry-alias {xsd:token}?
|
||||
concurrency-control.attlist &=
|
||||
## Allows you to define an external SessionRegistry bean to be used by the concurrency control setup.
|
||||
attribute session-registry-ref {xsd:token}?
|
||||
|
||||
|
||||
remember-me =
|
||||
## Sets up remember-me authentication. If used with the "key" attribute (or no attributes) the cookie-only implementation will be used. Specifying "token-repository-ref" or "remember-me-data-source-ref" will use the more secure, persisten token approach.
|
||||
element remember-me {remember-me.attlist}
|
||||
remember-me.attlist &=
|
||||
## The "key" used to identify cookies from a specific token-based remember-me application. You should set this to a unique value for your application. If unset, it will default to a random value generated by SecureRandom.
|
||||
attribute key {xsd:token}?
|
||||
|
||||
remember-me.attlist &=
|
||||
(token-repository-ref | remember-me-data-source-ref | remember-me-services-ref)
|
||||
|
||||
remember-me.attlist &=
|
||||
user-service-ref?
|
||||
|
||||
remember-me.attlist &=
|
||||
## Exports the internally defined RememberMeServices as a bean alias, allowing it to be used by other beans in the application context.
|
||||
attribute services-alias {xsd:token}?
|
||||
|
||||
remember-me.attlist &=
|
||||
## Determines whether the "secure" flag will be set on the remember-me cookie. If set to true, the cookie will only be submitted over HTTPS (recommended). By default, secure cookies will be used if the request is made on a secure connection.
|
||||
attribute use-secure-cookie {xsd:boolean}?
|
||||
|
||||
remember-me.attlist &=
|
||||
## The period (in seconds) for which the remember-me cookie should be valid.
|
||||
attribute token-validity-seconds {xsd:integer}?
|
||||
|
||||
remember-me.attlist &=
|
||||
## Reference to an AuthenticationSuccessHandler bean which should be used to handle a successful remember-me authentication.
|
||||
attribute authentication-success-handler-ref {xsd:token}?
|
||||
remember-me.attlist &=
|
||||
## The name of the request parameter which toggles remember-me authentication. Defaults to '_spring_security_remember_me'.
|
||||
attribute remember-me-parameter {xsd:token}?
|
||||
|
||||
token-repository-ref =
|
||||
## Reference to a PersistentTokenRepository bean for use with the persistent token remember-me implementation.
|
||||
attribute token-repository-ref {xsd:token}
|
||||
remember-me-services-ref =
|
||||
## Allows a custom implementation of RememberMeServices to be used. Note that this implementation should return RememberMeAuthenticationToken instances with the same "key" value as specified in the remember-me element. Alternatively it should register its own AuthenticationProvider. It should also implement the LogoutHandler interface, which will be invoked when a user logs out. Typically the remember-me cookie would be removed on logout.
|
||||
attribute services-ref {xsd:token}?
|
||||
remember-me-data-source-ref =
|
||||
## DataSource bean for the database that contains the token repository schema.
|
||||
data-source-ref
|
||||
|
||||
anonymous =
|
||||
## Adds support for automatically granting all anonymous web requests a particular principal identity and a corresponding granted authority.
|
||||
element anonymous {anonymous.attlist}
|
||||
anonymous.attlist &=
|
||||
## The key shared between the provider and filter. This generally does not need to be set. If unset, it will default to a random value generated by SecureRandom.
|
||||
attribute key {xsd:token}?
|
||||
anonymous.attlist &=
|
||||
## The username that should be assigned to the anonymous request. This allows the principal to be identified, which may be important for logging and auditing. if unset, defaults to "anonymousUser".
|
||||
attribute username {xsd:token}?
|
||||
anonymous.attlist &=
|
||||
## The granted authority that should be assigned to the anonymous request. Commonly this is used to assign the anonymous request particular roles, which can subsequently be used in authorization decisions. If unset, defaults to "ROLE_ANONYMOUS".
|
||||
attribute granted-authority {xsd:token}?
|
||||
anonymous.attlist &=
|
||||
## With the default namespace setup, the anonymous "authentication" facility is automatically enabled. You can disable it using this property.
|
||||
attribute enabled {xsd:boolean}?
|
||||
|
||||
|
||||
port-mappings =
|
||||
## Defines the list of mappings between http and https ports for use in redirects
|
||||
element port-mappings {port-mappings.attlist, port-mapping+}
|
||||
|
||||
port-mappings.attlist &= empty
|
||||
|
||||
port-mapping =
|
||||
## Provides a method to map http ports to https ports when forcing a redirect.
|
||||
element port-mapping {http-port, https-port}
|
||||
|
||||
http-port =
|
||||
## The http port to use.
|
||||
attribute http {xsd:token}
|
||||
|
||||
https-port =
|
||||
## The https port to use.
|
||||
attribute https {xsd:token}
|
||||
|
||||
|
||||
x509 =
|
||||
## Adds support for X.509 client authentication.
|
||||
element x509 {x509.attlist}
|
||||
x509.attlist &=
|
||||
## The regular expression used to obtain the username from the certificate's subject. Defaults to matching on the common name using the pattern "CN=(.*?),".
|
||||
attribute subject-principal-regex {xsd:token}?
|
||||
x509.attlist &=
|
||||
## Explicitly specifies which user-service should be used to load user data for X.509 authenticated clients. If ommitted, the default user-service will be used.
|
||||
user-service-ref?
|
||||
x509.attlist &=
|
||||
## Reference to an AuthenticationDetailsSource which will be used by the authentication filter
|
||||
attribute authentication-details-source-ref {xsd:token}?
|
||||
|
||||
jee =
|
||||
## Adds a J2eePreAuthenticatedProcessingFilter to the filter chain to provide integration with container authentication.
|
||||
element jee {jee.attlist}
|
||||
jee.attlist &=
|
||||
## A comma-separate list of roles to look for in the incoming HttpServletRequest.
|
||||
attribute mappable-roles {xsd:token}
|
||||
jee.attlist &=
|
||||
## Explicitly specifies which user-service should be used to load user data for container authenticated clients. If ommitted, the set of mappable-roles will be used to construct the authorities for the user.
|
||||
user-service-ref?
|
||||
|
||||
authentication-manager =
|
||||
## Registers the AuthenticationManager instance and allows its list of AuthenticationProviders to be defined. Also allows you to define an alias to allow you to reference the AuthenticationManager in your own beans.
|
||||
element authentication-manager {authman.attlist & authentication-provider* & ldap-authentication-provider*}
|
||||
authman.attlist &=
|
||||
id?
|
||||
authman.attlist &=
|
||||
## An alias you wish to use for the AuthenticationManager bean (not required it you are using a specific id)
|
||||
attribute alias {xsd:token}?
|
||||
authman.attlist &=
|
||||
## If set to true, the AuthenticationManger will attempt to clear any credentials data in the returned Authentication object, once the user has been authenticated.
|
||||
attribute erase-credentials {xsd:boolean}?
|
||||
|
||||
authentication-provider =
|
||||
## Indicates that the contained user-service should be used as an authentication source.
|
||||
element authentication-provider {ap.attlist & any-user-service & password-encoder?}
|
||||
ap.attlist &=
|
||||
## Specifies a reference to a separately configured AuthenticationProvider instance which should be registered within the AuthenticationManager.
|
||||
ref?
|
||||
ap.attlist &=
|
||||
## Specifies a reference to a separately configured UserDetailsService from which to obtain authentication data.
|
||||
user-service-ref?
|
||||
|
||||
user-service =
|
||||
## Creates an in-memory UserDetailsService from a properties file or a list of "user" child elements. Usernames are converted to lower-case internally to allow for case-insensitive lookups, so this should not be used if case-sensitivity is required.
|
||||
element user-service {id? & (properties-file | (user*))}
|
||||
properties-file =
|
||||
## The location of a Properties file where each line is in the format of username=password,grantedAuthority[,grantedAuthority][,enabled|disabled]
|
||||
attribute properties {xsd:token}?
|
||||
|
||||
user =
|
||||
## Represents a user in the application.
|
||||
element user {user.attlist, empty}
|
||||
user.attlist &=
|
||||
## The username assigned to the user.
|
||||
attribute name {xsd:token}
|
||||
user.attlist &=
|
||||
## The password assigned to the user. This may be hashed if the corresponding authentication provider supports hashing (remember to set the "hash" attribute of the "user-service" element). This attribute be omitted in the case where the data will not be used for authentication, but only for accessing authorities. If omitted, the namespace will generate a random value, preventing its accidental use for authentication. Cannot be empty.
|
||||
attribute password {xsd:string}?
|
||||
user.attlist &=
|
||||
## One of more authorities granted to the user. Separate authorities with a comma (but no space). For example, "ROLE_USER,ROLE_ADMINISTRATOR"
|
||||
attribute authorities {xsd:token}
|
||||
user.attlist &=
|
||||
## Can be set to "true" to mark an account as locked and unusable.
|
||||
attribute locked {xsd:boolean}?
|
||||
user.attlist &=
|
||||
## Can be set to "true" to mark an account as disabled and unusable.
|
||||
attribute disabled {xsd:boolean}?
|
||||
|
||||
jdbc-user-service =
|
||||
## Causes creation of a JDBC-based UserDetailsService.
|
||||
element jdbc-user-service {id? & jdbc-user-service.attlist}
|
||||
jdbc-user-service.attlist &=
|
||||
## The bean ID of the DataSource which provides the required tables.
|
||||
attribute data-source-ref {xsd:token}
|
||||
jdbc-user-service.attlist &=
|
||||
cache-ref?
|
||||
jdbc-user-service.attlist &=
|
||||
## An SQL statement to query a username, password, and enabled status given a username. Default is "select username,password,enabled from users where username = ?"
|
||||
attribute users-by-username-query {xsd:token}?
|
||||
jdbc-user-service.attlist &=
|
||||
## An SQL statement to query for a user's granted authorities given a username. The default is "select username, authority from authorities where username = ?"
|
||||
attribute authorities-by-username-query {xsd:token}?
|
||||
jdbc-user-service.attlist &=
|
||||
## An SQL statement to query user's group authorities given a username. The default is "select g.id, g.group_name, ga.authority from groups g, group_members gm, group_authorities ga where gm.username = ? and g.id = ga.group_id and g.id = gm.group_id"
|
||||
attribute group-authorities-by-username-query {xsd:token}?
|
||||
jdbc-user-service.attlist &=
|
||||
role-prefix?
|
||||
|
||||
|
||||
any-user-service = user-service | jdbc-user-service | ldap-user-service
|
||||
|
||||
custom-filter =
|
||||
## Used to indicate that a filter bean declaration should be incorporated into the security filter chain.
|
||||
element custom-filter {custom-filter.attlist}
|
||||
|
||||
custom-filter.attlist &=
|
||||
ref
|
||||
|
||||
custom-filter.attlist &=
|
||||
(after | before | position)
|
||||
|
||||
after =
|
||||
## The filter immediately after which the custom-filter should be placed in the chain. This feature will only be needed by advanced users who wish to mix their own filters into the security filter chain and have some knowledge of the standard Spring Security filters. The filter names map to specific Spring Security implementation filters.
|
||||
attribute after {named-security-filter}
|
||||
before =
|
||||
## The filter immediately before which the custom-filter should be placed in the chain
|
||||
attribute before {named-security-filter}
|
||||
position =
|
||||
## The explicit position at which the custom-filter should be placed in the chain. Use if you are replacing a standard filter.
|
||||
attribute position {named-security-filter}
|
||||
|
||||
named-security-filter = "FIRST" | "CHANNEL_FILTER" | "CONCURRENT_SESSION_FILTER" | "SECURITY_CONTEXT_FILTER" | "LOGOUT_FILTER" | "X509_FILTER" | "PRE_AUTH_FILTER" | "CAS_FILTER" | "FORM_LOGIN_FILTER" | "OPENID_FILTER" |"BASIC_AUTH_FILTER" | "SERVLET_API_SUPPORT_FILTER" | "REMEMBER_ME_FILTER" | "ANONYMOUS_FILTER" | "EXCEPTION_TRANSLATION_FILTER" | "SESSION_MANAGEMENT_FILTER" | "FILTER_SECURITY_INTERCEPTOR" | "SWITCH_USER_FILTER" | "LAST"
|
||||
+2321
File diff suppressed because it is too large
Load Diff
@@ -5,8 +5,8 @@
|
||||
|
||||
-->
|
||||
|
||||
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" version="1.0">
|
||||
<xsl:output method="xml" indent="yes"/>
|
||||
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" version="2.0">
|
||||
<xsl:output method="xml" indent="yes"/>
|
||||
|
||||
<xsl:variable name="elts-to-inline">
|
||||
<xsl:text>,access-denied-handler,anonymous,session-management,concurrency-control,after-invocation-provider,authentication-provider,ldap-authentication-provider,user,port-mapping,openid-login,expression-handler,form-login,http-basic,intercept-url,logout,password-encoder,port-mappings,port-mapper,password-compare,protect,protect-pointcut,pre-post-annotation-handling,pre-invocation-advice,post-invocation-advice,invocation-attribute-factory,remember-me,salt-source,x509,</xsl:text>
|
||||
@@ -42,4 +42,10 @@
|
||||
</xsl:copy>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template match="xs:documentation">
|
||||
<xsl:element name="xs:documentation">
|
||||
<xsl:copy-of select="@*" />
|
||||
<xsl:value-of select="replace(concat(normalize-space(text()),' '), '(.{0,90}) ','$1
 ')"/>
|
||||
</xsl:element>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright 2002-2013 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.config.annotation;
|
||||
|
||||
/**
|
||||
* Exists for mocking purposes to ensure that the Type information is found.
|
||||
*
|
||||
* @author Rob Winch
|
||||
*/
|
||||
public interface AnyObjectPostProcessor extends ObjectPostProcessor<Object> {
|
||||
|
||||
}
|
||||
+122
@@ -0,0 +1,122 @@
|
||||
/*
|
||||
* Copyright 2002-2013 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.config.annotation;
|
||||
|
||||
import javax.servlet.Filter
|
||||
|
||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException
|
||||
import org.springframework.context.ConfigurableApplicationContext
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext
|
||||
import org.springframework.mock.web.MockFilterChain
|
||||
import org.springframework.mock.web.MockHttpServletRequest
|
||||
import org.springframework.mock.web.MockHttpServletResponse
|
||||
import org.springframework.security.authentication.AuthenticationManager
|
||||
import org.springframework.security.authentication.AuthenticationProvider
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder
|
||||
import org.springframework.security.core.Authentication
|
||||
import org.springframework.security.core.authority.AuthorityUtils;
|
||||
import org.springframework.security.core.context.SecurityContextHolder
|
||||
import org.springframework.security.core.context.SecurityContextImpl
|
||||
import org.springframework.security.web.FilterChainProxy
|
||||
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor
|
||||
import org.springframework.security.web.context.HttpRequestResponseHolder
|
||||
import org.springframework.security.web.context.HttpSessionSecurityContextRepository
|
||||
|
||||
import spock.lang.AutoCleanup
|
||||
import spock.lang.Specification
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Rob Winch
|
||||
*/
|
||||
abstract class BaseSpringSpec extends Specification {
|
||||
@AutoCleanup
|
||||
ConfigurableApplicationContext context
|
||||
|
||||
MockHttpServletRequest request
|
||||
MockHttpServletResponse response
|
||||
MockFilterChain chain
|
||||
|
||||
def setup() {
|
||||
request = new MockHttpServletRequest(method:"GET")
|
||||
response = new MockHttpServletResponse()
|
||||
chain = new MockFilterChain()
|
||||
}
|
||||
|
||||
AuthenticationManagerBuilder authenticationBldr = new AuthenticationManagerBuilder().inMemoryAuthentication().and()
|
||||
|
||||
def cleanup() {
|
||||
SecurityContextHolder.clearContext()
|
||||
}
|
||||
|
||||
def loadConfig(Class<?>... configs) {
|
||||
context = new AnnotationConfigApplicationContext(configs)
|
||||
context
|
||||
}
|
||||
|
||||
def findFilter(Class<?> filter, int index = 0) {
|
||||
filterChain(index).filters.find { filter.isAssignableFrom(it.class)}
|
||||
}
|
||||
|
||||
def filterChain(int index=0) {
|
||||
filterChains()[index]
|
||||
}
|
||||
|
||||
def filterChains() {
|
||||
context.getBean(FilterChainProxy).filterChains
|
||||
}
|
||||
|
||||
Filter getSpringSecurityFilterChain() {
|
||||
context.getBean("springSecurityFilterChain",Filter.class)
|
||||
}
|
||||
|
||||
AuthenticationManager authenticationManager() {
|
||||
context.getBean(AuthenticationManager)
|
||||
}
|
||||
|
||||
AuthenticationManager getAuthenticationManager() {
|
||||
try {
|
||||
authenticationManager().delegateBuilder.getObject()
|
||||
} catch(NoSuchBeanDefinitionException e) {}
|
||||
findFilter(FilterSecurityInterceptor).authenticationManager
|
||||
}
|
||||
|
||||
List<AuthenticationProvider> authenticationProviders() {
|
||||
List<AuthenticationProvider> providers = new ArrayList<AuthenticationProvider>()
|
||||
AuthenticationManager authenticationManager = getAuthenticationManager()
|
||||
while(authenticationManager?.providers) {
|
||||
providers.addAll(authenticationManager.providers)
|
||||
authenticationManager = authenticationManager.parent
|
||||
}
|
||||
providers
|
||||
}
|
||||
|
||||
AuthenticationProvider findAuthenticationProvider(Class<?> provider) {
|
||||
authenticationProviders().find { provider.isAssignableFrom(it.class) }
|
||||
}
|
||||
|
||||
def login(String username="user", String role="ROLE_USER") {
|
||||
login(new UsernamePasswordAuthenticationToken(username, null, AuthorityUtils.createAuthorityList(role)))
|
||||
}
|
||||
|
||||
def login(Authentication auth) {
|
||||
HttpSessionSecurityContextRepository repo = new HttpSessionSecurityContextRepository()
|
||||
HttpRequestResponseHolder requestResponseHolder = new HttpRequestResponseHolder(request, response)
|
||||
repo.loadContext(requestResponseHolder)
|
||||
repo.saveContext(new SecurityContextImpl(authentication:auth), requestResponseHolder.request, requestResponseHolder.response)
|
||||
}
|
||||
}
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright 2002-2013 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.config.annotation;
|
||||
|
||||
import org.springframework.context.ConfigurableApplicationContext
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
import org.springframework.mock.web.MockFilterChain;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.mock.web.MockHttpServletResponse;
|
||||
import org.springframework.security.core.context.SecurityContextHolder
|
||||
import org.springframework.security.web.FilterChainProxy;
|
||||
|
||||
import spock.lang.AutoCleanup
|
||||
import spock.lang.Specification
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Rob Winch
|
||||
*/
|
||||
abstract class BaseWebSpecuritySpec extends BaseSpringSpec {
|
||||
FilterChainProxy springSecurityFilterChain
|
||||
MockHttpServletRequest request
|
||||
MockHttpServletResponse response
|
||||
MockFilterChain chain
|
||||
|
||||
def setup() {
|
||||
request = new MockHttpServletRequest()
|
||||
response = new MockHttpServletResponse()
|
||||
chain = new MockFilterChain()
|
||||
}
|
||||
|
||||
|
||||
def loadConfig(Class<?>... configs) {
|
||||
super.loadConfig(configs)
|
||||
springSecurityFilterChain = context.getBean(FilterChainProxy)
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright 2002-2013 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.config.annotation;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Rob Winch
|
||||
*
|
||||
*/
|
||||
class ConcereteSecurityConfigurerAdapter extends SecurityConfigurerAdapter<Object, SecurityBuilder<Object>> {
|
||||
private List<Object> list = new ArrayList<Object>();
|
||||
|
||||
@Override
|
||||
public void configure(SecurityBuilder<Object> builder) throws Exception {
|
||||
list = postProcess(list);
|
||||
}
|
||||
|
||||
public ConcereteSecurityConfigurerAdapter list(List<Object> l) {
|
||||
this.list = l;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright 2002-2013 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.config.annotation;
|
||||
|
||||
import static org.fest.assertions.Assertions.assertThat;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* @author Rob Winch
|
||||
*
|
||||
*/
|
||||
public class ObjectPostProcessorTests {
|
||||
|
||||
@Test
|
||||
public void convertTypes() {
|
||||
assertThat((Object)PerformConversion.perform(new ArrayList<Object>())).isInstanceOf(LinkedList.class);
|
||||
}
|
||||
}
|
||||
|
||||
class ListToLinkedListObjectPostProcessor implements ObjectPostProcessor<List<?>>{
|
||||
|
||||
@Override
|
||||
public <O extends List<?>> O postProcess(O l) {
|
||||
return (O) new LinkedList(l);
|
||||
}
|
||||
}
|
||||
|
||||
class PerformConversion {
|
||||
public static List<?> perform(ArrayList<?> l) {
|
||||
return new ListToLinkedListObjectPostProcessor().postProcess(l);
|
||||
}
|
||||
}
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright 2002-2013 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.config.annotation
|
||||
|
||||
import spock.lang.Specification
|
||||
|
||||
/**
|
||||
* @author Rob Winch
|
||||
*
|
||||
*/
|
||||
class SecurityConfigurerAdapterTests extends Specification {
|
||||
ConcereteSecurityConfigurerAdapter conf = new ConcereteSecurityConfigurerAdapter()
|
||||
|
||||
def "addPostProcessor closure"() {
|
||||
setup:
|
||||
SecurityBuilder<Object> builder = Mock()
|
||||
conf.addObjectPostProcessor({ List l ->
|
||||
l.add("a")
|
||||
l
|
||||
} as ObjectPostProcessor<List>)
|
||||
when:
|
||||
conf.init(builder)
|
||||
conf.configure(builder)
|
||||
then:
|
||||
conf.list.contains("a")
|
||||
}
|
||||
}
|
||||
+90
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Copyright 2002-2013 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.config.annotation.authentication
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.authentication.AuthenticationEventPublisher
|
||||
import org.springframework.security.authentication.AuthenticationManager
|
||||
import org.springframework.security.authentication.AuthenticationProvider
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.config.annotation.BaseSpringSpec
|
||||
import org.springframework.security.config.annotation.ObjectPostProcessor
|
||||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
import org.springframework.security.core.Authentication;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Rob Winch
|
||||
*
|
||||
*/
|
||||
class AuthenticationManagerBuilderTests extends BaseSpringSpec {
|
||||
def "add(AuthenticationProvider) does not perform registration"() {
|
||||
setup:
|
||||
ObjectPostProcessor opp = Mock()
|
||||
AuthenticationProvider provider = Mock()
|
||||
AuthenticationManagerBuilder builder = new AuthenticationManagerBuilder().objectPostProcessor(opp)
|
||||
when: "Adding an AuthenticationProvider"
|
||||
builder.authenticationProvider(provider)
|
||||
builder.build()
|
||||
then: "AuthenticationProvider is not passed into LifecycleManager (it should be managed externally)"
|
||||
0 * opp._(_ as AuthenticationProvider)
|
||||
}
|
||||
|
||||
// https://github.com/SpringSource/spring-security-javaconfig/issues/132
|
||||
def "#132 Custom AuthenticationEventPublisher with Web registerAuthentication"() {
|
||||
setup:
|
||||
AuthenticationEventPublisher aep = Mock()
|
||||
when:
|
||||
AuthenticationManager am = new AuthenticationManagerBuilder()
|
||||
.authenticationEventPublisher(aep)
|
||||
.inMemoryAuthentication()
|
||||
.and()
|
||||
.build()
|
||||
then:
|
||||
am.eventPublisher == aep
|
||||
}
|
||||
|
||||
def "authentication-manager support multiple DaoAuthenticationProvider's"() {
|
||||
setup:
|
||||
loadConfig(MultiAuthenticationProvidersConfig)
|
||||
when:
|
||||
Authentication auth = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("user","password"))
|
||||
then:
|
||||
auth.name == "user"
|
||||
auth.authorities*.authority == ['ROLE_USER']
|
||||
when:
|
||||
auth = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("admin","password"))
|
||||
then:
|
||||
auth.name == "admin"
|
||||
auth.authorities*.authority.sort() == ['ROLE_ADMIN','ROLE_USER']
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
@Configuration
|
||||
static class MultiAuthenticationProvidersConfig extends WebSecurityConfigurerAdapter {
|
||||
protected void registerAuthentication(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth
|
||||
.inMemoryAuthentication()
|
||||
.withUser("user").password("password").roles("USER").and()
|
||||
.and()
|
||||
.inMemoryAuthentication()
|
||||
.withUser("admin").password("password").roles("USER","ADMIN")
|
||||
}
|
||||
}
|
||||
}
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright 2002-2013 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.config.annotation.authentication
|
||||
|
||||
import java.rmi.registry.Registry;
|
||||
|
||||
import org.springframework.context.annotation.Bean
|
||||
import org.springframework.context.annotation.Configuration
|
||||
import org.springframework.security.authentication.AuthenticationManager
|
||||
import org.springframework.security.config.annotation.authentication.AuthenticationManagerBuilder
|
||||
import org.springframework.security.config.annotation.authentication.configurers.userdetails.UserDetailsServiceConfigurer;
|
||||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
||||
import org.springframework.security.config.annotation.authentication.configurers.provisioning.InMemoryUserDetailsManagerConfigurer;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Rob Winch
|
||||
*/
|
||||
@Configuration
|
||||
class BaseAuthenticationConfig {
|
||||
protected void registerAuthentication(
|
||||
AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth
|
||||
.inMemoryAuthentication()
|
||||
.withUser("user").password("password").roles("USER").and()
|
||||
.withUser("admin").password("password").roles("USER", "ADMIN").and()
|
||||
}
|
||||
|
||||
@Bean
|
||||
public AuthenticationManager authenticationManager() {
|
||||
AuthenticationManagerBuilder registry = new AuthenticationManagerBuilder();
|
||||
registerAuthentication(registry);
|
||||
return registry.build();
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user