|
@@ -2025,7 +2025,7 @@ The object returned by the call to `getContext()` is an instance of the `Securit
|
|
|
|
|
|
[[tech-userdetailsservice]]
|
|
|
==== The UserDetailsService
|
|
|
-Another item to note from the above code fragment is that you can obtain a principal from the `Authentication` object. The principal is just an `Object`. Most of the time this can be cast into a `UserDetails` object. `UserDetails` is a core interface in Spring Security. It represents a principal, but in an extensible and application-specific way. Think of `UserDetails` as the adapter between your own user database and what Spring Security needs inside the `SecurityContextHolder`. Being a representation of something from your own user database, quite often you will cast the `UserDetails` to the original object that your application provided, so you can call business-specific methods (like`getEmail()`, `getEmployeeNumber()` and so on).
|
|
|
+Another item to note from the above code fragment is that you can obtain a principal from the `Authentication` object. The principal is just an `Object`. Most of the time this can be cast into a `UserDetails` object. `UserDetails` is a core interface in Spring Security. It represents a principal, but in an extensible and application-specific way. Think of `UserDetails` as the adapter between your own user database and what Spring Security needs inside the `SecurityContextHolder`. Being a representation of something from your own user database, quite often you will cast the `UserDetails` to the original object that your application provided, so you can call business-specific methods (like `getEmail()`, `getEmployeeNumber()` and so on).
|
|
|
|
|
|
By now you're probably wondering, so when do I provide a `UserDetails` object? How do I do that? I thought you said this thing was declarative and I didn't need to write any Java code - what gives? The short answer is that there is a special interface called `UserDetailsService`. The only method on this interface accepts a `String`-based username argument and returns a `UserDetails`:
|
|
|
|
|
@@ -2261,7 +2261,7 @@ Each supported secure object type has its own interceptor class, which is a subc
|
|
|
|
|
|
[[tech-intro-config-attributes]]
|
|
|
===== What are Configuration Attributes?
|
|
|
-A "configuration attribute" can be thought of as a String that has special meaning to the classes used by `AbstractSecurityInterceptor`. They are represented by the interface `ConfigAttribute` within the framework. They may be simple role names or have more complex meaning, depending on the how sophisticated the `AccessDecisionManager` implementation is. The `AbstractSecurityInterceptor` is configured with a `SecurityMetadataSource` which it uses to look up the attributes for a secure object. Usually this configuration will be hidden from the user. Configuration attributes will be entered as annotations on secured methods or as access attributes on secured URLs. For example, when we saw something like `<intercept-url pattern='/secure/**' access='ROLE_A,ROLE_B'/>` in the namespace introduction, this is saying that the configuration attributes `ROLE_A` and `ROLE_B` apply to web requests matching the given pattern. In practice, with the default `AccessDecisionManager` configuration, this means that anyone who has a `GrantedAuthority` matching either of these two attributes will be allowed access. Strictly speaking though, they are just attributes and the interpretation is dependent on the `AccessDecisionManager` implementation. The use of the prefix `ROLE_` is a marker to indicate that these attributes are roles and should be consumed by Spring Security's`RoleVoter`. This is only relevant when a voter-based `AccessDecisionManager` is in use. We'll see how the `AccessDecisionManager` is implemented in the <<authz-arch,authorization chapter>>.
|
|
|
+A "configuration attribute" can be thought of as a String that has special meaning to the classes used by `AbstractSecurityInterceptor`. They are represented by the interface `ConfigAttribute` within the framework. They may be simple role names or have more complex meaning, depending on the how sophisticated the `AccessDecisionManager` implementation is. The `AbstractSecurityInterceptor` is configured with a `SecurityMetadataSource` which it uses to look up the attributes for a secure object. Usually this configuration will be hidden from the user. Configuration attributes will be entered as annotations on secured methods or as access attributes on secured URLs. For example, when we saw something like `<intercept-url pattern='/secure/**' access='ROLE_A,ROLE_B'/>` in the namespace introduction, this is saying that the configuration attributes `ROLE_A` and `ROLE_B` apply to web requests matching the given pattern. In practice, with the default `AccessDecisionManager` configuration, this means that anyone who has a `GrantedAuthority` matching either of these two attributes will be allowed access. Strictly speaking though, they are just attributes and the interpretation is dependent on the `AccessDecisionManager` implementation. The use of the prefix `ROLE_` is a marker to indicate that these attributes are roles and should be consumed by Spring Security's `RoleVoter`. This is only relevant when a voter-based `AccessDecisionManager` is in use. We'll see how the `AccessDecisionManager` is implemented in the <<authz-arch,authorization chapter>>.
|
|
|
|
|
|
|
|
|
===== RunAsManager
|
|
@@ -2287,7 +2287,7 @@ Spring Security supports localization of exception messages that end users are l
|
|
|
|
|
|
All exception messages can be localized, including messages related to authentication failures and access being denied (authorization failures). Exceptions and logging messages that are focused on developers or system deployers (including incorrect attributes, interface contract violations, using incorrect constructors, startup time validation, debug-level logging) are not localized and instead are hard-coded in English within Spring Security's code.
|
|
|
|
|
|
-Shipping in the `spring-security-core-xx.jar` you will find an `org.springframework.security` package that in turn contains a `messages.properties` file, as well as localized versions for some common languages. This should be referred to by your`ApplicationContext`, as Spring Security classes implement Spring's `MessageSourceAware` interface and expect the message resolver to be dependency injected at application context startup time. Usually all you need to do is register a bean inside your application context to refer to the messages. An example is shown below:
|
|
|
+Shipping in the `spring-security-core-xx.jar` you will find an `org.springframework.security` package that in turn contains a `messages.properties` file, as well as localized versions for some common languages. This should be referred to by your `ApplicationContext`, as Spring Security classes implement Spring's `MessageSourceAware` interface and expect the message resolver to be dependency injected at application context startup time. Usually all you need to do is register a bean inside your application context to refer to the messages. An example is shown below:
|
|
|
|
|
|
[source,xml]
|
|
|
----
|
|
@@ -2301,7 +2301,7 @@ The `messages.properties` is named in accordance with standard resource bundles
|
|
|
|
|
|
If you wish to customize the `messages.properties` file, or support other languages, you should copy the file, rename it accordingly, and register it inside the above bean definition. There are not a large number of message keys inside this file, so localization should not be considered a major initiative. If you do perform localization of this file, please consider sharing your work with the community by logging a JIRA task and attaching your appropriately-named localized version of `messages.properties`.
|
|
|
|
|
|
-Spring Security relies on Spring's localization support in order to actually lookup the appropriate message. In order for this to work, you have to make sure that the locale from the incoming request is stored in Spring's `org.springframework.context.i18n.LocaleContextHolder`. Spring MVC's `DispatcherServlet` does this for your application automatically, but since Spring Security's filters are invoked before this, the `LocaleContextHolder` needs to be set up to contain the correct `Locale` before the filters are called. You can either do this in a filter yourself (which must come before the Spring Security filters in`web.xml`) or you can use Spring's `RequestContextFilter`. Please refer to the Spring Framework documentation for further details on using localization with Spring.
|
|
|
+Spring Security relies on Spring's localization support in order to actually lookup the appropriate message. In order for this to work, you have to make sure that the locale from the incoming request is stored in Spring's `org.springframework.context.i18n.LocaleContextHolder`. Spring MVC's `DispatcherServlet` does this for your application automatically, but since Spring Security's filters are invoked before this, the `LocaleContextHolder` needs to be set up to contain the correct `Locale` before the filters are called. You can either do this in a filter yourself (which must come before the Spring Security filters in `web.xml`) or you can use Spring's `RequestContextFilter`. Please refer to the Spring Framework documentation for further details on using localization with Spring.
|
|
|
|
|
|
The "contacts" sample application is set up to use localized messages.
|
|
|
|
|
@@ -2371,7 +2371,7 @@ As mentioned in the earlier in this reference guide, most authentication provide
|
|
|
UserDetails loadUserByUsername(String username) throws UsernameNotFoundException;
|
|
|
----
|
|
|
|
|
|
-The returned `UserDetails` is an interface that provides getters that guarantee non-null provision of authentication information such as the username, password, granted authorities and whether the user account is enabled or disabled. Most authentication providers will use a`UserDetailsService`, even if the username and password are not actually used as part of the authentication decision. They may use the returned `UserDetails` object just for its `GrantedAuthority` information, because some other system (like LDAP or X.509 or CAS etc) has undertaken the responsibility of actually validating the credentials.
|
|
|
+The returned `UserDetails` is an interface that provides getters that guarantee non-null provision of authentication information such as the username, password, granted authorities and whether the user account is enabled or disabled. Most authentication providers will use a `UserDetailsService`, even if the username and password are not actually used as part of the authentication decision. They may use the returned `UserDetails` object just for its `GrantedAuthority` information, because some other system (like LDAP or X.509 or CAS etc) has undertaken the responsibility of actually validating the credentials.
|
|
|
|
|
|
Given `UserDetailsService` is so simple to implement, it should be easy for users to retrieve authentication information using a persistence strategy of their choice. Having said that, Spring Security does include a couple of useful base implementations, which we'll look at below.
|
|
|
|
|
@@ -2561,7 +2561,7 @@ The Servlet Specification defines several properties for the `HttpServletRequest
|
|
|
|
|
|
As mentioned above, the default strategy is to use Ant-style paths for matching and this is likely to be the best choice for most users. The strategy is implemented in the class `AntPathRequestMatcher` which uses Spring's `AntPathMatcher` to perform a case-insensitive match of the pattern against the concatenated `servletPath` and `pathInfo`, ignoring the `queryString`.
|
|
|
|
|
|
-If for some reason, you need a more powerful matching strategy, you can use regular expressions. The strategy implementation is then`RegexRequestMatcher`. See the Javadoc for this class for more information.
|
|
|
+If for some reason, you need a more powerful matching strategy, you can use regular expressions. The strategy implementation is then `RegexRequestMatcher`. See the Javadoc for this class for more information.
|
|
|
|
|
|
In practice we recommend that you use method security at your service layer, to control access to your application, and do not rely entirely on the use of security constraints defined at the web-application level. URLs change and it is difficult to take account of all the possible URLs that an application might support and how requests might be manipulated. You should try and restrict yourself to using a few simple ant paths which are simple to understand. Always try to use a"deny-by-default" approach where you have a catch-all wildcard ( /** or **) defined last and denying access.
|
|
|
|
|
@@ -2602,7 +2602,7 @@ There are some key filters which will always be used in a web application which
|
|
|
|
|
|
[[filter-security-interceptor]]
|
|
|
=== FilterSecurityInterceptor
|
|
|
-We've already seen `FilterSecurityInterceptor` briefly when discussing <<tech-intro-access-control,access-control in general>>, and we've already used it with the namespace where the `<intercept-url>` elements are combined to configure it internally. Now we'll see how to explicitly configure it for use with a`FilterChainProxy`, along with its companion filter `ExceptionTranslationFilter`. A typical configuration example is shown below:
|
|
|
+We've already seen `FilterSecurityInterceptor` briefly when discussing <<tech-intro-access-control,access-control in general>>, and we've already used it with the namespace where the `<intercept-url>` elements are combined to configure it internally. Now we'll see how to explicitly configure it for use with a `FilterChainProxy`, along with its companion filter `ExceptionTranslationFilter`. A typical configuration example is shown below:
|
|
|
|
|
|
[source,xml]
|
|
|
----
|
|
@@ -2621,9 +2621,9 @@ We've already seen `FilterSecurityInterceptor` briefly when discussing <<tech-in
|
|
|
|
|
|
`FilterSecurityInterceptor` is responsible for handling the security of HTTP resources. It requires a reference to an `AuthenticationManager` and an `AccessDecisionManager`. It is also supplied with configuration attributes that apply to different HTTP URL requests. Refer back to <<tech-intro-config-attributes,the original discussion on these>> in the technical introduction.
|
|
|
|
|
|
-The `FilterSecurityInterceptor` can be configured with configuration attributes in two ways. The first, which is shown above, is using the `<filter-security-metadata-source>` namespace element. This is similar to the `<http>` element from the namespace chapter but the `<intercept-url>` child elements only use the `pattern` and `access` attributes. Commas are used to delimit the different configuration attributes that apply to each HTTP URL. The second option is to write your own`SecurityMetadataSource`, but this is beyond the scope of this document. Irrespective of the approach used, the `SecurityMetadataSource` is responsible for returning a `List<ConfigAttribute>` containing all of the configuration attributes associated with a single secure HTTP URL.
|
|
|
+The `FilterSecurityInterceptor` can be configured with configuration attributes in two ways. The first, which is shown above, is using the `<filter-security-metadata-source>` namespace element. This is similar to the `<http>` element from the namespace chapter but the `<intercept-url>` child elements only use the `pattern` and `access` attributes. Commas are used to delimit the different configuration attributes that apply to each HTTP URL. The second option is to write your own `SecurityMetadataSource`, but this is beyond the scope of this document. Irrespective of the approach used, the `SecurityMetadataSource` is responsible for returning a `List<ConfigAttribute>` containing all of the configuration attributes associated with a single secure HTTP URL.
|
|
|
|
|
|
-It should be noted that the `FilterSecurityInterceptor.setSecurityMetadataSource()` method actually expects an instance of `FilterInvocationSecurityMetadataSource`. This is a marker interface which subclasses`SecurityMetadataSource`. It simply denotes the `SecurityMetadataSource` understands `FilterInvocation` s. In the interests of simplicity we'll continue to refer to the `FilterInvocationSecurityMetadataSource` as a `SecurityMetadataSource`, as the distinction is of little relevance to most users.
|
|
|
+It should be noted that the `FilterSecurityInterceptor.setSecurityMetadataSource()` method actually expects an instance of `FilterInvocationSecurityMetadataSource`. This is a marker interface which subclasses `SecurityMetadataSource`. It simply denotes the `SecurityMetadataSource` understands `FilterInvocation` s. In the interests of simplicity we'll continue to refer to the `FilterInvocationSecurityMetadataSource` as a `SecurityMetadataSource`, as the distinction is of little relevance to most users.
|
|
|
|
|
|
The `SecurityMetadataSource` created by the namespace syntax obtains the configuration attributes for a particular `FilterInvocation` by matching the request URL against the configured `pattern` attributes. This behaves in the same way as it does for namespace configuration. The default is to treat all expressions as Apache Ant paths and regular expressions are also supported for more complex cases. The `request-matcher` attribute is used to specify the type of pattern being used. It is not possible to mix expression syntaxes within the same definition. As an example, the previous configuration using regular expressions instead of Ant paths would be written as follows:
|
|
|
|
|
@@ -2725,7 +2725,7 @@ void saveContext(SecurityContext context, HttpServletRequest request,
|
|
|
|
|
|
The `HttpRequestResponseHolder` is simply a container for the incoming request and response objects, allowing the implementation to replace these with wrapper classes. The returned contents will be passed to the filter chain.
|
|
|
|
|
|
-The default implementation is `HttpSessionSecurityContextRepository`, which stores the security context as an `HttpSession` attribute footnote:[In Spring Security 2.0 and earlier, this filter was called `HttpSessionContextIntegrationFilter` and performed all the work of storing the context was performed by the filter itself. If you were familiar with this class, then most of the configuration options which were available can now be found on`HttpSessionSecurityContextRepository`.]. The most important configuration parameter for this implementation is the `allowSessionCreation` property, which defaults to `true`, thus allowing the class to create a session if it needs one to store the security context for an authenticated user (it won't create one unless authentication has taken place and the contents of the security context have changed). If you don't want a session to be created, then you can set this property to `false`:
|
|
|
+The default implementation is `HttpSessionSecurityContextRepository`, which stores the security context as an `HttpSession` attribute footnote:[In Spring Security 2.0 and earlier, this filter was called `HttpSessionContextIntegrationFilter` and performed all the work of storing the context was performed by the filter itself. If you were familiar with this class, then most of the configuration options which were available can now be found on `HttpSessionSecurityContextRepository`.]. The most important configuration parameter for this implementation is the `allowSessionCreation` property, which defaults to `true`, thus allowing the class to create a session if it needs one to store the security context for an authenticated user (it won't create one unless authentication has taken place and the contents of the security context have changed). If you don't want a session to be created, then you can set this property to `false`:
|
|
|
|
|
|
[source,xml]
|
|
|
----
|
|
@@ -2970,7 +2970,7 @@ class="org.springframework.security.web.authentication.www.BasicAuthenticationEn
|
|
|
</bean>
|
|
|
----
|
|
|
|
|
|
-The configured `AuthenticationManager` processes each authentication request. If authentication fails, the configured `AuthenticationEntryPoint` will be used to retry the authentication process. Usually you will use the filter in combination with a`BasicAuthenticationEntryPoint`, which returns a 401 response with a suitable header to retry HTTP Basic authentication. If authentication is successful, the resulting `Authentication` object will be placed into the `SecurityContextHolder` as usual.
|
|
|
+The configured `AuthenticationManager` processes each authentication request. If authentication fails, the configured `AuthenticationEntryPoint` will be used to retry the authentication process. Usually you will use the filter in combination with a `BasicAuthenticationEntryPoint`, which returns a 401 response with a suitable header to retry HTTP Basic authentication. If authentication is successful, the resulting `Authentication` object will be placed into the `SecurityContextHolder` as usual.
|
|
|
|
|
|
If the authentication event was successful, or authentication was not attempted because the HTTP header did not contain a supported authentication request, the filter chain will continue as normal. The only time the filter chain will be interrupted is if authentication fails and the `AuthenticationEntryPoint` is called.
|
|
|
|
|
@@ -3042,7 +3042,7 @@ This approach uses hashing to achieve a useful remember-me strategy. In essence
|
|
|
base64(username + ":" + expirationTime + ":" +
|
|
|
md5Hex(username + ":" + expirationTime + ":" password + ":" + key))
|
|
|
|
|
|
-username: As identifiable to the `UserDetailsService`
|
|
|
+username: As identifiable to the UserDetailsService
|
|
|
password: That matches the one in the retrieved UserDetails
|
|
|
expirationTime: The date and time when the remember-me token expires, expressed in milliseconds
|
|
|
key: A private key to prevent modification of the remember-me token
|
|
@@ -4132,10 +4132,10 @@ HTTP session related functonality is handled by a combination of the `SessionMan
|
|
|
|
|
|
=== SessionManagementFilter
|
|
|
The `SessionManagementFilter` checks the contents of the `SecurityContextRepository` against the current contents of the `SecurityContextHolder` to determine whether a user has been authenticated during the current request, typically by a non-interactive authentication mechanism, such as pre-authentication or remember-me footnote:[
|
|
|
-Authentication by mechanisms which perform a redirect after authenticating (such as form-login) will not be detected by`SessionManagementFilter`, as the filter will not be invoked during the authenticating request. Session-management functionality has to be handled separately in these cases.
|
|
|
+Authentication by mechanisms which perform a redirect after authenticating (such as form-login) will not be detected by `SessionManagementFilter`, as the filter will not be invoked during the authenticating request. Session-management functionality has to be handled separately in these cases.
|
|
|
]. If the repository contains a security context, the filter does nothing. If it doesn't, and the thread-local `SecurityContext` contains a (non-anonymous) `Authentication` object, the filter assumes they have been authenticated by a previous filter in the stack. It will then invoke the configured `SessionAuthenticationStrategy`.
|
|
|
|
|
|
-If the user is not currently authenticated, the filter will check whether an invalid session ID has been requested (because of a timeout, for example) and will invoke the configured`InvalidSessionStrategy`, if one is set. The most common behaviour is just to redirect to a fixed URL and this is encapsulated in the standard implementation`SimpleRedirectInvalidSessionStrategy`. The latter is also used when configuring an invalid session URL through the namespace,<<ns-session-mgmt,as described earlier>>.
|
|
|
+If the user is not currently authenticated, the filter will check whether an invalid session ID has been requested (because of a timeout, for example) and will invoke the configured `InvalidSessionStrategy`, if one is set. The most common behaviour is just to redirect to a fixed URL and this is encapsulated in the standard implementation `SimpleRedirectInvalidSessionStrategy`. The latter is also used when configuring an invalid session URL through the namespace,<<ns-session-mgmt,as described earlier>>.
|
|
|
|
|
|
|
|
|
=== SessionAuthenticationStrategy
|
|
@@ -4376,7 +4376,7 @@ boolean supports(ConfigAttribute attribute);
|
|
|
boolean supports(Class clazz);
|
|
|
----
|
|
|
|
|
|
-The `AccessDecisionManager`'s `decide` method is passed all the relevant information it needs in order to make an authorization decision. In particular, passing the secure `Object` enables those arguments contained in the actual secure object invocation to be inspected. For example, let's assume the secure object was a`MethodInvocation`. It would be easy to query the `MethodInvocation` for any `Customer` argument, and then implement some sort of security logic in the `AccessDecisionManager` to ensure the principal is permitted to operate on that customer. Implementations are expected to throw an `AccessDeniedException` if access is denied.
|
|
|
+The ``AccessDecisionManager``'s `decide` method is passed all the relevant information it needs in order to make an authorization decision. In particular, passing the secure `Object` enables those arguments contained in the actual secure object invocation to be inspected. For example, let's assume the secure object was a `MethodInvocation`. It would be easy to query the `MethodInvocation` for any `Customer` argument, and then implement some sort of security logic in the `AccessDecisionManager` to ensure the principal is permitted to operate on that customer. Implementations are expected to throw an `AccessDeniedException` if access is denied.
|
|
|
|
|
|
The `supports(ConfigAttribute)` method is called by the `AbstractSecurityInterceptor` at startup time to determine if the `AccessDecisionManager` can process the passed `ConfigAttribute`. The `supports(Class)` method is called by a security interceptor implementation to ensure the configured `AccessDecisionManager` supports the type of secure object that the security interceptor will present.
|
|
|
|
|
@@ -4441,7 +4441,7 @@ image::images/after-invocation.png[]
|
|
|
|
|
|
Like many other parts of Spring Security, `AfterInvocationManager` has a single concrete implementation, `AfterInvocationProviderManager`, which polls a list of `AfterInvocationProvider` s. Each `AfterInvocationProvider` is allowed to modify the return object or throw an `AccessDeniedException`. Indeed multiple providers can modify the object, as the result of the previous provider is passed to the next in the list.
|
|
|
|
|
|
-Please be aware that if you're using `AfterInvocationManager`, you will still need configuration attributes that allow the `MethodSecurityInterceptor`'s `AccessDecisionManager` to allow an operation. If you're using the typical Spring Security included `AccessDecisionManager` implementations, having no configuration attributes defined for a particular secure method invocation will cause each `AccessDecisionVoter` to abstain from voting. In turn, if the `AccessDecisionManager` property "`allowIfAllAbstainDecisions`" is `false`, an `AccessDeniedException` will be thrown. You may avoid this potential issue by either (i) setting "`allowIfAllAbstainDecisions`" to `true` (although this is generally not recommended) or (ii) simply ensure that there is at least one configuration attribute that an `AccessDecisionVoter` will vote to grant access for. This latter (recommended) approach is usually achieved through a `ROLE_USER` or `ROLE_AUTHENTICATED` configuration attribute.
|
|
|
+Please be aware that if you're using `AfterInvocationManager`, you will still need configuration attributes that allow the ``MethodSecurityInterceptor``'s `AccessDecisionManager` to allow an operation. If you're using the typical Spring Security included `AccessDecisionManager` implementations, having no configuration attributes defined for a particular secure method invocation will cause each `AccessDecisionVoter` to abstain from voting. In turn, if the `AccessDecisionManager` property "`allowIfAllAbstainDecisions`" is `false`, an `AccessDeniedException` will be thrown. You may avoid this potential issue by either (i) setting "`allowIfAllAbstainDecisions`" to `true` (although this is generally not recommended) or (ii) simply ensure that there is at least one configuration attribute that an `AccessDecisionVoter` will vote to grant access for. This latter (recommended) approach is usually achieved through a `ROLE_USER` or `ROLE_AUTHENTICATED` configuration attribute.
|
|
|
|
|
|
|
|
|
[[authz-hierarchical-roles]]
|
|
@@ -4528,7 +4528,7 @@ Let's first consider how the `AspectJSecurityInterceptor` is configured in the S
|
|
|
----
|
|
|
|
|
|
|
|
|
-As you can see, aside from the class name, the `AspectJSecurityInterceptor` is exactly the same as the AOP Alliance security interceptor. Indeed the two interceptors can share the same`securityMetadataSource`, as the `SecurityMetadataSource` works with `java.lang.reflect.Method` s rather than an AOP library-specific class. Of course, your access decisions have access to the relevant AOP library-specific invocation (ie `MethodInvocation` or `JoinPoint`) and as such can consider a range of addition criteria when making access decisions (such as method arguments).
|
|
|
+As you can see, aside from the class name, the `AspectJSecurityInterceptor` is exactly the same as the AOP Alliance security interceptor. Indeed the two interceptors can share the same `securityMetadataSource`, as the `SecurityMetadataSource` works with `java.lang.reflect.Method` s rather than an AOP library-specific class. Of course, your access decisions have access to the relevant AOP library-specific invocation (ie `MethodInvocation` or `JoinPoint`) and as such can consider a range of addition criteria when making access decisions (such as method arguments).
|
|
|
|
|
|
Next you'll need to define an AspectJ `aspect`. For example:
|
|
|
|
|
@@ -4908,7 +4908,7 @@ To use `hasPermission()` expressions, you have to explicitly configure a `Permis
|
|
|
</bean>
|
|
|
----
|
|
|
|
|
|
-Where `myPermissionEvaluator` is the bean which implements `PermissionEvaluator`. Usually this will be the implementation from the ACL module which is called`AclPermissionEvaluator`. See the "Contacts" sample application configuration for more details.
|
|
|
+Where `myPermissionEvaluator` is the bean which implements `PermissionEvaluator`. Usually this will be the implementation from the ACL module which is called `AclPermissionEvaluator`. See the "Contacts" sample application configuration for more details.
|
|
|
|
|
|
===== Method Security Meta Annotations
|
|
|
|
|
@@ -4947,7 +4947,7 @@ Complex applications often will find the need to define access permissions not s
|
|
|
Imagine you're designing an application for a pet clinic. There will be two main groups of users of your Spring-based application: staff of the pet clinic, as well as the pet clinic's customers. The staff will have access to all of the data, whilst your customers will only be able to see their own customer records. To make it a little more interesting, your customers can allow other users to see their customer records, such as their "puppy preschool" mentor or president of their local "Pony Club". Using Spring Security as the foundation, you have several approaches that can be used:
|
|
|
|
|
|
* Write your business methods to enforce the security. You could consult a collection within the `Customer` domain object instance to determine which users have access. By using the `SecurityContextHolder.getContext().getAuthentication()`, you'll be able to access the `Authentication` object.
|
|
|
-* Write an `AccessDecisionVoter` to enforce the security from the `GrantedAuthority[]` s stored in the `Authentication` object. This would mean your `AuthenticationManager` would need to populate the `Authentication` with custom `GrantedAuthority`[]s representing each of the `Customer` domain object instances the principal has access to.
|
|
|
+* Write an `AccessDecisionVoter` to enforce the security from the `GrantedAuthority[]` s stored in the `Authentication` object. This would mean your `AuthenticationManager` would need to populate the `Authentication` with custom ``GrantedAuthority[]``s representing each of the `Customer` domain object instances the principal has access to.
|
|
|
* Write an `AccessDecisionVoter` to enforce the security and open the target `Customer` domain object directly. This would mean your voter needs access to a DAO that allows it to retrieve the `Customer` object. It would then access the `Customer` object's collection of approved users and make the appropriate decision.
|
|
|
|
|
|
|
|
@@ -4992,7 +4992,7 @@ Now that we've provided a basic overview of what the ACL system does, and what i
|
|
|
|
|
|
* `Acl`: Every domain object has one and only one `Acl` object, which internally holds the `AccessControlEntry` s as well as knows the owner of the `Acl`. An Acl does not refer directly to the domain object, but instead to an `ObjectIdentity`. The `Acl` is stored in the ACL_OBJECT_IDENTITY table.
|
|
|
|
|
|
-* `AccessControlEntry`: An `Acl` holds multiple `AccessControlEntry` s, which are often abbreviated as ACEs in the framework. Each ACE refers to a specific tuple of`Permission`, `Sid` and `Acl`. An ACE can also be granting or non-granting and contain audit settings. The ACE is stored in the ACL_ENTRY table.
|
|
|
+* `AccessControlEntry`: An `Acl` holds multiple `AccessControlEntry` s, which are often abbreviated as ACEs in the framework. Each ACE refers to a specific tuple of `Permission`, `Sid` and `Acl`. An ACE can also be granting or non-granting and contain audit settings. The ACE is stored in the ACL_ENTRY table.
|
|
|
|
|
|
* `Permission`: A permission represents a particular immutable bit mask, and offers convenience functions for bit masking and outputting information. The basic permissions presented above (bits 0 through 4) are contained in the `BasePermission` class.
|
|
|
|
|
@@ -5017,7 +5017,7 @@ To get starting using Spring Security's ACL capability, you will need to store y
|
|
|
|
|
|
Once you've created the required schema and instantiated `JdbcMutableAclService`, you'll next need to ensure your domain model supports interoperability with the Spring Security ACL package. Hopefully `ObjectIdentityImpl` will prove sufficient, as it provides a large number of ways in which it can be used. Most people will have domain objects that contain a `public Serializable getId()` method. If the return type is long, or compatible with long (eg an int), you will find you need not give further consideration to `ObjectIdentity` issues. Many parts of the ACL module rely on long identifiers. If you're not using long (or an int, byte etc), there is a very good chance you'll need to reimplement a number of classes. We do not intend to support non-long identifiers in Spring Security's ACL module, as longs are already compatible with all database sequences, the most common identifier data type, and are of sufficient length to accommodate all common usage scenarios.
|
|
|
|
|
|
-The following fragment of code shows how to create an `Acl`, or modify an existing`Acl`:
|
|
|
+The following fragment of code shows how to create an `Acl`, or modify an existing `Acl`:
|
|
|
|
|
|
[source,java]
|
|
|
----
|
|
@@ -5170,7 +5170,7 @@ When using LDAP authentication, it is important to ensure that you configure LDA
|
|
|
=== Using LDAP with Spring Security
|
|
|
LDAP authentication in Spring Security can be roughly divided into the following stages.
|
|
|
|
|
|
-* Obtaining the unique LDAP "Distinguished Name", or DN, from the login name. This will often mean performing a search in the directory, unless the exact mapping of usernames to DNs is known in advance. So a user might enter the name "joe" when logging in, but the actual name used to authenticate to LDAP will be the full DN, such as`uid=joe,ou=users,dc=spring,dc=io`.
|
|
|
+* Obtaining the unique LDAP "Distinguished Name", or DN, from the login name. This will often mean performing a search in the directory, unless the exact mapping of usernames to DNs is known in advance. So a user might enter the name "joe" when logging in, but the actual name used to authenticate to LDAP will be the full DN, such as `uid=joe,ou=users,dc=spring,dc=io`.
|
|
|
|
|
|
* Authenticating the user, either by "binding" as that user or by performing a remote "compare" operation of the user's password against the password attribute in the directory entry for the DN.
|
|
|
|
|
@@ -5229,8 +5229,8 @@ If used with the server definition above, this would perform a search under the
|
|
|
How authorities are loaded from groups in the LDAP directory is controlled by the following attributes.
|
|
|
|
|
|
* `group-search-base`. Defines the part of the directory tree under which group searches should be performed.
|
|
|
-* `group-role-attribute`. The attribute which contains the name of the authority defined by the group entry. Defaults to`cn`
|
|
|
-* `group-search-filter`. The filter which is used to search for group membership. The default is`uniqueMember={0}`, corresponding to the `groupOfUniqueNames` LDAP class footnote:[Note that this is different from the default configuration of the underlying `DefaultLdapAuthoritiesPopulator` which uses `member={0}`.]. In this case, the substituted parameter is the full distinguished name of the user. The parameter `{1}` can be used if you want to filter on the login name.
|
|
|
+* `group-role-attribute`. The attribute which contains the name of the authority defined by the group entry. Defaults to `cn`
|
|
|
+* `group-search-filter`. The filter which is used to search for group membership. The default is `uniqueMember={0}`, corresponding to the `groupOfUniqueNames` LDAP class footnote:[Note that this is different from the default configuration of the underlying `DefaultLdapAuthoritiesPopulator` which uses `member={0}`.]. In this case, the substituted parameter is the full distinguished name of the user. The parameter `{1}` can be used if you want to filter on the login name.
|
|
|
|
|
|
So if we used the following configuration
|
|
|
|
|
@@ -5240,7 +5240,7 @@ So if we used the following configuration
|
|
|
group-search-base="ou=groups" />
|
|
|
----
|
|
|
|
|
|
-and authenticated successfully as user "ben", the subsequent loading of authorities would perform a search under the directory entry`ou=groups,dc=springframework,dc=org`, looking for entries which contain the attribute `uniqueMember` with value `uid=ben,ou=people,dc=springframework,dc=org`. By default the authority names will have the prefix `ROLE_` prepended. You can change this using the `role-prefix` attribute. If you don't want any prefix, use `role-prefix="none"`. For more information on loading authorities, see the Javadoc for the `DefaultLdapAuthoritiesPopulator` class.
|
|
|
+and authenticated successfully as user "ben", the subsequent loading of authorities would perform a search under the directory entry `ou=groups,dc=springframework,dc=org`, looking for entries which contain the attribute `uniqueMember` with value `uid=ben,ou=people,dc=springframework,dc=org`. By default the authority names will have the prefix `ROLE_` prepended. You can change this using the `role-prefix` attribute. If you don't want any prefix, use `role-prefix="none"`. For more information on loading authorities, see the Javadoc for the `DefaultLdapAuthoritiesPopulator` class.
|
|
|
|
|
|
=== Implementation Classes
|
|
|
The namespace configuration options we've used above are simple to use and much more concise than using Spring beans explicitly. There are situations when you may need to know how to configure Spring Security LDAP directly in your application context. You may wish to customize the behaviour of some of the classes, for example. If you're happy using namespace configuration then you can skip this section and the next one.
|
|
@@ -5260,7 +5260,7 @@ There are currently two authentication strategies supplied with Spring Security:
|
|
|
|
|
|
[[ldap-ldap-authenticators-common]]
|
|
|
===== Common Functionality
|
|
|
-Before it is possible to authenticate a user (by either strategy), the distinguished name (DN) has to be obtained from the login name supplied to the application. This can be done either by simple pattern-matching (by setting the `setUserDnPatterns` array property) or by setting the `userSearch` property. For the DN pattern-matching approach, a standard Java pattern format is used, and the login name will be substituted for the parameter `{0}`. The pattern should be relative to the DN that the configured `SpringSecurityContextSource` will bind to (see the section on <<ldap-context-source,connecting to the LDAP server>> for more information on this). For example, if you are using an LDAP server with the URL`ldap://monkeymachine.co.uk/dc=springframework,dc=org`, and have a pattern `uid={0},ou=greatapes`, then a login name of "gorilla" will map to a DN`uid=gorilla,ou=greatapes,dc=springframework,dc=org`. Each configured DN pattern will be tried in turn until a match is found. For information on using a search, see the section on <<ldap-searchobjects,search objects>> below. A combination of the two approaches can also be used - the patterns will be checked first and if no matching DN is found, the search will be used.
|
|
|
+Before it is possible to authenticate a user (by either strategy), the distinguished name (DN) has to be obtained from the login name supplied to the application. This can be done either by simple pattern-matching (by setting the `setUserDnPatterns` array property) or by setting the `userSearch` property. For the DN pattern-matching approach, a standard Java pattern format is used, and the login name will be substituted for the parameter `{0}`. The pattern should be relative to the DN that the configured `SpringSecurityContextSource` will bind to (see the section on <<ldap-context-source,connecting to the LDAP server>> for more information on this). For example, if you are using an LDAP server with the URL `ldap://monkeymachine.co.uk/dc=springframework,dc=org`, and have a pattern `uid={0},ou=greatapes`, then a login name of "gorilla" will map to a DN `uid=gorilla,ou=greatapes,dc=springframework,dc=org`. Each configured DN pattern will be tried in turn until a match is found. For information on using a search, see the section on <<ldap-searchobjects,search objects>> below. A combination of the two approaches can also be used - the patterns will be checked first and if no matching DN is found, the search will be used.
|
|
|
|
|
|
|
|
|
[[ldap-ldap-authenticators-bind]]
|
|
@@ -5328,7 +5328,7 @@ A typical configuration, using some of the beans we've discussed here, might loo
|
|
|
</bean>
|
|
|
----
|
|
|
|
|
|
-This would set up the provider to access an LDAP server with URL `ldap://monkeymachine:389/dc=springframework,dc=org`. Authentication will be performed by attempting to bind with the DN`uid=<user-login-name>,ou=people,dc=springframework,dc=org`. After successful authentication, roles will be assigned to the user by searching under the DN `ou=groups,dc=springframework,dc=org` with the default filter `(member=<user's-DN>)`. The role name will be taken from the "ou" attribute of each match.
|
|
|
+This would set up the provider to access an LDAP server with URL `ldap://monkeymachine:389/dc=springframework,dc=org`. Authentication will be performed by attempting to bind with the DN `uid=<user-login-name>,ou=people,dc=springframework,dc=org`. After successful authentication, roles will be assigned to the user by searching under the DN `ou=groups,dc=springframework,dc=org` with the default filter `(member=<user's-DN>)`. The role name will be taken from the "ou" attribute of each match.
|
|
|
|
|
|
To configure a user search object, which uses the filter `(uid=<user-login-name>)` for use instead of the DN-pattern (or in addition to it), you would configure the following bean
|
|
|
|
|
@@ -5361,7 +5361,7 @@ void mapUserToContext(UserDetails user, DirContextAdapter ctx);
|
|
|
}
|
|
|
----
|
|
|
|
|
|
-Only the first method is relevant for authentication. If you provide an implementation of this interface and inject it into the `LdapAuthenticationProvider`, you have control over exactly how the UserDetails object is created. The first parameter is an instance of Spring LDAP's `DirContextOperations` which gives you access to the LDAP attributes which were loaded during authentication. the `username` parameter is the name used to authenticate and the final parameter is the collection of authorities loaded for the user by the configured`LdapAuthoritiesPopulator`.
|
|
|
+Only the first method is relevant for authentication. If you provide an implementation of this interface and inject it into the `LdapAuthenticationProvider`, you have control over exactly how the UserDetails object is created. The first parameter is an instance of Spring LDAP's `DirContextOperations` which gives you access to the LDAP attributes which were loaded during authentication. the `username` parameter is the name used to authenticate and the final parameter is the collection of authorities loaded for the user by the configured `LdapAuthoritiesPopulator`.
|
|
|
|
|
|
The way the context data is loaded varies slightly depending on the type of authentication you are using. With the `BindAuthenticator`, the context returned from the bind operation will be used to read the attributes, otherwise the data will be read using the standard context obtained from the configured `ContextSource` (when a search is configured to locate the user, this will be the data returned by the search object).
|
|
|
|
|
@@ -5741,7 +5741,7 @@ The basic interaction between a web browser, CAS server and a Spring Security-se
|
|
|
* The `Cas20TicketValidator` will parse the XML received from the CAS server. It will return to the `CasAuthenticationProvider` a `TicketResponse`, which includes the username (mandatory), proxy list (if any were involved), and proxy-granting ticket IOU (if the proxy callback was requested).
|
|
|
* Next `CasAuthenticationProvider` will call a configured `CasProxyDecider`. The `CasProxyDecider` indicates whether the proxy list in the `TicketResponse` is acceptable to the service. Several implementations are provided with Spring Security: `RejectProxyTickets`, `AcceptAnyCasProxy` and `NamedCasProxyDecider`. These names are largely self-explanatory, except `NamedCasProxyDecider` which allows a `List` of trusted proxies to be provided.
|
|
|
* `CasAuthenticationProvider` will next request a `AuthenticationUserDetailsService` to load the `GrantedAuthority` objects that apply to the user contained in the `Assertion`.
|
|
|
-* If there were no problems, `CasAuthenticationProvider` constructs a `CasAuthenticationToken` including the details contained in the `TicketResponse` and the `GrantedAuthority`s.
|
|
|
+* If there were no problems, `CasAuthenticationProvider` constructs a `CasAuthenticationToken` including the details contained in the `TicketResponse` and the ``GrantedAuthority``s.
|
|
|
* Control then returns to `CasAuthenticationFilter`, which places the created `CasAuthenticationToken` in the security context.
|
|
|
* The user's browser is redirected to the original page that caused the `AuthenticationException` (or a <<form-login-flow-handling,custom destination>> depending on the configuration).
|
|
|
|
|
@@ -6354,7 +6354,7 @@ executor.execute(originalRunnable);
|
|
|
The code performs the following steps:
|
|
|
|
|
|
* Creates the `SecurityContext` to be used for our `DelegatingSecurityContextExecutor`. Note that in this example we simply create the `SecurityContext` by hand. However, it does not matter where or how we get the `SecurityContext` (i.e. we could obtain it from the `SecurityContextHolder` if we wanted).
|
|
|
-* Creates a delegateExecutor that is in charge of executing submitted `Runnable`s
|
|
|
+* Creates a delegateExecutor that is in charge of executing submitted ``Runnable``s
|
|
|
* Finally we create a `DelegatingSecurityContextExecutor` which is in charge of wrapping any Runnable that is passed into the execute method with a `DelegatingSecurityContextRunnable`. It then passes the wrapped Runnable to the delegateExecutor. In this instance, the same `SecurityContext` will be used for every Runnable submitted to our `DelegatingSecurityContextExecutor`. This is nice if we are running background tasks that need to be run by a user with elevated privileges.
|
|
|
* At this point you may be asking yourself "How does this shield my code of any knowledge of Spring Security?" Instead of creating the `SecurityContext` and the `DelegatingSecurityContextExecutor` in our own code, we can inject an already initialized instance of `DelegatingSecurityContextExecutor`.
|
|
|
|
|
@@ -6373,7 +6373,7 @@ executor.execute(originalRunnable);
|
|
|
}
|
|
|
----
|
|
|
|
|
|
-Now our code is unaware that the `SecurityContext` is being propagated to the `Thread`, then the `originalRunnable` is executed, and then the `SecurityContextHolder` is cleared out. In this example, the same user is being used to execute each Thread. What if we wanted to use the user from `SecurityContextHolder` at the time we invoked `executor.execute(Runnable)` (i.e. the currently logged in user) to process `originalRunnable`? This can be done by removing the `SecurityContext` argument from our `DelegatingSecurityContextExecutor` constructor. For example:
|
|
|
+Now our code is unaware that the `SecurityContext` is being propagated to the `Thread`, then the `originalRunnable` is executed, and then the `SecurityContextHolder` is cleared out. In this example, the same user is being used to execute each Thread. What if we wanted to use the user from `SecurityContextHolder` at the time we invoked `executor.execute(Runnable)` (i.e. the currently logged in user) to process ``originalRunnable``? This can be done by removing the `SecurityContext` argument from our `DelegatingSecurityContextExecutor` constructor. For example:
|
|
|
|
|
|
|
|
|
[source,java]
|
|
@@ -7120,7 +7120,7 @@ The access denied page that an authenticated user will be redirected to if they
|
|
|
|
|
|
[[nsa-access-denied-handler-ref]]
|
|
|
* **ref**
|
|
|
-Defines a reference to a Spring bean of type `AccessDeniedHandler `.
|
|
|
+Defines a reference to a Spring bean of type `AccessDeniedHandler`.
|
|
|
|
|
|
|
|
|
[[nsa-headers]]
|
|
@@ -8424,7 +8424,7 @@ Unless used with a `ref` attribute, this element is shorthand for configuring a
|
|
|
|
|
|
[[nsa-authentication-provider-ref]]
|
|
|
* **ref**
|
|
|
-Defines a reference to a Spring bean that implements `AuthenticationProvider `.
|
|
|
+Defines a reference to a Spring bean that implements `AuthenticationProvider`.
|
|
|
|
|
|
If you have written your own `AuthenticationProvider` implementation (or want to configure one of Spring Security's own implementations as a traditional bean for some reason, then you can use the following syntax to add it to the internal list of `ProviderManager`:
|
|
|
|
|
@@ -8563,7 +8563,7 @@ Defines the hashing algorithm used on user passwords. We recommend strongly agai
|
|
|
|
|
|
[[nsa-password-encoder-ref]]
|
|
|
* **ref**
|
|
|
-Defines a reference to a Spring bean that implements `PasswordEncoder `.
|
|
|
+Defines a reference to a Spring bean that implements `PasswordEncoder`.
|
|
|
|
|
|
|
|
|
[[nsa-password-encoder-children]]
|
|
@@ -8779,7 +8779,7 @@ This element can be used to decorate an `AfterInvocationProvider` for use by the
|
|
|
|
|
|
[[nsa-after-invocation-provider-ref]]
|
|
|
* **ref**
|
|
|
-Defines a reference to a Spring bean that implements ` AfterInvocationProvider`.
|
|
|
+Defines a reference to a Spring bean that implements `AfterInvocationProvider`.
|
|
|
|
|
|
|
|
|
[[nsa-pre-post-annotation-handling]]
|
|
@@ -9047,22 +9047,22 @@ This element is shorthand for the creation of an `LdapAuthenticationProvider` in
|
|
|
|
|
|
[[nsa-ldap-authentication-provider-group-role-attribute]]
|
|
|
* **group-role-attribute**
|
|
|
-The LDAP attribute name which contains the role name which will be used within Spring Security. Maps to the `DefaultLdapAuthoritiesPopulator`'s `groupRoleAttribute` property. Defaults to "cn".
|
|
|
+The LDAP attribute name which contains the role name which will be used within Spring Security. Maps to the ``DefaultLdapAuthoritiesPopulator``'s `groupRoleAttribute` property. Defaults to "cn".
|
|
|
|
|
|
|
|
|
[[nsa-ldap-authentication-provider-group-search-base]]
|
|
|
* **group-search-base**
|
|
|
-Search base for group membership searches. Maps to the `DefaultLdapAuthoritiesPopulator`'s `groupSearchBase` constructor argument. Defaults to "" (searching from the root).
|
|
|
+Search base for group membership searches. Maps to the ``DefaultLdapAuthoritiesPopulator``'s `groupSearchBase` constructor argument. Defaults to "" (searching from the root).
|
|
|
|
|
|
|
|
|
[[nsa-ldap-authentication-provider-group-search-filter]]
|
|
|
* **group-search-filter**
|
|
|
-Group search filter. Maps to the `DefaultLdapAuthoritiesPopulator`'s `groupSearchFilter` property. Defaults to (uniqueMember={0}). The substituted parameter is the DN of the user.
|
|
|
+Group search filter. Maps to the ``DefaultLdapAuthoritiesPopulator``'s `groupSearchFilter` property. Defaults to (uniqueMember={0}). The substituted parameter is the DN of the user.
|
|
|
|
|
|
|
|
|
[[nsa-ldap-authentication-provider-role-prefix]]
|
|
|
* **role-prefix**
|
|
|
-A non-empty string prefix that will be added to role strings loaded from persistent. Maps to the `DefaultLdapAuthoritiesPopulator`'s `rolePrefix` property. Defaults to "ROLE_". Use the value "none" for no prefix in cases where the default is non-empty.
|
|
|
+A non-empty string prefix that will be added to role strings loaded from persistent. Maps to the ``DefaultLdapAuthoritiesPopulator``'s `rolePrefix` property. Defaults to "ROLE_". Use the value "none" for no prefix in cases where the default is non-empty.
|
|
|
|
|
|
|
|
|
[[nsa-ldap-authentication-provider-server-ref]]
|