From 67a90b36ee23f74edb13209008f6a218dd3115a6 Mon Sep 17 00:00:00 2001 From: Luke Taylor Date: Tue, 16 Jun 2009 12:47:26 +0000 Subject: [PATCH] SEC-1178: New manual chapters --- .../src/docbook/concurrent-sessions.xml | 54 +++ docs/manual/src/docbook/core-filters.xml | 307 ++++++++++++++++++ docs/manual/src/docbook/core-services.xml | 169 ++++++++++ .../manual/src/docbook/web-infrastructure.xml | 252 ++++++++++++++ 4 files changed, 782 insertions(+) create mode 100644 docs/manual/src/docbook/concurrent-sessions.xml create mode 100644 docs/manual/src/docbook/core-filters.xml create mode 100644 docs/manual/src/docbook/core-services.xml create mode 100644 docs/manual/src/docbook/web-infrastructure.xml diff --git a/docs/manual/src/docbook/concurrent-sessions.xml b/docs/manual/src/docbook/concurrent-sessions.xml new file mode 100644 index 0000000000..e67b61e7ac --- /dev/null +++ b/docs/manual/src/docbook/concurrent-sessions.xml @@ -0,0 +1,54 @@ + + + Concurrent Session Handling + + + Spring Security is able to prevent a principal from concurrently authenticating to the + same application more than a specified number of times. Many ISVs take advantage of this to + enforce licensing, whilst network administrators like this feature because it helps prevent + people from sharing login names. You can, for example, stop user "Batman" from logging onto + the web application from two different sessions. + To use concurrent session support, you'll need to add the following to + web.xml: + + org.springframework.security.web.session.HttpSessionEventPublisher + + ]]> + + In addition, you will need to add the + org.springframework.security.web.authentication.concurrent.ConcurrentSessionFilter + to your FilterChainProxy. The + ConcurrentSessionFilter requires two properties, + sessionRegistry, which generally points to an instance of + SessionRegistryImpl, and expiredUrl, which points to + the page to display when a session has expired. + The web.xml + HttpSessionEventPublisher causes an ApplicationEvent to + be published to the Spring ApplicationContext every time a + HttpSession commences or terminates. This is critical, as it allows the + SessionRegistryImpl to be notified when a session ends. + You will also need to wire up the ConcurrentSessionControllerImpl + and refer to it from your ProviderManager bean: + + + + + + + + + + + + + + +]]> + + diff --git a/docs/manual/src/docbook/core-filters.xml b/docs/manual/src/docbook/core-filters.xml new file mode 100644 index 0000000000..1936456465 --- /dev/null +++ b/docs/manual/src/docbook/core-filters.xml @@ -0,0 +1,307 @@ + + Core Security Filters + There are some key filters which will always be used in a web application which uses + Spring Security, so we'll look at these and their supporting classes and interfaces them + first. We won't cover every feature, so be sure to look at the Javadoc for them if you want + to get the complete picture. +
+ <classname>FilterSecurityInterceptor</classname> + We've already seen FilterSecurityInterceptor briefly when + discussing access-control in general (see), 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: + + + + + + + + +]]> + 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 where we saw these originally. + 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 <filter-chain-map> used to configure a + FilterChainProxy 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 + FilterSecurityMetadataSource. This is a marker + interface which subclasses SecurityMetadataSource. It + simply denotes the SecurityMetadataSource understands + FilterInvocations. In the interests of simplicity we'll + continue to refer to the FilterInvocationDefinitionSource + 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 + path-type 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: + + + + + + + + + + +]]> + Patterns are always evaluated in the order they are defined. Thus it is important that + more specific patterns are defined higher in the list than less specific patterns. This + is reflected in our example above, where the more specific + /secure/super/ pattern appears higher than the less specific + /secure/ pattern. If they were reversed, the + /secure/ pattern would always match and the + /secure/super/ pattern would never be evaluated. + +
+
+ + <classname>ExceptionTranslationFilter</classname> + The ExceptionTranslationFilter sits above the FilterSecurityInterceptor + in the security filter stack. It doesn't do any actual security enforcement itself, + but handles exceptions thrown by the security interceptors and provides suitable + and HTTP responses. + + + + + + + + + + + + +]]> + +
+ <interfacename>AuthenticationEntryPoint</interfacename> + + The AuthenticationEntryPoint will be + called if the user requests a secure HTTP resource but they are not authenticated. An + appropriate AuthenticationException or + AccessDeniedException will be thrown by a security + interceptor further down the call stack, triggering the + commence method on the entry point. This does the job of + presenting the appropriate response to the user so that authentication can begin. The + one we've used here is LoginUrlAuthenticationEntryPoint, which + redirects the request to a different URL (typically a login page). The actual + implementation used will depend on the authentication mechanism you want to be used in + your application. +
+
+ <interfacename>AccessDeniedHandler</interfacename> + What happens if a user is already authenticated an they try to access a protected + resource? In normal usage, this shouldn't happen because the application workflow + should be restricted to operations to which a user has access. For example, an HTML + link to an administration page might be hidden from users who do not have an admin + role. You can't rely on hiding links for security though, as there's always a + possibility that a user will just enter the URL directly in an attempt to bypass the + restrictions. Or they might modify a RESTful URL to change some of the argument + values. Your application must be protected against these scenarios or it will + definitely be insecure. You will typically use simple web layer security to apply + constraints to basic URLs and use more specific method-based security on your + service layer interfaces to really nail down what is permissible. + If an AccessDeniedException is thrown and a user + has already been authenticated, then this means that an operation has been attempted + for which they don't have enough permissions. In this case, + ExceptionTranslationFilter will invoke a second strategy, + the AccessDeniedHandler. By default, an + AccessDeniedHandlerImpl is used, which just sends a 403 (Forbidden) + response to the client. Alternatively you can configure an instance explicitly (as in + the above example) and set an error page URL which it will forwards the request to + We use a forward so that the SecurityContextHolder still contains details of the principal, + which may be useful for displaying to the user. In old releases of Spring Security we relied upon the servlet + container to handle a 403 error message, which lacked this useful contextual information.. + This can be a simple access denied page, such as a JSP, or it could be + a more complex handler such as an MVC controller. And of course, you can implement the + interface yourself and use your own implementation. + + It's also possible to supply a custom AccessDeniedHandler when you're + using the namespace to configure your application. See . +
+
+ <classname>SecurityContextPersistenceFilter</classname> + + We covered the purpose of this all-important filter in so + you might want to re-read that section at this point. Let's first take a look at how you would configure it + for use with a FilterChainProxy. A basic configuration only requires the bean itself + + ]]> + As we saw previously, this filter has two main tasks. It is responsible for storage of the SecurityContext + contents between HTTP requests and for clearing the SecurityContextHolder when a request is completed. + Clearing the ThreadLocal in which the context is stored is essential, as it might otherwise be possible for + a thread to be replaced into the servlet container's thread pool, with the security context for a particular user still + attached. This thread might then be used at a later stage, performing operations with the wrong credentials. + + +
+ <interfacename>SecurityContextRepository</interfacename> + From Spring Security 3.0, the job of loading and storing the security context is now delegated + to a separate strategy interface: + +public interface SecurityContextRepository { + SecurityContext loadContext(HttpRequestResponseHolder requestResponseHolder); + void saveContext(SecurityContext context, HttpServletRequest request, HttpServletResponse response); +} + + 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 + 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: + + + + + + + + ]]> + + Alternatively you could provide a null implementation of the SecurityContextRepository interface. + +
+
+
+ <classname>UsernamePasswordAuthenticationProcessingFilter</classname> + We've now seen the three main filters which are always present in a Spring Security web configuration. These + are also the three which are automatically created by the namespace <http> element and + cannot be substituted with alternatives. The only thing that's missing now is an actual authentication mechanism, something + that will allow a user to authenticate. This filter is the most commonly used authentication filter and the one + that is most often customized + For historical reasons, prior to Spring Security 3.0, this filter was called + AuthenticationProcessingFilter and the entry point was called + AuthenticationProcessingFilterEntryPoint. Since the framework now supports + many different forms of authentication, they have both been given more specific names in 3.0.. + It also provides the implementation used by the <form-login> element from the namespace. + There are three stages required to configure it. + + Configure a LoginUrlAuthenticationEntryPoint with the URL + of the login page, just as we did above, and set it on the ExceptionTranslationFilter. + + + Implement the login page (using a JSP or MVC controller). + Configure an instance of UsernamePasswordAuthenticationProcessingFilter in the application context + Add the filter bean to your filter chain proxy (making sure you pay attention to the order). + + The login form simply contains j_username and + j_password input fields, and posts to the URL that is + monitored by the filter (by default this is /j_spring_security_check). + The basic filter configuration looks something like this: + + + + ]]> + + + +
+ Application Flow on Authentication Success and Failure + + The filter calls the configured AuthenticationManager + processes each authentication request. The destination following a successful authentication + or an authentication failure is controlled by the AuthenticationSuccessHandler + and AuthenticationFailureHandler strategy interfaces, respectively. + The filter has properties which allow you to set these so you can customize the behaviour as + much as you want + In versions prior to 3.0, the application flow at this point had evolved to a stage + was controlled by a mix of properties on this class and strategy plugins. The + decision was made for 3.0 to refactor the code to make these two strategies entirely responsible. + . + Some standard implementations are supplied such as + SimpleUrlAuthenticationSuccessHandler, + SavedRequestAwareAuthenticationSuccessHandler, + SimpleUrlAuthenticationFailureHandler and + ExceptionMappingAuthenticationFailureHandler. Have a look at the Javadoc + for these classes to see how they work. + + + If authentication is successful, the resulting + Authentication object will be placed into the + SecurityContextHolder. + The configured AuthenticationSuccessHandler will then be called to either redirect or forward + the user to the approprate destination. By default a SavedRequestAwareAuthenticationSuccessHandler + is used, which means that the user will be redirected to the original destination they requested before they were asked to + login. + + + The ExceptionTranslationFilter caches the original request a user makes. + When the user authenticates, the request handler makes use of this cached request to obtain the original + URL and redirect to it. The original request is then rebuilt and used as an alternative. + + + If authentication fails, the configured AuthenticationFailureHandler will be invoked. + +
+
+
+
diff --git a/docs/manual/src/docbook/core-services.xml b/docs/manual/src/docbook/core-services.xml new file mode 100644 index 0000000000..f95282604a --- /dev/null +++ b/docs/manual/src/docbook/core-services.xml @@ -0,0 +1,169 @@ + + 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. +
+ The <interfacename>AuthenticationManager</interfacename>, + <classname>ProviderManager</classname> and + <classname>AuthenticationProvider</classname>s + 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 + AuthenticationProviders, 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, which wraps a + UserDetailsService to implement an + AuthenticationProvider. The loaded + UserDetails object - and particularly the + GrantedAuthoritys 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 + ProviderMananger is created and maintained internally, and + you add providers to it either by using the namespace authentication provired elements, + or by adding the <custom-authentication-provider> element to a + bean (see 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: + + + + + + + +]]> + 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 JavaDocs. + 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. +
+
+ <interfacename>UserDetailsService</interfacename> 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: + + + 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. +
+ 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 namespace: + + + + ]]> + This also supports the use of an external properties + file: + ]]> The properties file should contain entries in the form + username=password,grantedAuthority[,grantedAuthority][,enabled|disabled] + For example + + jimi=jimispassword,ROLE_USER,ROLE_ADMIN,enabled + bob=bobspassword,ROLE_USER,enabled +
+
+ <literal>JdbcDaoImpl</literal> + 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: + + + + + + + + + + + ]]> + + 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. + +
+
+
diff --git a/docs/manual/src/docbook/web-infrastructure.xml b/docs/manual/src/docbook/web-infrastructure.xml new file mode 100644 index 0000000000..d81e67be90 --- /dev/null +++ b/docs/manual/src/docbook/web-infrastructure.xml @@ -0,0 +1,252 @@ + + + Web Application Infrastructure + + +
+ The Security Filter Chain + Spring Security's web infrastructure is based entirely on standard servlet filters. It + doesn't use servlets or any other servlet-based frameworks (such as Spring MVC) internally, so + it has no strong links to any particular web technology. It deals in + HttpServletRequests and HttpServletResponses + and doesn't care whether the requests come from a browser, a web service client, an + HttpInvoker or an AJAX application. + Spring Security maintains a filter chain internally where each of the filters has a + particular responsibility and filters are added or removed from the configuration depending on + which services are required. The ordering of the filters is important as there are + dependencies between them. If you have been using namespace + configuration, then the filters are automatically configured for you and you don't + have to define any Spring beans explicitly but here may be times when you want full control + over the security filter chain, either because you are using features which aren't supported + in the namespace, or you are using your own customized versions of classes. +
+ <classname>DelegatingFilterProxy</classname> + When using servlet filters, you obviously need to declare them in your + web.xml, or they will be ignored by the servlet container. In Spring + Security, the filter classes are also Spring beans defined in the application context and + thus able to take advantage of Spring's rich dependency-injection facilities and lifecycle + interfaces. Spring's DelegatingFilterProxy provides the link between + web.xml and the application context. + When using DelegatingFilterProxy, you will see something like + this in the web.xml file: + myFilter + org.springframework.web.filter.DelegatingFilterProxy + + + + myFilter + /* + ]]> + Notice that the filter is actually a + DelegatingFilterProxy, and not the class that will actually implement + the logic of the filter. What DelegatingFilterProxy does is delegate + the Filter's methods through to a bean which is obtained from + the Spring application context. This enables the bean to benefit from the Spring web + application context lifecycle support and configuration flexibility. The bean must implement + javax.servlet.Filter and it must have the same name as that + in the filter-name element. Read the Javadoc for + DelegatingFilterProxy for more information +
+
+ <classname>FilterChainProxy</classname> + It should now be clear that you can declare each Spring Security filter bean that you + require in your application context file and add a corresponding + DelegatingFilterProxy entry to web.xml for + each filter, making sure that they are ordered correctly. This is a cumbersome approach and + clutters up the web.xml file quickly if we have a lot of filters. We + would prefer to just add a single entry to web.xml and deal entirely + with the application context file for managing our web security beans. This is where Spring + Secuiryt's FilterChainProxy comes in. It is wired using a + DelegatingFilterProxy, just like in the example above, but with the + filter-name set to the bean name filterChainProxy. The + filter chain is then declared in the application context with the same bean name. Here's an + example: + + + + + +]]> + The namespace element filter-chain-map is + used to set up the security filter chain(s) which are required within the application + Note that you'll need to include the security namespace in your application context + XML file in order to use this syntax. + . It maps a particular URL pattern to a chain of filters built up from the bean + names specified in the filters element. Both regular expressions and Ant + Paths are supported, and the most specific URIs appear first. At runtime the + FilterChainProxy will locate the first URI pattern that matches the + current web request and the list of filter beans specified by the filters + attribute will be applied to that request. The filters will be invoked in the order they are + defined, so you have complete control over the filter chain which is applied to a particular + URL. + You may have noticed we have declared two + SecurityContextPersistenceFilters in the filter chain + (ASC is short for allowSessionCreation, a property + of SecurityContextPersistenceFilter). As web services will never + present a jsessionid on future requests, creating + HttpSessions for such user agents would be wasteful. If you had a + high-volume application which required maximum scalability, we recommend you use the + approach shown above. For smaller applications, using a single + SecurityContextPersistenceFilter (with its default + allowSessionCreation as true) would likely be + sufficient. + In relation to lifecycle issues, the FilterChainProxy will always + delegate init(FilterConfig) and destroy() + methods through to the underlaying Filters if such methods + are called against FilterChainProxy itself. In this case, + FilterChainProxy guarantees to only initialize and destroy each + Filter bean once, no matter how many times it is declared in the filter + chain(s). You control the overall choice as to whether these methods are called or not via + the targetFilterLifecycle initialization parameter of + DelegatingFilterProxy. By default this property is + false and servlet container lifecycle invocations are not delegated + through DelegatingFilterProxy. + When we looked at how to set up web security using namespace configuration, we used a + DelegatingFilterProxy with the name + springSecurityFilterChain. You should now be able to see that this is the + name of the FilterChainProxy which is created by the namespace. +
+ Bypassing the Filter Chain + As with the namespace, you can use the attribute filters = "none" + as an alternative to supplying a filter bean list. This will omit the request pattern from + the security filter chain entirely. Note that anything matching this path will then have + no authentication or authorization services applied and will be freely accessible. If you + want to make use of the contents of the SecurityContext contents + during a request, then it must have passed through the security filter chain. Otherwise + the SecurityContextHolder will not have been populated and the + contents will be null. +
+
+
+ Filter Ordering + The order that filters are defined in the chain is very important. Irrespective of which + filters you are actually using, the order should be as follows: + + + ChannelProcessingFilter, because it might need to redirect + to a different protocol + + + ConcurrentSessionFilter, because it doesn't use any + SecurityContextHolder functionality but needs to update the + SessionRegistry to reflect ongoing requests from the + principal + + + SecurityContextPersistenceFilter, so a + SecurityContext can be set up in the + SecurityContextHolder at the beginning of a web request, and + any changes to the SecurityContext can be copied to the + HttpSession when the web request ends (ready for use with the + next web request) + + + Authentication processing mechanisms - + UsernamePasswordAuthenticationProcessingFilter, + CasProcessingFilter, + BasicProcessingFilter etc - so that the + SecurityContextHolder can be modified to contain a valid + Authentication request token + + + The SecurityContextHolderAwareRequestFilter, if you are using + it to install a Spring Security aware HttpServletRequestWrapper + into your servlet container + + + RememberMeProcessingFilter, so that if no earlier + authentication processing mechanism updated the + SecurityContextHolder, and the request presents a cookie that + enables remember-me services to take place, a suitable remembered + Authentication object will be put there + + + AnonymousProcessingFilter, so that if no earlier + authentication processing mechanism updated the + SecurityContextHolder, an anonymous + Authentication object will be put there + + + ExceptionTranslationFilter, to catch any Spring Security + exceptions so that either an HTTP error response can be returned or an appropriate + AuthenticationEntryPoint can be launched + + + FilterSecurityInterceptor, to protect web URIs and raise + exceptions when access is denied + + +
+
+ Use with other Filter-Based Frameworks + If you're using some other framework that is also filter-based, then you need to make + sure that the Spring Security filters come first. This enables the + SecurityContextHolder to be populated in time for use by the other + filters. Examples are the use of SiteMesh to decorate your web pages or a web framework like + Wicket which uses a filter to handle its requests. +
+
+ +