A brief description of the processing that occurs to authenticate and authorize an HTTP request using Acegi and the SAIS Framework.
The HTTP request is passed through a series of filters, called the filter chain. Each filter performs a specific task in a particular order. The filter chain is configured in the applicationContext-web.xml file, located in src/main/resources of the application. Upon successful authentication and authorization a SecurityContext is established that can be used by the application.
The configuration bean that holds the filter configuration is called the filterChainProxy. As the name suggests, it acts as an interface to the filter chain. A filter using this proxy class is also defined in the web.xml so it gets used.
<bean id="filterChainProxy" class="org.acegisecurity.util.FilterChainProxy"> <property name="filterInvocationDefinitionSource"> <value> PATTERN_TYPE_APACHE_ANT /css/**=#NONE# /dhtml/**=#NONE# /images/**=#NONE# /js/**=#NONE# /**=httpSessionContextIntegrationFilter,exceptionTranslationFilter,ssoAuthenticationProcessingFilter,mitBasicProcessingFilter,filterSecurityInterceptor,switchUserProcessingFilter </value> </property> </bean>
The filter chain run order is defined on the line starting with "/**=httpSessionContextIntegrationFilter". The items in this list are also configured bean references. They perform the following functions:
httpSessionContextIntegrationFilter: Gets an existing security context from the session, or creates a new empty context.
exceptionTranslationFilter: catches all exceptions from the filters that follow. Applies configured exception handlers based on the exception type caught. For example, if an AuthenticationException is thrown, indicating that the request is not authenticated yet, then it calls the method to start the authentication process. If an AccessDeniedException is thrown, indicating that authentication has failed, then the AccessDeniedHandler is called. The default handler simply sends an access denies http response code in the response header.
ssoAuthenticationProcessingFilter: If authentication has not already been established in the SecurityContext ( that is was not present in the session ), checks to see if the user is already set in the servlet request, indicating that SSO has authenticated the user. If so, it sets up all the data structures needed by the security context, and sets them into the context. This includes the list of roles that the user is authorized for, based on the results of calling the configured authorization services.
mitBasicProcessingFilter: If authentication has not already been established ( that is by either being present in the session of by the ssoAuthenticationProcessingFilter ), and the local authentication property has been set in the application property file, performs Basic authentication against the local credentials configured in the application property file. Basic authentication is a two step process that requires two requests. The first request that is unauthenticated will result in an AuthenticationException, which results in the start of the Basic authentication process, which sends a response with an authentication request in the header. Browsers interpret this to show the familiar ugly login box to the user. When the user submits the login credentials in what is now the second request, it contains a header with the credentials. The presence of this header is detected by the mitBasicProcessingFilter and the credentials are compared to the values from the property file. If there is a match the data structures for the security context are configured including the list of roles from the configured authorization services. However in this case the presence of role properties in the application property file will bypass the calls to the authorization services.
filterSecurityInterceptor: Secures the requested HTTP resource(s) based on the SecurityContext. The work is delegated to a number of helpers configured for this bean. Requires a definition of what resources are to be protected and what roles apply. If the requested resource is supposed to be protected and there is no established authentication in the SecurityContext by this point, it throws an AuthenticationException which is handled as described before. Otherwise, it will determine if authorization in the SecurityContext is sufficient for access to the resource, throwing AccessDeniedException if appropriate.
switchProcessingUserFilter: This is an optional filter that the allows a user to invoke a URL that lets them impersonate another user. Since access to this feature usually requires that the request be authorized for the URL resource that performs the switch, it follows the filterSecurityInterceptor in the chain. Once the switch is performed, the SecurityContext contains the credentials for a different user, but it also remembers the original user so impersonation may be exited and the original credentials restored.
The beans that determines which authorization services will be called to get the authenticated user's roles looks as follows:
<bean id="mitsisRolesUserDetailsService" class="edu.mit.common.security.acegi.userdetails.MitsisRolesUserDetailsService"> <property name="authorizationService" ref="authorizationService" /> </bean> <bean id="authorizationService" class="edu.mit.common.security.authorization.MultipleAuthorizationsService"> <property name="combine" value="false" /> <property name="authorizationServices"> <list> <ref bean="studentRoleAuthorizationService" /> <ref bean="mitRolesAuthorizationService" /> </list> </property> </bean>
mitsisRolesUserDetailsService: acts as an adapter between the Acegi security system and the authorization classes in the SAIS framework.