Extract top level section of reference

Issue: gh-2567
This commit is contained in:
Rob Winch 2018-03-05 16:10:47 -06:00
parent e799f13ae2
commit 86465026a1
8 changed files with 13347 additions and 13325 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,647 @@
[[overall-architecture]]
= Architecture and Implementation
Once you are familiar with setting up and running some namespace-configuration based applications, you may wish to develop more of an understanding of how the framework actually works behind the namespace facade.
Like most software, Spring Security has certain central interfaces, classes and conceptual abstractions that are commonly used throughout the framework.
In this part of the reference guide we will look at some of these and see how they work together to support authentication and access-control within Spring Security.
[[technical-overview]]
== Technical Overview
[[runtime-environment]]
=== Runtime Environment
Spring Security 3.0 requires a Java 5.0 Runtime Environment or higher.
As Spring Security aims to operate in a self-contained manner, there is no need to place any special configuration files into your Java Runtime Environment.
In particular, there is no need to configure a special Java Authentication and Authorization Service (JAAS) policy file or place Spring Security into common classpath locations.
Similarly, if you are using an EJB Container or Servlet Container there is no need to put any special configuration files anywhere, nor include Spring Security in a server classloader.
All the required files will be contained within your application.
This design offers maximum deployment time flexibility, as you can simply copy your target artifact (be it a JAR, WAR or EAR) from one system to another and it will immediately work.
[[core-components]]
=== Core Components
In Spring Security 3.0, the contents of the `spring-security-core` jar were stripped down to the bare minimum.
It no longer contains any code related to web-application security, LDAP or namespace configuration.
We'll take a look here at some of the Java types that you'll find in the core module.
They represent the building blocks of the framework, so if you ever need to go beyond a simple namespace configuration then it's important that you understand what they are, even if you don't actually need to interact with them directly.
==== SecurityContextHolder, SecurityContext and Authentication Objects
The most fundamental object is `SecurityContextHolder`.
This is where we store details of the present security context of the application, which includes details of the principal currently using the application.
By default the `SecurityContextHolder` uses a `ThreadLocal` to store these details, which means that the security context is always available to methods in the same thread of execution, even if the security context is not explicitly passed around as an argument to those methods.
Using a `ThreadLocal` in this way is quite safe if care is taken to clear the thread after the present principal's request is processed.
Of course, Spring Security takes care of this for you automatically so there is no need to worry about it.
Some applications aren't entirely suitable for using a `ThreadLocal`, because of the specific way they work with threads.
For example, a Swing client might want all threads in a Java Virtual Machine to use the same security context.
`SecurityContextHolder` can be configured with a strategy on startup to specify how you would like the context to be stored.
For a standalone application you would use the `SecurityContextHolder.MODE_GLOBAL` strategy.
Other applications might want to have threads spawned by the secure thread also assume the same security identity.
This is achieved by using `SecurityContextHolder.MODE_INHERITABLETHREADLOCAL`.
You can change the mode from the default `SecurityContextHolder.MODE_THREADLOCAL` in two ways.
The first is to set a system property, the second is to call a static method on `SecurityContextHolder`.
Most applications won't need to change from the default, but if you do, take a look at the JavaDoc for `SecurityContextHolder` to learn more.
===== Obtaining information about the current user
Inside the `SecurityContextHolder` we store details of the principal currently interacting with the application.
Spring Security uses an `Authentication` object to represent this information.
You won't normally need to create an `Authentication` object yourself, but it is fairly common for users to query the `Authentication` object.
You can use the following code block - from anywhere in your application - to obtain the name of the currently authenticated user, for example:
[source,java]
----
Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
if (principal instanceof UserDetails) {
String username = ((UserDetails)principal).getUsername();
} else {
String username = principal.toString();
}
----
The object returned by the call to `getContext()` is an instance of the `SecurityContext` interface.
This is the object that is kept in thread-local storage.
As we'll see below, most authentication mechanisms within Spring Security return an instance of `UserDetails` as the principal.
[[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).
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`:
[source,java]
----
UserDetails loadUserByUsername(String username) throws UsernameNotFoundException;
----
This is the most common approach to loading information for a user within Spring Security and you will see it used throughout the framework whenever information on a user is required.
On successful authentication, `UserDetails` is used to build the `Authentication` object that is stored in the `SecurityContextHolder` (more on this <<tech-intro-authentication,below>>).
The good news is that we provide a number of `UserDetailsService` implementations, including one that uses an in-memory map (`InMemoryDaoImpl`) and another that uses JDBC (`JdbcDaoImpl`).
Most users tend to write their own, though, with their implementations often simply sitting on top of an existing Data Access Object (DAO) that represents their employees, customers, or other users of the application.
Remember the advantage that whatever your `UserDetailsService` returns can always be obtained from the `SecurityContextHolder` using the above code fragment.
[NOTE]
====
There is often some confusion about `UserDetailsService`.
It is purely a DAO for user data and performs no other function other than to supply that data to other components within the framework.
In particular, it __does not__ authenticate the user, which is done by the `AuthenticationManager`.
In many cases it makes more sense to <<core-services-authentication-manager,implement `AuthenticationProvider`>> directly if you require a custom authentication process.
====
[[tech-granted-authority]]
==== GrantedAuthority
Besides the principal, another important method provided by `Authentication` is `getAuthorities()`.
This method provides an array of `GrantedAuthority` objects.
A `GrantedAuthority` is, not surprisingly, an authority that is granted to the principal.
Such authorities are usually "roles", such as `ROLE_ADMINISTRATOR` or `ROLE_HR_SUPERVISOR`.
These roles are later on configured for web authorization, method authorization and domain object authorization.
Other parts of Spring Security are capable of interpreting these authorities, and expect them to be present.
`GrantedAuthority` objects are usually loaded by the `UserDetailsService`.
Usually the `GrantedAuthority` objects are application-wide permissions.
They are not specific to a given domain object.
Thus, you wouldn't likely have a `GrantedAuthority` to represent a permission to `Employee` object number 54, because if there are thousands of such authorities you would quickly run out of memory (or, at the very least, cause the application to take a long time to authenticate a user).
Of course, Spring Security is expressly designed to handle this common requirement, but you'd instead use the project's domain object security capabilities for this purpose.
==== Summary
Just to recap, the major building blocks of Spring Security that we've seen so far are:
* `SecurityContextHolder`, to provide access to the `SecurityContext`.
* `SecurityContext`, to hold the `Authentication` and possibly request-specific security information.
* `Authentication`, to represent the principal in a Spring Security-specific manner.
* `GrantedAuthority`, to reflect the application-wide permissions granted to a principal.
* `UserDetails`, to provide the necessary information to build an Authentication object from your application's DAOs or other source of security data.
* `UserDetailsService`, to create a `UserDetails` when passed in a `String`-based username (or certificate ID or the like).
Now that you've gained an understanding of these repeatedly-used components, let's take a closer look at the process of authentication.
[[tech-intro-authentication]]
=== Authentication
Spring Security can participate in many different authentication environments.
While we recommend people use Spring Security for authentication and not integrate with existing Container Managed Authentication, it is nevertheless supported - as is integrating with your own proprietary authentication system.
==== What is authentication in Spring Security?
Let's consider a standard authentication scenario that everyone is familiar with.
. A user is prompted to log in with a username and password.
. The system (successfully) verifies that the password is correct for the username.
. The context information for that user is obtained (their list of roles and so on).
. A security context is established for the user
. The user proceeds, potentially to perform some operation which is potentially protected by an access control mechanism which checks the required permissions for the operation against the current security context information.
The first three items constitute the authentication process so we'll take a look at how these take place within Spring Security.
. The username and password are obtained and combined into an instance of `UsernamePasswordAuthenticationToken` (an instance of the `Authentication` interface, which we saw earlier).
. The token is passed to an instance of `AuthenticationManager` for validation.
. The `AuthenticationManager` returns a fully populated `Authentication` instance on successful authentication.
. The security context is established by calling `SecurityContextHolder.getContext().setAuthentication(...)`, passing in the returned authentication object.
From that point on, the user is considered to be authenticated.
Let's look at some code as an example.
[source,java]
----
import org.springframework.security.authentication.*;
import org.springframework.security.core.*;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
public class AuthenticationExample {
private static AuthenticationManager am = new SampleAuthenticationManager();
public static void main(String[] args) throws Exception {
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
while(true) {
System.out.println("Please enter your username:");
String name = in.readLine();
System.out.println("Please enter your password:");
String password = in.readLine();
try {
Authentication request = new UsernamePasswordAuthenticationToken(name, password);
Authentication result = am.authenticate(request);
SecurityContextHolder.getContext().setAuthentication(result);
break;
} catch(AuthenticationException e) {
System.out.println("Authentication failed: " + e.getMessage());
}
}
System.out.println("Successfully authenticated. Security context contains: " +
SecurityContextHolder.getContext().getAuthentication());
}
}
class SampleAuthenticationManager implements AuthenticationManager {
static final List<GrantedAuthority> AUTHORITIES = new ArrayList<GrantedAuthority>();
static {
AUTHORITIES.add(new SimpleGrantedAuthority("ROLE_USER"));
}
public Authentication authenticate(Authentication auth) throws AuthenticationException {
if (auth.getName().equals(auth.getCredentials())) {
return new UsernamePasswordAuthenticationToken(auth.getName(),
auth.getCredentials(), AUTHORITIES);
}
throw new BadCredentialsException("Bad Credentials");
}
}
----
Here we have written a little program that asks the user to enter a username and password and performs the above sequence.
The `AuthenticationManager` which we've implemented here will authenticate any user whose username and password are the same.
It assigns a single role to every user.
The output from the above will be something like:
[source,txt]
----
Please enter your username:
bob
Please enter your password:
password
Authentication failed: Bad Credentials
Please enter your username:
bob
Please enter your password:
bob
Successfully authenticated. Security context contains: \
org.springframework.security.authentication.UsernamePasswordAuthenticationToken@441d0230: \
Principal: bob; Password: [PROTECTED]; \
Authenticated: true; Details: null; \
Granted Authorities: ROLE_USER
----
Note that you don't normally need to write any code like this.
The process will normally occur internally, in a web authentication filter for example.
We've just included the code here to show that the question of what actually constitutes authentication in Spring Security has quite a simple answer.
A user is authenticated when the `SecurityContextHolder` contains a fully populated `Authentication` object.
==== Setting the SecurityContextHolder Contents Directly
In fact, Spring Security doesn't mind how you put the `Authentication` object inside the `SecurityContextHolder`.
The only critical requirement is that the `SecurityContextHolder` contains an `Authentication` which represents a principal before the `AbstractSecurityInterceptor` (which we'll see more about later) needs to authorize a user operation.
You can (and many users do) write their own filters or MVC controllers to provide interoperability with authentication systems that are not based on Spring Security.
For example, you might be using Container-Managed Authentication which makes the current user available from a ThreadLocal or JNDI location.
Or you might work for a company that has a legacy proprietary authentication system, which is a corporate "standard" over which you have little control.
In situations like this it's quite easy to get Spring Security to work, and still provide authorization capabilities.
All you need to do is write a filter (or equivalent) that reads the third-party user information from a location, build a Spring Security-specific `Authentication` object, and put it into the `SecurityContextHolder`.
In this case you also need to think about things which are normally taken care of automatically by the built-in authentication infrastructure.
For example, you might need to pre-emptively create an HTTP session to <<tech-intro-sec-context-persistence,cache the context between requests>>, before you write the response to the client footnote:[It isn't possible to create a session once the response has been committed.
If you're wondering how the `AuthenticationManager` is implemented in a real world example, we'll look at that in the <<core-services-authentication-manager,core services chapter>>.
[[tech-intro-web-authentication]]
=== Authentication in a Web Application
Now let's explore the situation where you are using Spring Security in a web application (without `web.xml` security enabled).
How is a user authenticated and the security context established?
Consider a typical web application's authentication process:
. You visit the home page, and click on a link.
. A request goes to the server, and the server decides that you've asked for a protected resource.
. As you're not presently authenticated, the server sends back a response indicating that you must authenticate.
The response will either be an HTTP response code, or a redirect to a particular web page.
. Depending on the authentication mechanism, your browser will either redirect to the specific web page so that you can fill out the form, or the browser will somehow retrieve your identity (via a BASIC authentication dialogue box, a cookie, a X.509 certificate etc.).
. The browser will send back a response to the server.
This will either be an HTTP POST containing the contents of the form that you filled out, or an HTTP header containing your authentication details.
. Next the server will decide whether or not the presented credentials are valid.
If they're valid, the next step will happen.
If they're invalid, usually your browser will be asked to try again (so you return to step two above).
. The original request that you made to cause the authentication process will be retried.
Hopefully you've authenticated with sufficient granted authorities to access the protected resource.
If you have sufficient access, the request will be successful.
Otherwise, you'll receive back an HTTP error code 403, which means "forbidden".
Spring Security has distinct classes responsible for most of the steps described above.
The main participants (in the order that they are used) are the `ExceptionTranslationFilter`, an `AuthenticationEntryPoint` and an "authentication mechanism", which is responsible for calling the `AuthenticationManager` which we saw in the previous section.
==== ExceptionTranslationFilter
`ExceptionTranslationFilter` is a Spring Security filter that has responsibility for detecting any Spring Security exceptions that are thrown.
Such exceptions will generally be thrown by an `AbstractSecurityInterceptor`, which is the main provider of authorization services.
We will discuss `AbstractSecurityInterceptor` in the next section, but for now we just need to know that it produces Java exceptions and knows nothing about HTTP or how to go about authenticating a principal.
Instead the `ExceptionTranslationFilter` offers this service, with specific responsibility for either returning error code 403 (if the principal has been authenticated and therefore simply lacks sufficient access - as per step seven above), or launching an `AuthenticationEntryPoint` (if the principal has not been authenticated and therefore we need to go commence step three).
[[tech-intro-auth-entry-point]]
==== AuthenticationEntryPoint
The `AuthenticationEntryPoint` is responsible for step three in the above list.
As you can imagine, each web application will have a default authentication strategy (well, this can be configured like nearly everything else in Spring Security, but let's keep it simple for now).
Each major authentication system will have its own `AuthenticationEntryPoint` implementation, which typically performs one of the actions described in step 3.
==== Authentication Mechanism
Once your browser submits your authentication credentials (either as an HTTP form post or HTTP header) there needs to be something on the server that "collects" these authentication details.
By now we're at step six in the above list.
In Spring Security we have a special name for the function of collecting authentication details from a user agent (usually a web browser), referring to it as the "authentication mechanism".
Examples are form-base login and Basic authentication.
Once the authentication details have been collected from the user agent, an `Authentication` "request" object is built and then presented to the `AuthenticationManager`.
After the authentication mechanism receives back the fully-populated `Authentication` object, it will deem the request valid, put the `Authentication` into the `SecurityContextHolder`, and cause the original request to be retried (step seven above).
If, on the other hand, the `AuthenticationManager` rejected the request, the authentication mechanism will ask the user agent to retry (step two above).
[[tech-intro-sec-context-persistence]]
==== Storing the SecurityContext between requests
Depending on the type of application, there may need to be a strategy in place to store the security context between user operations.
In a typical web application, a user logs in once and is subsequently identified by their session Id.
The server caches the principal information for the duration session.
In Spring Security, the responsibility for storing the `SecurityContext` between requests falls to the `SecurityContextPersistenceFilter`, which by default stores the context as an `HttpSession` attribute between HTTP requests.
It restores the context to the `SecurityContextHolder` for each request and, crucially, clears the `SecurityContextHolder` when the request completes.
You shouldn't interact directly with the `HttpSession` for security purposes.
There is simply no justification for doing so - always use the `SecurityContextHolder` instead.
Many other types of application (for example, a stateless RESTful web service) do not use HTTP sessions and will re-authenticate on every request.
However, it is still important that the `SecurityContextPersistenceFilter` is included in the chain to make sure that the `SecurityContextHolder` is cleared after each request.
[NOTE]
====
In an application which receives concurrent requests in a single session, the same `SecurityContext` instance will be shared between threads.
Even though a `ThreadLocal` is being used, it is the same instance that is retrieved from the `HttpSession` for each thread.
This has implications if you wish to temporarily change the context under which a thread is running.
If you just use `SecurityContextHolder.getContext()`, and call `setAuthentication(anAuthentication)` on the returned context object, then the `Authentication` object will change in __all__ concurrent threads which share the same `SecurityContext` instance.
You can customize the behaviour of `SecurityContextPersistenceFilter` to create a completely new `SecurityContext` for each request, preventing changes in one thread from affecting another.
Alternatively you can create a new instance just at the point where you temporarily change the context.
The method `SecurityContextHolder.createEmptyContext()` always returns a new context instance.
====
[[tech-intro-access-control]]
=== Access-Control (Authorization) in Spring Security
The main interface responsible for making access-control decisions in Spring Security is the `AccessDecisionManager`.
It has a `decide` method which takes an `Authentication` object representing the principal requesting access, a "secure object" (see below) and a list of security metadata attributes which apply for the object (such as a list of roles which are required for access to be granted).
==== Security and AOP Advice
If you're familiar with AOP, you'd be aware there are different types of advice available: before, after, throws and around.
An around advice is very useful, because an advisor can elect whether or not to proceed with a method invocation, whether or not to modify the response, and whether or not to throw an exception.
Spring Security provides an around advice for method invocations as well as web requests.
We achieve an around advice for method invocations using Spring's standard AOP support and we achieve an around advice for web requests using a standard Filter.
For those not familiar with AOP, the key point to understand is that Spring Security can help you protect method invocations as well as web requests.
Most people are interested in securing method invocations on their services layer.
This is because the services layer is where most business logic resides in current-generation Java EE applications.
If you just need to secure method invocations in the services layer, Spring's standard AOP will be adequate.
If you need to secure domain objects directly, you will likely find that AspectJ is worth considering.
You can elect to perform method authorization using AspectJ or Spring AOP, or you can elect to perform web request authorization using filters.
You can use zero, one, two or three of these approaches together.
The mainstream usage pattern is to perform some web request authorization, coupled with some Spring AOP method invocation authorization on the services layer.
[[secure-objects]]
==== Secure Objects and the AbstractSecurityInterceptor
So what __is__ a "secure object" anyway? Spring Security uses the term to refer to any object that can have security (such as an authorization decision) applied to it.
The most common examples are method invocations and web requests.
Each supported secure object type has its own interceptor class, which is a subclass of `AbstractSecurityInterceptor`.
Importantly, by the time the `AbstractSecurityInterceptor` is called, the `SecurityContextHolder` will contain a valid `Authentication` if the principal has been authenticated.
`AbstractSecurityInterceptor` provides a consistent workflow for handling secure object requests, typically:
. Look up the "configuration attributes" associated with the present request
. Submitting the secure object, current `Authentication` and configuration attributes to the `AccessDecisionManager` for an authorization decision
. Optionally change the `Authentication` under which the invocation takes place
. Allow the secure object invocation to proceed (assuming access was granted)
. Call the `AfterInvocationManager` if configured, once the invocation has returned.
If the invocation raised an exception, the `AfterInvocationManager` will not be invoked.
[[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>>.
===== RunAsManager
Assuming `AccessDecisionManager` decides to allow the request, the `AbstractSecurityInterceptor` will normally just proceed with the request.
Having said that, on rare occasions users may want to replace the `Authentication` inside the `SecurityContext` with a different `Authentication`, which is handled by the `AccessDecisionManager` calling a `RunAsManager`.
This might be useful in reasonably unusual situations, such as if a services layer method needs to call a remote system and present a different identity.
Because Spring Security automatically propagates security identity from one server to another (assuming you're using a properly-configured RMI or HttpInvoker remoting protocol client), this may be useful.
===== AfterInvocationManager
Following the secure object invocation proceeding and then returning - which may mean a method invocation completing or a filter chain proceeding - the `AbstractSecurityInterceptor` gets one final chance to handle the invocation.
At this stage the `AbstractSecurityInterceptor` is interested in possibly modifying the return object.
We might want this to happen because an authorization decision couldn't be made "on the way in" to a secure object invocation.
Being highly pluggable, `AbstractSecurityInterceptor` will pass control to an `AfterInvocationManager` to actually modify the object if needed.
This class can even entirely replace the object, or throw an exception, or not change it in any way as it chooses.
The after-invocation checks will only be executed if the invocation is successful.
If an exception occurs, the additional checks will be skipped.
`AbstractSecurityInterceptor` and its related objects are shown in <<abstract-security-interceptor>>
[[abstract-security-interceptor]]
.Security interceptors and the "secure object" model
image::images/security-interception.png[Abstract Security Interceptor]
===== Extending the Secure Object Model
Only developers contemplating an entirely new way of intercepting and authorizing requests would need to use secure objects directly.
For example, it would be possible to build a new secure object to secure calls to a messaging system.
Anything that requires security and also provides a way of intercepting a call (like the AOP around advice semantics) is capable of being made into a secure object.
Having said that, most Spring applications will simply use the three currently supported secure object types (AOP Alliance `MethodInvocation`, AspectJ `JoinPoint` and web request `FilterInvocation`) with complete transparency.
[[localization]]
=== Localization
Spring Security supports localization of exception messages that end users are likely to see.
If your application is designed for English-speaking users, you don't need to do anything as by default all Security messages are in English.
If you need to support other locales, everything you need to know is contained in this section.
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:
[source,xml]
----
<bean id="messageSource"
class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<property name="basename" value="classpath:org/springframework/security/messages"/>
</bean>
----
The `messages.properties` is named in accordance with standard resource bundles and represents the default language supported by Spring Security messages.
This default file is in English.
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.
The "contacts" sample application is set up to use localized messages.
[[core-services]]
== Core Services
Now that we have a high-level overview of the Spring Security architecture and its core classes, let's take a closer look at one or two of the core interfaces and their implementations, in particular the `AuthenticationManager`, `UserDetailsService` and the `AccessDecisionManager`.
These crop up regularly throughout the remainder of this document so it's important you know how they are configured and how they operate.
[[core-services-authentication-manager]]
=== The AuthenticationManager, ProviderManager and AuthenticationProvider
The `AuthenticationManager` is just an interface, so the implementation can be anything we choose, but how does it work in practice? What if we need to check multiple authentication databases or a combination of different authentication services such as a database and an LDAP server?
The default implementation in Spring Security is called `ProviderManager` and rather than handling the authentication request itself, it delegates to a list of configured `AuthenticationProvider` s, each of which is queried in turn to see if it can perform the authentication.
Each provider will either throw an exception or return a fully populated `Authentication` object.
Remember our good friends, `UserDetails` and `UserDetailsService`? If not, head back to the previous chapter and refresh your memory.
The most common approach to verifying an authentication request is to load the corresponding `UserDetails` and check the loaded password against the one that has been entered by the user.
This is the approach used by the `DaoAuthenticationProvider` (see below).
The loaded `UserDetails` object - and particularly the `GrantedAuthority` s it contains - will be used when building the fully populated `Authentication` object which is returned from a successful authentication and stored in the `SecurityContext`.
If you are using the namespace, an instance of `ProviderManager` is created and maintained internally, and you add providers to it by using the namespace authentication provider elements (see <<ns-auth-manager,the namespace chapter>>).
In this case, you should not declare a `ProviderManager` bean in your application context.
However, if you are not using the namespace then you would declare it like so:
[source,xml]
----
<bean id="authenticationManager"
class="org.springframework.security.authentication.ProviderManager">
<constructor-arg>
<list>
<ref local="daoAuthenticationProvider"/>
<ref local="anonymousAuthenticationProvider"/>
<ref local="ldapAuthenticationProvider"/>
</list>
</constructor-arg>
</bean>
----
In the above example we have three providers.
They are tried in the order shown (which is implied by the use of a `List`), with each provider able to attempt authentication, or skip authentication by simply returning `null`.
If all implementations return null, the `ProviderManager` will throw a `ProviderNotFoundException`.
If you're interested in learning more about chaining providers, please refer to the `ProviderManager` Javadoc.
Authentication mechanisms such as a web form-login processing filter are injected with a reference to the `ProviderManager` and will call it to handle their authentication requests.
The providers you require will sometimes be interchangeable with the authentication mechanisms, while at other times they will depend on a specific authentication mechanism.
For example, `DaoAuthenticationProvider` and `LdapAuthenticationProvider` are compatible with any mechanism which submits a simple username/password authentication request and so will work with form-based logins or HTTP Basic authentication.
On the other hand, some authentication mechanisms create an authentication request object which can only be interpreted by a single type of `AuthenticationProvider`.
An example of this would be JA-SIG CAS, which uses the notion of a service ticket and so can therefore only be authenticated by a `CasAuthenticationProvider`.
You needn't be too concerned about this, because if you forget to register a suitable provider, you'll simply receive a `ProviderNotFoundException` when an attempt to authenticate is made.
[[core-services-erasing-credentials]]
==== Erasing Credentials on Successful Authentication
By default (from Spring Security 3.1 onwards) the `ProviderManager` will attempt to clear any sensitive credentials information from the `Authentication` object which is returned by a successful authentication request.
This prevents information like passwords being retained longer than necessary.
This may cause issues when you are using a cache of user objects, for example, to improve performance in a stateless application.
If the `Authentication` contains a reference to an object in the cache (such as a `UserDetails` instance) and this has its credentials removed, then it will no longer be possible to authenticate against the cached value.
You need to take this into account if you are using a cache.
An obvious solution is to make a copy of the object first, either in the cache implementation or in the `AuthenticationProvider` which creates the returned `Authentication` object.
Alternatively, you can disable the `eraseCredentialsAfterAuthentication` property on `ProviderManager`.
See the Javadoc for more information.
[[core-services-dao-provider]]
==== DaoAuthenticationProvider
The simplest `AuthenticationProvider` implemented by Spring Security is `DaoAuthenticationProvider`, which is also one of the earliest supported by the framework.
It leverages a `UserDetailsService` (as a DAO) in order to lookup the username, password and `GrantedAuthority` s.
It authenticates the user simply by comparing the password submitted in a `UsernamePasswordAuthenticationToken` against the one loaded by the `UserDetailsService`.
Configuring the provider is quite simple:
[source,xml]
----
<bean id="daoAuthenticationProvider"
class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
<property name="userDetailsService" ref="inMemoryDaoImpl"/>
<property name="passwordEncoder" ref="passwordEncoder"/>
</bean>
----
The `PasswordEncoder` is optional.
A `PasswordEncoder` provides encoding and decoding of passwords presented in the `UserDetails` object that is returned from the configured `UserDetailsService`.
This will be discussed in more detail <<core-services-password-encoding,below>>.
=== UserDetailsService Implementations
As mentioned in the earlier in this reference guide, most authentication providers take advantage of the `UserDetails` and `UserDetailsService` interfaces.
Recall that the contract for `UserDetailsService` is a single method:
[source,java]
----
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.
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.
[[core-services-in-memory-service]]
==== In-Memory Authentication
Is easy to use create a custom `UserDetailsService` implementation that extracts information from a persistence engine of choice, but many applications do not require such complexity.
This is particularly true if you're building a prototype application or just starting integrating Spring Security, when you don't really want to spend time configuring databases or writing `UserDetailsService` implementations.
For this sort of situation, a simple option is to use the `user-service` element from the security <<ns-minimal,namespace>>:
[source,xml]
----
<user-service id="userDetailsService">
<!-- Password is prefixed with {noop} to indicate to DelegatingPasswordEncoder that
NoOpPasswordEncoder should be used. This is not safe for production, but makes reading
in samples easier. Normally passwords should be hashed using BCrypt -->
<user name="jimi" password="{noop}jimispassword" authorities="ROLE_USER, ROLE_ADMIN" />
<user name="bob" password="{noop}bobspassword" authorities="ROLE_USER" />
</user-service>
----
This also supports the use of an external properties file:
[source,xml]
----
<user-service id="userDetailsService" properties="users.properties"/>
----
The properties file should contain entries in the form
[source,txt]
----
username=password,grantedAuthority[,grantedAuthority][,enabled|disabled]
----
For example
[source,txt]
----
jimi=jimispassword,ROLE_USER,ROLE_ADMIN,enabled
bob=bobspassword,ROLE_USER,enabled
----
[[core-services-jdbc-user-service]]
==== JdbcDaoImpl
Spring Security also includes a `UserDetailsService` that can obtain authentication information from a JDBC data source.
Internally Spring JDBC is used, so it avoids the complexity of a fully-featured object relational mapper (ORM) just to store user details.
If your application does use an ORM tool, you might prefer to write a custom `UserDetailsService` to reuse the mapping files you've probably already created.
Returning to `JdbcDaoImpl`, an example configuration is shown below:
[source,xml]
----
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="org.hsqldb.jdbcDriver"/>
<property name="url" value="jdbc:hsqldb:hsql://localhost:9001"/>
<property name="username" value="sa"/>
<property name="password" value=""/>
</bean>
<bean id="userDetailsService"
class="org.springframework.security.core.userdetails.jdbc.JdbcDaoImpl">
<property name="dataSource" ref="dataSource"/>
</bean>
----
You can use different relational database management systems by modifying the `DriverManagerDataSource` shown above.
You can also use a global data source obtained from JNDI, as with any other Spring configuration.
===== Authority Groups
By default, `JdbcDaoImpl` loads the authorities for a single user with the assumption that the authorities are mapped directly to users (see the <<appendix-schema,database schema appendix>>).
An alternative approach is to partition the authorities into groups and assign groups to the user.
Some people prefer this approach as a means of administering user rights.
See the `JdbcDaoImpl` Javadoc for more information on how to enable the use of group authorities.
The group schema is also included in the appendix.
include::password-encoder.adoc[leveloffset=+2]
include::jackson.adoc[]

View File

@ -0,0 +1,728 @@
[[authorization]]
= Authorization
The advanced authorization capabilities within Spring Security represent one of the most compelling reasons for its popularity.
Irrespective of how you choose to authenticate - whether using a Spring Security-provided mechanism and provider, or integrating with a container or other non-Spring Security authentication authority - you will find the authorization services can be used within your application in a consistent and simple way.
In this part we'll explore the different `AbstractSecurityInterceptor` implementations, which were introduced in Part I.
We then move on to explore how to fine-tune authorization through use of domain access control lists.
[[authz-arch]]
== Authorization Architecture
[[authz-authorities]]
=== Authorities
As we saw in the <<tech-granted-authority,technical overview>>, all `Authentication` implementations store a list of `GrantedAuthority` objects.
These represent the authorities that have been granted to the principal.
the `GrantedAuthority` objects are inserted into the `Authentication` object by the `AuthenticationManager` and are later read by `AccessDecisionManager` s when making authorization decisions.
`GrantedAuthority` is an interface with only one method:
[source,java]
----
String getAuthority();
----
This method allows
`AccessDecisionManager` s to obtain a precise `String` representation of the `GrantedAuthority`.
By returning a representation as a `String`, a `GrantedAuthority` can be easily "read" by most `AccessDecisionManager` s.
If a `GrantedAuthority` cannot be precisely represented as a `String`, the `GrantedAuthority` is considered "complex" and `getAuthority()` must return `null`.
An example of a "complex" `GrantedAuthority` would be an implementation that stores a list of operations and authority thresholds that apply to different customer account numbers.
Representing this complex `GrantedAuthority` as a `String` would be quite difficult, and as a result the `getAuthority()` method should return `null`.
This will indicate to any `AccessDecisionManager` that it will need to specifically support the `GrantedAuthority` implementation in order to understand its contents.
Spring Security includes one concrete `GrantedAuthority` implementation, `SimpleGrantedAuthority`.
This allows any user-specified `String` to be converted into a `GrantedAuthority`.
All `AuthenticationProvider` s included with the security architecture use `SimpleGrantedAuthority` to populate the `Authentication` object.
[[authz-pre-invocation]]
=== Pre-Invocation Handling
As we've also seen in the <<secure-objects,Technical Overview>> chapter, Spring Security provides interceptors which control access to secure objects such as method invocations or web requests.
A pre-invocation decision on whether the invocation is allowed to proceed is made by the `AccessDecisionManager`.
[[authz-access-decision-manager]]
==== The AccessDecisionManager
The `AccessDecisionManager` is called by the `AbstractSecurityInterceptor` and is responsible for making final access control decisions.
the `AccessDecisionManager` interface contains three methods:
[source,java]
----
void decide(Authentication authentication, Object secureObject,
Collection<ConfigAttribute> attrs) throws AccessDeniedException;
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 `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.
[[authz-voting-based]]
==== Voting-Based AccessDecisionManager Implementations
Whilst users can implement their own `AccessDecisionManager` to control all aspects of authorization, Spring Security includes several `AccessDecisionManager` implementations that are based on voting.
<<authz-access-voting>> illustrates the relevant classes.
[[authz-access-voting]]
.Voting Decision Manager
image::images/access-decision-voting.png[]
Using this approach, a series of `AccessDecisionVoter` implementations are polled on an authorization decision.
The `AccessDecisionManager` then decides whether or not to throw an `AccessDeniedException` based on its assessment of the votes.
The `AccessDecisionVoter` interface has three methods:
[source,java]
----
int vote(Authentication authentication, Object object, Collection<ConfigAttribute> attrs);
boolean supports(ConfigAttribute attribute);
boolean supports(Class clazz);
----
Concrete implementations return an `int`, with possible values being reflected in the `AccessDecisionVoter` static fields `ACCESS_ABSTAIN`, `ACCESS_DENIED` and `ACCESS_GRANTED`.
A voting implementation will return `ACCESS_ABSTAIN` if it has no opinion on an authorization decision.
If it does have an opinion, it must return either `ACCESS_DENIED` or `ACCESS_GRANTED`.
There are three concrete `AccessDecisionManager` s provided with Spring Security that tally the votes.
The `ConsensusBased` implementation will grant or deny access based on the consensus of non-abstain votes.
Properties are provided to control behavior in the event of an equality of votes or if all votes are abstain.
The `AffirmativeBased` implementation will grant access if one or more `ACCESS_GRANTED` votes were received (i.e. a deny vote will be ignored, provided there was at least one grant vote).
Like the `ConsensusBased` implementation, there is a parameter that controls the behavior if all voters abstain.
The `UnanimousBased` provider expects unanimous `ACCESS_GRANTED` votes in order to grant access, ignoring abstains.
It will deny access if there is any `ACCESS_DENIED` vote.
Like the other implementations, there is a parameter that controls the behaviour if all voters abstain.
It is possible to implement a custom `AccessDecisionManager` that tallies votes differently.
For example, votes from a particular `AccessDecisionVoter` might receive additional weighting, whilst a deny vote from a particular voter may have a veto effect.
[[authz-role-voter]]
===== RoleVoter
The most commonly used `AccessDecisionVoter` provided with Spring Security is the simple `RoleVoter`, which treats configuration attributes as simple role names and votes to grant access if the user has been assigned that role.
It will vote if any `ConfigAttribute` begins with the prefix `ROLE_`.
It will vote to grant access if there is a `GrantedAuthority` which returns a `String` representation (via the `getAuthority()` method) exactly equal to one or more `ConfigAttributes` starting with the prefix `ROLE_`.
If there is no exact match of any `ConfigAttribute` starting with `ROLE_`, the `RoleVoter` will vote to deny access.
If no `ConfigAttribute` begins with `ROLE_`, the voter will abstain.
[[authz-authenticated-voter]]
===== AuthenticatedVoter
Another voter which we've implicitly seen is the `AuthenticatedVoter`, which can be used to differentiate between anonymous, fully-authenticated and remember-me authenticated users.
Many sites allow certain limited access under remember-me authentication, but require a user to confirm their identity by logging in for full access.
When we've used the attribute `IS_AUTHENTICATED_ANONYMOUSLY` to grant anonymous access, this attribute was being processed by the `AuthenticatedVoter`.
See the Javadoc for this class for more information.
[[authz-custom-voter]]
===== Custom Voters
Obviously, you can also implement a custom `AccessDecisionVoter` and you can put just about any access-control logic you want in it.
It might be specific to your application (business-logic related) or it might implement some security administration logic.
For example, you'll find a http://spring.io/blog/2009/01/03/spring-security-customization-part-2-adjusting-secured-session-in-real-time[blog article] on the Spring web site which describes how to use a voter to deny access in real-time to users whose accounts have been suspended.
[[authz-after-invocation-handling]]
=== After Invocation Handling
Whilst the `AccessDecisionManager` is called by the `AbstractSecurityInterceptor` before proceeding with the secure object invocation, some applications need a way of modifying the object actually returned by the secure object invocation.
Whilst you could easily implement your own AOP concern to achieve this, Spring Security provides a convenient hook that has several concrete implementations that integrate with its ACL capabilities.
<<authz-after-invocation>> illustrates Spring Security's `AfterInvocationManager` and its concrete implementations.
[[authz-after-invocation]]
.After Invocation Implementation
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.
[[authz-hierarchical-roles]]
=== Hierarchical Roles
It is a common requirement that a particular role in an application should automatically "include" other roles.
For example, in an application which has the concept of an "admin" and a "user" role, you may want an admin to be able to do everything a normal user can.
To achieve this, you can either make sure that all admin users are also assigned the "user" role.
Alternatively, you can modify every access constraint which requires the "user" role to also include the "admin" role.
This can get quite complicated if you have a lot of different roles in your application.
The use of a role-hierarchy allows you to configure which roles (or authorities) should include others.
An extended version of Spring Security's <<authz-role-voter,RoleVoter>>, `RoleHierarchyVoter`, is configured with a `RoleHierarchy`, from which it obtains all the "reachable authorities" which the user is assigned.
A typical configuration might look like this:
[source,xml]
----
<bean id="roleVoter" class="org.springframework.security.access.vote.RoleHierarchyVoter">
<constructor-arg ref="roleHierarchy" />
</bean>
<bean id="roleHierarchy"
class="org.springframework.security.access.hierarchicalroles.RoleHierarchyImpl">
<property name="hierarchy">
<value>
ROLE_ADMIN > ROLE_STAFF
ROLE_STAFF > ROLE_USER
ROLE_USER > ROLE_GUEST
</value>
</property>
</bean>
----
Here we have four roles in a hierarchy `ROLE_ADMIN => ROLE_STAFF => ROLE_USER => ROLE_GUEST`.
A user who is authenticated with `ROLE_ADMIN`, will behave as if they have all four roles when security constraints are evaluated against an `AccessDecisionManager` cconfigured with the above `RoleHierarchyVoter`.
The `>` symbol can be thought of as meaning "includes".
Role hierarchies offer a convenient means of simplifying the access-control configuration data for your application and/or reducing the number of authorities which you need to assign to a user.
For more complex requirements you may wish to define a logical mapping between the specific access-rights your application requires and the roles that are assigned to users, translating between the two when loading the user information.
[[secure-object-impls]]
== Secure Object Implementations
[[aop-alliance]]
=== AOP Alliance (MethodInvocation) Security Interceptor
Prior to Spring Security 2.0, securing `MethodInvocation` s needed quite a lot of boiler plate configuration.
Now the recommended approach for method security is to use <<ns-method-security,namespace configuration>>.
This way the method security infrastructure beans are configured automatically for you so you don't really need to know about the implementation classes.
We'll just provide a quick overview of the classes that are involved here.
Method security in enforced using a `MethodSecurityInterceptor`, which secures `MethodInvocation` s.
Depending on the configuration approach, an interceptor may be specific to a single bean or shared between multiple beans.
The interceptor uses a `MethodSecurityMetadataSource` instance to obtain the configuration attributes that apply to a particular method invocation.
`MapBasedMethodSecurityMetadataSource` is used to store configuration attributes keyed by method names (which can be wildcarded) and will be used internally when the attributes are defined in the application context using the `<intercept-methods>` or `<protect-point>` elements.
Other implementations will be used to handle annotation-based configuration.
==== Explicit MethodSecurityInterceptor Configuration
You can of course configure a `MethodSecurityIterceptor` directly in your application context for use with one of Spring AOP's proxying mechanisms:
[source,xml]
----
<bean id="bankManagerSecurity" class=
"org.springframework.security.access.intercept.aopalliance.MethodSecurityInterceptor">
<property name="authenticationManager" ref="authenticationManager"/>
<property name="accessDecisionManager" ref="accessDecisionManager"/>
<property name="afterInvocationManager" ref="afterInvocationManager"/>
<property name="securityMetadataSource">
<sec:method-security-metadata-source>
<sec:protect method="com.mycompany.BankManager.delete*" access="ROLE_SUPERVISOR"/>
<sec:protect method="com.mycompany.BankManager.getBalance" access="ROLE_TELLER,ROLE_SUPERVISOR"/>
</sec:method-security-metadata-source>
</property>
</bean>
----
[[aspectj]]
=== AspectJ (JoinPoint) Security Interceptor
The AspectJ security interceptor is very similar to the AOP Alliance security interceptor discussed in the previous section.
Indeed we will only discuss the differences in this section.
The AspectJ interceptor is named `AspectJSecurityInterceptor`.
Unlike the AOP Alliance security interceptor, which relies on the Spring application context to weave in the security interceptor via proxying, the `AspectJSecurityInterceptor` is weaved in via the AspectJ compiler.
It would not be uncommon to use both types of security interceptors in the same application, with `AspectJSecurityInterceptor` being used for domain object instance security and the AOP Alliance `MethodSecurityInterceptor` being used for services layer security.
Let's first consider how the `AspectJSecurityInterceptor` is configured in the Spring application context:
[source,xml]
----
<bean id="bankManagerSecurity" class=
"org.springframework.security.access.intercept.aspectj.AspectJMethodSecurityInterceptor">
<property name="authenticationManager" ref="authenticationManager"/>
<property name="accessDecisionManager" ref="accessDecisionManager"/>
<property name="afterInvocationManager" ref="afterInvocationManager"/>
<property name="securityMetadataSource">
<sec:method-security-metadata-source>
<sec:protect method="com.mycompany.BankManager.delete*" access="ROLE_SUPERVISOR"/>
<sec:protect method="com.mycompany.BankManager.getBalance" access="ROLE_TELLER,ROLE_SUPERVISOR"/>
</sec:method-security-metadata-source>
</property>
</bean>
----
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:
[source,java]
----
package org.springframework.security.samples.aspectj;
import org.springframework.security.access.intercept.aspectj.AspectJSecurityInterceptor;
import org.springframework.security.access.intercept.aspectj.AspectJCallback;
import org.springframework.beans.factory.InitializingBean;
public aspect DomainObjectInstanceSecurityAspect implements InitializingBean {
private AspectJSecurityInterceptor securityInterceptor;
pointcut domainObjectInstanceExecution(): target(PersistableEntity)
&& execution(public * *(..)) && !within(DomainObjectInstanceSecurityAspect);
Object around(): domainObjectInstanceExecution() {
if (this.securityInterceptor == null) {
return proceed();
}
AspectJCallback callback = new AspectJCallback() {
public Object proceedWithObject() {
return proceed();
}
};
return this.securityInterceptor.invoke(thisJoinPoint, callback);
}
public AspectJSecurityInterceptor getSecurityInterceptor() {
return securityInterceptor;
}
public void setSecurityInterceptor(AspectJSecurityInterceptor securityInterceptor) {
this.securityInterceptor = securityInterceptor;
}
public void afterPropertiesSet() throws Exception {
if (this.securityInterceptor == null)
throw new IllegalArgumentException("securityInterceptor required");
}
}
}
----
In the above example, the security interceptor will be applied to every instance of `PersistableEntity`, which is an abstract class not shown (you can use any other class or `pointcut` expression you like).
For those curious, `AspectJCallback` is needed because the `proceed();` statement has special meaning only within an `around()` body.
The `AspectJSecurityInterceptor` calls this anonymous `AspectJCallback` class when it wants the target object to continue.
You will need to configure Spring to load the aspect and wire it with the `AspectJSecurityInterceptor`.
A bean declaration which achieves this is shown below:
[source,xml]
----
<bean id="domainObjectInstanceSecurityAspect"
class="security.samples.aspectj.DomainObjectInstanceSecurityAspect"
factory-method="aspectOf">
<property name="securityInterceptor" ref="bankManagerSecurity"/>
</bean>
----
That's it!
Now you can create your beans from anywhere within your application, using whatever means you think fit (eg `new Person();`) and they will have the security interceptor applied.
[[el-access]]
== Expression-Based Access Control
Spring Security 3.0 introduced the ability to use Spring EL expressions as an authorization mechanism in addition to the simple use of configuration attributes and access-decision voters which have seen before.
Expression-based access control is built on the same architecture but allows complicated Boolean logic to be encapsulated in a single expression.
=== Overview
Spring Security uses Spring EL for expression support and you should look at how that works if you are interested in understanding the topic in more depth.
Expressions are evaluated with a "root object" as part of the evaluation context.
Spring Security uses specific classes for web and method security as the root object, in order to provide built-in expressions and access to values such as the current principal.
[[el-common-built-in]]
==== Common Built-In Expressions
The base class for expression root objects is `SecurityExpressionRoot`.
This provides some common expressions which are available in both web and method security.
[[common-expressions]]
.Common built-in expressions
|===
| Expression | Description
| `hasRole([role])`
| Returns `true` if the current principal has the specified role.
By default if the supplied role does not start with 'ROLE_' it will be added.
This can be customized by modifying the `defaultRolePrefix` on `DefaultWebSecurityExpressionHandler`.
| `hasAnyRole([role1,role2])`
| Returns `true` if the current principal has any of the supplied roles (given as a comma-separated list of strings).
By default if the supplied role does not start with 'ROLE_' it will be added.
This can be customized by modifying the `defaultRolePrefix` on `DefaultWebSecurityExpressionHandler`.
| `hasAuthority([authority])`
| Returns `true` if the current principal has the specified authority.
| `hasAnyAuthority([authority1,authority2])`
| Returns `true` if the current principal has any of the supplied roles (given as a comma-separated list of strings)
| `principal`
| Allows direct access to the principal object representing the current user
| `authentication`
| Allows direct access to the current `Authentication` object obtained from the `SecurityContext`
| `permitAll`
| Always evaluates to `true`
| `denyAll`
| Always evaluates to `false`
| `isAnonymous()`
| Returns `true` if the current principal is an anonymous user
| `isRememberMe()`
| Returns `true` if the current principal is a remember-me user
| `isAuthenticated()`
| Returns `true` if the user is not anonymous
| `isFullyAuthenticated()`
| Returns `true` if the user is not an anonymous or a remember-me user
| `hasPermission(Object target, Object permission)`
| Returns `true` if the user has access to the provided target for the given permission.
For example, `hasPermission(domainObject, 'read')`
| `hasPermission(Object targetId, String targetType, Object permission)`
| Returns `true` if the user has access to the provided target for the given permission.
For example, `hasPermission(1, 'com.example.domain.Message', 'read')`
|===
[[el-access-web]]
=== Web Security Expressions
To use expressions to secure individual URLs, you would first need to set the `use-expressions` attribute in the `<http>` element to `true`.
Spring Security will then expect the `access` attributes of the `<intercept-url>` elements to contain Spring EL expressions.
The expressions should evaluate to a Boolean, defining whether access should be allowed or not.
For example:
[source,xml]
----
<http>
<intercept-url pattern="/admin*"
access="hasRole('admin') and hasIpAddress('192.168.1.0/24')"/>
...
</http>
----
Here we have defined that the "admin" area of an application (defined by the URL pattern) should only be available to users who have the granted authority "admin" and whose IP address matches a local subnet.
We've already seen the built-in `hasRole` expression in the previous section.
The expression `hasIpAddress` is an additional built-in expression which is specific to web security.
It is defined by the `WebSecurityExpressionRoot` class, an instance of which is used as the expression root object when evaluation web-access expressions.
This object also directly exposed the `HttpServletRequest` object under the name `request` so you can invoke the request directly in an expression.
If expressions are being used, a `WebExpressionVoter` will be added to the `AccessDecisionManager` which is used by the namespace.
So if you aren't using the namespace and want to use expressions, you will have to add one of these to your configuration.
[[el-access-web-beans]]
==== Referring to Beans in Web Security Expressions
If you wish to extend the expressions that are available, you can easily refer to any Spring Bean you expose.
For example, assuming you have a Bean with the name of `webSecurity` that contains the following method signature:
[source,java]
----
public class WebSecurity {
public boolean check(Authentication authentication, HttpServletRequest request) {
...
}
}
----
You could refer to the method using:
[source,xml]
----
<http>
<intercept-url pattern="/user/**"
access="@webSecurity.check(authentication,request)"/>
...
</http>
----
or in Java configuration
[source,java]
----
http
.authorizeRequests()
.antMatchers("/user/**").access("@webSecurity.check(authentication,request)")
...
----
[[el-access-web-path-variables]]
==== Path Variables in Web Security Expressions
At times it is nice to be able to refer to path variables within a URL.
For example, consider a RESTful application that looks up a user by id from the URL path in the format `/user/{userId}`.
You can easily refer to the path variable by placing it in the pattern.
For example, if you had a Bean with the name of `webSecurity` that contains the following method signature:
[source,java]
----
public class WebSecurity {
public boolean checkUserId(Authentication authentication, int id) {
...
}
}
----
You could refer to the method using:
[source,xml]
----
<http>
<intercept-url pattern="/user/{userId}/**"
access="@webSecurity.checkUserId(authentication,#userId)"/>
...
</http>
----
or in Java configuration
[source,java]
----
http
.authorizeRequests()
.antMatchers("/user/{userId}/**").access("@webSecurity.checkUserId(authentication,#userId)")
...
----
In both configurations URLs that match would pass in the path variable (and convert it) into checkUserId method.
For example, if the URL were `/user/123/resource`, then the id passed in would be `123`.
=== Method Security Expressions
Method security is a bit more complicated than a simple allow or deny rule.
Spring Security 3.0 introduced some new annotations in order to allow comprehensive support for the use of expressions.
[[el-pre-post-annotations]]
==== @Pre and @Post Annotations
There are four annotations which support expression attributes to allow pre and post-invocation authorization checks and also to support filtering of submitted collection arguments or return values.
They are `@PreAuthorize`, `@PreFilter`, `@PostAuthorize` and `@PostFilter`.
Their use is enabled through the `global-method-security` namespace element:
[source,xml]
----
<global-method-security pre-post-annotations="enabled"/>
----
===== Access Control using @PreAuthorize and @PostAuthorize
The most obviously useful annotation is `@PreAuthorize` which decides whether a method can actually be invoked or not.
For example (from the"Contacts" sample application)
[source,java]
----
@PreAuthorize("hasRole('USER')")
public void create(Contact contact);
----
which means that access will only be allowed for users with the role "ROLE_USER".
Obviously the same thing could easily be achieved using a traditional configuration and a simple configuration attribute for the required role.
But what about:
[source,java]
----
@PreAuthorize("hasPermission(#contact, 'admin')")
public void deletePermission(Contact contact, Sid recipient, Permission permission);
----
Here we're actually using a method argument as part of the expression to decide whether the current user has the "admin"permission for the given contact.
The built-in `hasPermission()` expression is linked into the Spring Security ACL module through the application context, as we'll<<el-permission-evaluator,see below>>.
You can access any of the method arguments by name as expression variables.
There are a number of ways in which Spring Security can resolve the method arguments.
Spring Security uses `DefaultSecurityParameterNameDiscoverer` to discover the parameter names.
By default, the following options are tried for a method as a whole.
* If Spring Security's `@P` annotation is present on a single argument to the method, the value will be used.
This is useful for interfaces compiled with a JDK prior to JDK 8 which do not contain any information about the parameter names.
For example:
+
[source,java]
----
import org.springframework.security.access.method.P;
...
@PreAuthorize("#c.name == authentication.name")
public void doSomething(@P("c") Contact contact);
----
+
Behind the scenes this use implemented using `AnnotationParameterNameDiscoverer` which can be customized to support the value attribute of any specified annotation.
* If Spring Data's `@Param` annotation is present on at least one parameter for the method, the value will be used.
This is useful for interfaces compiled with a JDK prior to JDK 8 which do not contain any information about the parameter names.
For example:
+
[source,java]
----
import org.springframework.data.repository.query.Param;
...
@PreAuthorize("#n == authentication.name")
Contact findContactByName(@Param("n") String name);
----
+
Behind the scenes this use implemented using `AnnotationParameterNameDiscoverer` which can be customized to support the value attribute of any specified annotation.
* If JDK 8 was used to compile the source with the -parameters argument and Spring 4+ is being used, then the standard JDK reflection API is used to discover the parameter names.
This works on both classes and interfaces.
* Last, if the code was compiled with the debug symbols, the parameter names will be discovered using the debug symbols.
This will not work for interfaces since they do not have debug information about the parameter names.
For interfaces, annotations or the JDK 8 approach must be used.
.[[el-pre-post-annotations-spel]]
--
Any Spring-EL functionality is available within the expression, so you can also access properties on the arguments.
For example, if you wanted a particular method to only allow access to a user whose username matched that of the contact, you could write
--
[source,java]
----
@PreAuthorize("#contact.name == authentication.name")
public void doSomething(Contact contact);
----
Here we are accessing another built-in expression, `authentication`, which is the `Authentication` stored in the security context.
You can also access its "principal" property directly, using the expression `principal`.
The value will often be a `UserDetails` instance, so you might use an expression like `principal.username` or `principal.enabled`.
.[[el-pre-post-annotations-post]]
--
Less commonly, you may wish to perform an access-control check after the method has been invoked.
This can be achieved using the `@PostAuthorize` annotation.
To access the return value from a method, use the built-in name `returnObject` in the expression.
--
===== Filtering using @PreFilter and @PostFilter
As you may already be aware, Spring Security supports filtering of collections and arrays and this can now be achieved using expressions.
This is most commonly performed on the return value of a method.
For example:
[source,java]
----
@PreAuthorize("hasRole('USER')")
@PostFilter("hasPermission(filterObject, 'read') or hasPermission(filterObject, 'admin')")
public List<Contact> getAll();
----
When using the `@PostFilter` annotation, Spring Security iterates through the returned collection and removes any elements for which the supplied expression is false.
The name `filterObject` refers to the current object in the collection.
You can also filter before the method call, using `@PreFilter`, though this is a less common requirement.
The syntax is just the same, but if there is more than one argument which is a collection type then you have to select one by name using the `filterTarget` property of this annotation.
Note that filtering is obviously not a substitute for tuning your data retrieval queries.
If you are filtering large collections and removing many of the entries then this is likely to be inefficient.
[[el-method-built-in]]
==== Built-In Expressions
There are some built-in expressions which are specific to method security, which we have already seen in use above.
The `filterTarget` and `returnValue` values are simple enough, but the use of the `hasPermission()` expression warrants a closer look.
[[el-permission-evaluator]]
===== The PermissionEvaluator interface
`hasPermission()` expressions are delegated to an instance of `PermissionEvaluator`.
It is intended to bridge between the expression system and Spring Security's ACL system, allowing you to specify authorization constraints on domain objects, based on abstract permissions.
It has no explicit dependencies on the ACL module, so you could swap that out for an alternative implementation if required.
The interface has two methods:
[source,java]
----
boolean hasPermission(Authentication authentication, Object targetDomainObject,
Object permission);
boolean hasPermission(Authentication authentication, Serializable targetId,
String targetType, Object permission);
----
which map directly to the available versions of the expression, with the exception that the first argument (the `Authentication` object) is not supplied.
The first is used in situations where the domain object, to which access is being controlled, is already loaded.
Then expression will return true if the current user has the given permission for that object.
The second version is used in cases where the object is not loaded, but its identifier is known.
An abstract "type" specifier for the domain object is also required, allowing the correct ACL permissions to be loaded.
This has traditionally been the Java class of the object, but does not have to be as long as it is consistent with how the permissions are loaded.
To use `hasPermission()` expressions, you have to explicitly configure a `PermissionEvaluator` in your application context.
This would look something like this:
[source,xml]
----
<security:global-method-security pre-post-annotations="enabled">
<security:expression-handler ref="expressionHandler"/>
</security:global-method-security>
<bean id="expressionHandler" class=
"org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler">
<property name="permissionEvaluator" ref="myPermissionEvaluator"/>
</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.
===== Method Security Meta Annotations
You can make use of meta annotations for method security to make your code more readable.
This is especially convenient if you find that you are repeating the same complex expression throughout your code base.
For example, consider the following:
[source,java]
----
@PreAuthorize("#contact.name == authentication.name")
----
Instead of repeating this everywhere, we can create a meta annotation that can be used instead.
[source,java]
----
@Retention(RetentionPolicy.RUNTIME)
@PreAuthorize("#contact.name == authentication.name")
public @interface ContactPermission {}
----
Meta annotations can be used for any of the Spring Security method security annotations.
In order to remain compliant with the specification JSR-250 annotations do not support meta annotations.

