Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Migrated to Confluence 5.3

...

What's going on in security.xml

Acegi's filter, which gets called first for each incoming request, checks to see if the request is authenticated. If it is, then Acegi wraps the incoming HttpServletRequest object to ensure that request.isUserInRole() and request.getUserPrincipal() return the right values. If not, then Acegi redirects the user to the login page and then back to the originally requested page on successful login or to the login error page on failure.

To configure Acegi to protect our URLs and to authenticate against the Roller user and role tables, we create a twisty maze of nested Java beans strung together by XML in the Acegi configuration file security.xml. You'll have to understand a bit about Spring and spend some time reading the Acegi Javadocs before you can write one yourself. I'll explain what Roller's does at a high-level.

filterChainProxy

The first thing you must understand about Acegi is that it uses its own filterChainProxy to define the series of events that are going to take place as part of the Acegi authentication/authorization workflow. So to add/modify/remove any functionality you must first make adjust the filterChainProxy, which is the first bean listed in the security.xml. In that bean you will see line like this which sets the chain we use ...

Code Block

/**=channelProcessingFilter,httpSessionContextIntegrationFilter,remoteUserFilter,authenticationProcessin
gFilter,rememberMeProcessingFilter,anonymousProcessingFilter,exceptionTranslation
Filter,filterInvocationInterceptor

Each item in the chain will be processed sequentially and be given its chance to affect the workflow. Here's what the various filters mean ...

channelProcessingFilter

The ChannelProcessingFilter is responsible for doing scheme enforcement. This means that if a request is supposed to be done over a specific scheme (http/https) and the current request is not using the right scheme, it will force the client to be redirected to the right scheme. We mainly use this to force https for logins and a few other things.

httpSessionContextIntegrationFilter

The HttpSessionContextIntegrationFilter is what Acegi uses to make sure a session is maintained across multiple requests. In Acegi the primary object that represents a client session is called a SessionContext and all other information about a session is available through that object. This filter is used to load/store the SessionContext object in the standard servlet HttpSession so that it is available between requests.

This filter must be early on in the chain.

remoteUserFilter

The SecurityContextHolderAwareRequestFilter, which we call the remoteUserFilter, is a filter which wraps the servlet request object using a custom Acegi request wrapper so that various authentication/authorization methods of the request are properly implemented to work with Acegi. This is how request.getUserPrincipal() and request.isUserInRole() are made to work.

authenticationProcessingFilter

The AuthenticationProcessingFilter is the filter which actual checks for submitted login credentials and uses them to attempt to setup a client session by creating an Authorization object. The Authorization object is Acegi's way of indicating a client session is authentic and it holds information about authentic client.

In a nutshell what this filter does is it looks for requests posted to the filterProcessesUrl, /roller_j_security_check in our case, and for those requests it uses the submitted information to try and login the client. Much of the work is delegated to supporting beans such as the authenticationManager to do the actual authentication bit, but in the end it is this filter which makes login possible.

rememberMeProcessingFilter

The RememberMeProcessingFilter is how we allow for "remembered" sessions. When this filter is reached, if Acegi does not already have a valid Authentication for the client's session then it consults any configured rememberMeServices which are given a chance to attempt an "auto-login". This is basically the same thing as an SSO login. Normally you would do this by looking for a special cookie and value which you can use to identify the client as being authentic, then use that information to create and Authentication object.

In Roller's case this is done via one of Acegi's stock remember me tools which uses a hashed cookie to mark a session that can be "remembered".

anonymousProcessingFilter

The AnonymousProcessingFilter is meant to be the last filter in the authentication phase of the Acegi workflow. All it does is checks if the client session has a valid Authentication and if not it grants a simple anonymous Authentication. This is just Acegi's way of marking the client as officially anonymous.

exceptionTranslationFilter

The ExceptionTranslationFilter is used to translate exceptions into actions. We don't really use this much, but it is used to translate a failed authentication exception from the AuthenticationProcessingFilter into an action which sends the client to the "login failed" page. So it's looking for exceptions that happened earlier in the workflow and translates them into some kind of action if it finds them.

filterInvocationInterceptor

The FilterSecurityInterceptor is the filter which handles the authorization part of the Acegi security model. To define the URLs to be protected and the roles required for each, we configure a FilterSecurityInterceptor with the rules listed below in security.xml. The rules say that most URL patterns require either the admin or editor role, but the /roller-ui/admin and /rewrite-status URLs are only for admin users.

Code Block
    /roller-ui/login-redirect**=admin,editor
    /roller-ui/profile**=admin,editor
    /roller-ui/createWeblog**=admin,editor
    /roller-ui/menu**=admin,editor
    /roller-ui/authoring/**=admin,editor
    /roller-ui/admin/**=admin
    /rewrite-status*=admin

As you would expect, this is the last filter in the chain because if a client gets past here then we assume they are authorized to access whatever they are requesting.

Acegi authentication providers

To setup Acegi to authenticate against the Roller database, we configure a Acegi ProviderManager, which has a Acegi DaoAuthenticationProvider, which has a RollerUserDetailsService, a Roller provided class that creates an Acegi UserDetails object by reading from the Roller database. That's how Acegi gets user and role information from Roller. And we configure various other beans to tell Acegi that the Roller login page is at URL /roller-ui/login.rol, the login error page is /roller-ui/login.rol?error=true and to configure Acegi's Remember Me feature.

The RollerUserDetailsService uses Roller's database layer to fetch user details. So, we don't have to ask our users to go through the tedious and error prone process of seting up a JDBC Realm as we would have had to do if we were using plain old Servlet Authentication.

What about authentication for webservices?

Authentication for Roller's remote apis and web services is handled completely separately from the Acegi authentication and authorization which controls access to the web authoring tools. Acegi has no part in webservice authentication and so all authentication to webservices is part of the api and happens via checks directly against the Roller UserManager.

The end

1 security experts frown at Force Secure Login, but Roller site administrators want that option.