Lately I've been busy learning and trying out the Acegi Security System, which is a security framework for the Spring Framework. It's not the easiest framework to grasp, but if you have the time and will, it will pay off. During the process of learning it, I created a diagram to help me understand, and now I decided to create a small introduction around it.
Remember, this is just an example of a possible Acegi configuration. Acegi Security is very flexible and has a lot more features (like single-sign-on and remember-me services).
Introduction
Acegi is based on servlet filters. This has one big advantage: it decouples your application from Acegi. And this makes it easier to add Acegi to an already working application, for example.
For simplicity sake, there's no need to declare all filters on the
web.xml. You can use
FilterChainProxy which encapsulates a group of filters and executes them in order. As you can see in the picture, we can have 3 filters lined up. Ignoring the
HttpSessionIntegrationFilter for now, the other two,
AuthenticationProcessingFilter and
SecurityEnforcementFilter, implement Authentication and Authorization, respectively.
AuthenticationAuthentication is the process of confirming that a user is who he claims to be. Typically, this is done by supplying an username and a password (in Acegi concepts those are called
Principal and
Credentials, respectively). In a web environment, normally, the username and password are provided as a result of an HTML form submit. This submission is captured by the
AuthenticationProcessingFilter (it analyzes the URLs passing by, looking for the configured string, that is passed by the form's "action" property)
AuthenticationProcessingFilter then calls
AuthenticationManager, which starts the process of authenticating. First step is to find the user in some repository, based on the given username. Next, the credentials are compared, and if they are equal, authentication is successful.
The base class in this process is the
Authentication class. It's a simple bean composed of a
Principal, Credentials and a few
Authorities (this normally means user "roles").
AuthenticationProcessingFilter creates a new
Authentication Object with the specified username and password, and if authentication succeeds, at the end of the process the
Authentication Object will be filled with some Authorities.
But first, we need to find the claimed user in the system. There can be a variety of user repositories in the system (database, ldap, etc). Each of these repositories can be accessed through an
AuthenticationProvider. The role of the
AuthenticationManager is to maintain a collection of these providers.
Acegi has a few different types of
AuthenticationProviders, but probably the most used is the
DaoAuthenticationProvider. This
AuthenticationProvider uses a DAO (Data Access Object) to retrieve the user from a repository (typically a database). You can use the provided
JdbcDaoImpl to connect to a database through JDBC and retrieve the user information, without writing any code. However, is quite simple to implement your own Dao (I did it because I was using
Hibernate): just one method that retrieves a
User based on a username.
AuthorizationAuthorization is the process of protecting resources by only allowing those resources to be used by users that have been granted authority to use them.
SecurityEnforcementFilter is the filter responsible for the authorization process. It uses a FilterSecurityInterceptor to identify the resources that need to be secured. It holds a collection of patterns (regular expressions) and authorities (an Authority is normally just a string representing an user role). When an URL is identified by one of the patterns, the related authorities must be present in the
Authentication object (the one that was created by the authentication process). If there is no
Authentication object (the user has not logged in yet) or if the given
Authentication does not have the authorities the resource requires, then the application is redirected to a configured
AuthenticationProcessingFilterEntryPoint. This normally just represents an URL to a login form.
Now for the first filter,
HttpSessionIntegrationFilter...this is responsible for integrating the
Authentication object with the HTTP Session. The authentication and authorization processes talked before don't really interact with the HTTP Session. They aren't even aware there is such a thing. They use a
SecurityContextHolder to retrieve a
SecurityContext, which contains the
Authentication object. When a request is made,
HttpSessionIntegrationFilter loads the
SecurityContext from the Session and stores it in the
SecurityContextHolder, where all subsequent filters can access it. At the end of the request, the
SecurityContext (that may have been altered during the request) is stored again in the Session. This kind of design is very flexible... all the authentication and authorization processes are independent of HTTP session handling. Thus, we could provide a
SecurityContext in any other way.
HttpSessionIntegrationFilter it's just a thin layer on top of the rest of the Acegi Security System.