View File

@ -0,0 +1,46 @@
[[data]]
= Spring Data Integration
Spring Security provides Spring Data integration that allows referring to the current user within your queries.
It is not only useful but necessary to include the user in the queries to support paged results since filtering the results afterwards would not scale.
[[data-configuration]]
== Spring Data & Spring Security Configuration
To use this support, provide a bean of type `SecurityEvaluationContextExtension`.
In Java Configuration, this would look like:
[source,java]
----
@Bean
public SecurityEvaluationContextExtension securityEvaluationContextExtension() {
return new SecurityEvaluationContextExtension();
}
----
In XML Configuration, this would look like:
[source,xml]
----
<bean class="org.springframework.security.data.repository.query.SecurityEvaluationContextExtension"/>
----
[[data-query]]
== Security Expressions within @Query
Now Spring Security can be used within your queries.
For example:
[source,java]
----
@Repository
public interface MessageRepository extends PagingAndSortingRepository<Message,Long> {
@Query("select m from Message m where m.to.id = ?#{ principal?.id }")
Page<Message> findInbox(Pageable pageable);
}
----
This checks to see if the `Authentication.getPrincipal().getId()` is equal to the recipient of the `Message`.
Note that this example assumes you have customized the principal to be an Object that has an id property.
By exposing the `SecurityEvaluationContextExtension` bean, all of the <<common-expressions,Common Security Expressions>> are available within the Query.

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff