Help is available by sending an email to csf-support@mit.edu
Have any suggestion on how improve this wiki?  Please give us your feedback at csf-support@mit.edu

About this document

This document is a brief description of the processing that occurs to authenticate and authorize an HTTP request using Spring Security and the CSF, highlighting features that are useful for application developers to know about.

The processing has two parts. One part is performed by Spring Security, and the other part is performed by CSF code.

Quick Links to:

Spring Security

Spring Security is part of the Spring Framework and it abstracts authentication and authorization processing in a manner that allows them to be customized for a particular set of requirements. For web applications, Spring Security is "plugged in" as a servlet filter. If the Spring Security servlet filter is configured in the web.xml then Spring Security will be called on each request to the servlet.

Spring Security processing is composed of parts that are assembled into what is called a "filter chain". Those parts are themselves customized by injection of service beans. The filters in an Spring Security filter chain are not the same as servlet filters, although the general concept is the same. The filter chain determines the sequence of authorization and authentication processing, and the inclusion of authentication protocols.

The end result of running the filter chain is that access is either granted or denied to the resource requested. Granted access creates an Spring Security Security Context for the request, which an application may consult for roles and user information collected previously during the Spring Security processing.  Denied access should cause an access denied message to be returned to the user.

CSF

The CSF provides a wrapper around Spring Security, so that applications are not directly tied to a particular security framework implementation. It also provides services to the Spring Security filter chain that handle the specifics of authentication and authorization as are customary or required at MIT. For example, it provides services for SSO authentication, and the following services to obtain roles either separately or in combination :

  • MIT Roles database
  • Student role
  • Instructor role
  • STV_ROLES
  • STVACC roles

With potentially many more possibilities.

It also provides an impersonation function that is useful during testing and problem diagnosis.

It also provides local development environments a way to test different roles and users with an application.

The Filter Chain Proxy and the Spring Security filters

Complexity is the price of flexibility. There are several interacting system artifacts, the components and their configurations.

Spring Security itself and the CSF components are all configured using the Spring context. Configurations for Spring Security and framework components related to it are found in the applicationContext-common-security.xml of an application or in CSF. Some configuration entries in web.xml and applicationContext-web.xml are also important. When you look at the entries in these files there are many more than what are described in this document, however, it is unusual to have to change entries not discussed.

The configuration bean for the filter chain is called the filterChainProxy. Here is a sample configuration:

	<bean id="filterChainProxy" class="org.springframework.security.web.FilterChainProxy">
        <security:filter-chain-map path-type="ant">
           <security:filter-chain pattern="/css/**" filters="logoutFilter" />
           <security:filter-chain pattern="/img/**" filters="logoutFilter" />
           <security:filter-chain pattern="/js/**" filters="logoutFilter" />
           <security:filter-chain pattern="/docs/**" filters="logoutFilter" />
           <security:filter-chain pattern="/**" filters="httpSessionContextIntegrationFilter,
           		logoutFilter,
           		ssoAuthenticationProcessingFilter,
           		basicAuthenticationProcessingFilter,
           		exceptionTranslationFilter,
           		filterSecurityInterceptor,
           		switchUserProcessingFilter"
           />
        </security:filter-chain-map>
	</bean>

In this example,

  1. We are telling the filter chain to run, that is authenticate and authorize, on url patterns that match everything except the contents of /images, /js, /css, and /docs.
  2. We are constructing the filter chain components processing order. The components are references to beans defined in the Spring context.

The beans in this example serve the following functions :

  • httpSessionContextIntegrationFilter: Gets an existing security context from the HTTP session, or creates a new empty context.
  • 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. This includes the list of roles that the user is authorized for, based on the results of calling the configured authorization services ( see below ).
  • basicAuthenticationProcessingFilter: If authentication has not already been established ( that is by either being present in the session or by SSO ), and the local.authentication property has been set, performs HTTP Basic authentication. The user is prompted for a username and password, which must match what is configured in the application property file.  This filter is intended as a solution to running the application with a security context in the absence of SSO, which is the situation on developer's local workstations. This filter checks that the user and password entered in the login prompt in the browser match the property values for Local Authentication Properties. It then sets up all the data structures needed by the security context. This includes the list of roles that the user is authorized for, based on the results of calling the configured authorization services ( see below ).
  • Local Authentication Properties: A set of CSF properties that can be used to directly set the user and roles in local development environments.

    local.authentication=true
    local.user.name=beaver
    local.user.password=whatever

    All of the above properties must be present to set a user.  The local authentication properties should never be set on Education Systems servers.
    They are set in the Application Property File that resides in the user's home folder.

    Roles may be set also, here is an example:

    local.mitroles = WTW_REPORT_ADMIN | 1 5 21W, WTW_READ

    This sets two roles, WTW_REPORT_ADMIN and WTW_READ, and also sets qualifier codes 1, 5, and 21W on WTW_REPORT_ADMIN. The meaning of qualifier codes is role dependent, and some roles have no qualifiers. In this case the qualifiers represent departments that the user has this role for.

    Only MIT roles database roles may be set this way. Other roles like instructor and student are best set by setting the user as shown above to a student or instructor.
  • 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 the user is not authorized, then the AccessDeniedHandler is called.
  • 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. 

There are several other filters in the CSF.

The Authorization Framework

As mentioned above, filters that authenticate users also get the "details" for the authenticated user, that is, the user's authorizations, to put into the security context. In CSF, there is a single bean that is configured to get the user details, the mitAuthorizationUserDetailService.

Here is a sample configuration:

    <!-- the Spring Security adapter for MIT authorizations retrieval -->
    <bean id="mitAuthorizationUserDetailService" class="edu.mit.csf.security.spring.userdetails.MitAuthorizationUserDetailsService">
        <property name="authorizationService" ref="authorizationService"/>
    </bean>

    <!-- MIT Roles database authorization -->
    <bean id="mitRolesAuthorizationService" class="edu.mit.csf.security.service.MitRolesAuthorizationService">
        <property name="applicationConfiguration" ref="applicationConfiguration" />
        <property name="uaSao" ref="uaSao" />
        <!-- all the academic services apps use this domain, same as category in MIT Roles -->
        <property name="domain" value="REG" />
        <!-- if you have this property value in your applicationConfiguration then
        getDomain be overridden with the value this property -->
        <property name="domainProperty" value="roles.function.category"/>
        <property name="functionProperty" value="roles.function.function"/>
    </bean>

The beans and property definitions in this example serve the following functions:

mitAuthorizationUserDetailService bean: acts as an adapter between the Spring Security security system and the authorization classes in CSF.

authorizationService bean: CSF bean that implements the AuthorizationService interface. In this example, it is an implementation that delegates to a chain of other AuthorizationService implementations, one for determining if the user is a student, and another to obtain the roles the user may have in the MIT Roles database. The combine = false property means that roles from the two services will not be combined, that is, either the role student will be assigned to the user or the MIT roles, but not both. If combine = true the user would be assigned all roles found.

Application access to a user's roles in the Security Context

It is not uncommon for applications to need access to roles information that may be collected by Spring Security and the CSF. CSF provides facilities to make this easier.

IMPORTANT: when you are writing Java code that needs authorization information about the current user, use the methods on the CSF "SecurityContextService" interface rather than using Spring Security classes. This will insulate us from any future changes in the Spring Security framework classes.

Lets take the example of an application that needs to display a list of sections for the user to choose, which will allow them to view the students assigned to the section, and there is a rule that the class lists are only to be shown to instructors of the section.

First, we need to configure the authorization service to capture whether the user is an instructor.

 <bean id="mitAuthorizationUserDetailService" class="edu.mit.csf.security.spring.userdetails.MitAuthorizationUserDetailsService">
	<property name="authorizationService"  ref="authorizationService" />
 </bean>

 <bean id="authorizationService" class="edu.mit.common.security.authorization.InstructorAuthorizationsService">
        <property name="dao" ref="hibernateAuthorizedInstructorDao" />
 </bean>

In this example, the instructorAuthorizationsService and hibernateAuthorizedInstructorDao bean are Spring beans defined elsewhere. The InstructorAuthorizationService has a single method, getAuthorizationsByUser. This method uses the dao to fetch the user's instructor records as an AuthorizedInstructor object containing a collection of AuthorizedTeachingAssignment objects. This is wrapped in an InstructorRoleAuthorization object which is an adaptor for communicating with Spring Security. All of this is done merely by creating the configuration above.

A little later in the application processing, we will have a list of sections, and we want to filter the list to only include those that the instructor has taught. Probably first you would want to check that the user is in fact an instructor, that is, has at least taught some section  at some time, and if not, perhaps show them a different page:

boolean isInstructor = securityContextService.hasAnyRole(new String[] { InstructorRoleAuthorization.ROLE_INSTRUCTOR });

if ( isInstructor ) {

  Set allowedSections = securityContextService.getMaskedQualifiersForRole(InstructorRoleAuthorization.ROLE_INSTRUCTOR, allSections);
  // put allowedSections in model map ...

} else {
 // not so fast buster !
}

The mask method takes a collection of things that might be associated with a role and returns a set of things that actually are associated with the role. The things you can filter this way depends on the kind of role. For instructors, you can filter collections of subjects, sections, or teaching assignments. For MIT Roles Database roles that have qualifiers you can filter a collection of strings that would match the qualifier codes.

Impersonation

Impersonation that is a regular part of an application's feature set delivered to MIT administrators is accomplished with an additional filter on the Spring Security filter chain called the switchProcessingUserFilter.This basically gives authorized users a "login" button or link that logs them in as another user. 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.

There are a couple of things that are required to use this filter.

  1. There must be a role, usually in the MIT Roles database, associated with users allowed to do the impersonation.
  2. The login url should be protected at the page level with this role. Third, the login url, and a logout url, should be implemented and configured on the filter. Fourth, the filter should be added to the filterChainProxy bean configuration, after the filterSecurityInterceptor, since we have to get the "can impersonate" role first. ( Example TBD )

Page level security

One may also configure a mapping of roles to page urls. In the example above where we were testing if a user had the instructor role before showing them a page to select sections to view, instead of writing code, we could have  declared our protection like this:

	<bean id="filterSecurityInterceptor" class="org.springframework.security.web.access.intercept.FilterSecurityInterceptor">
		<property name="authenticationManager" ref="authenticationManager"/>
		<property name="accessDecisionManager" ref="accessDecisionManager"/>
                <property name="securityMetadataSource">
                   <security:filter-security-metadata-source>
                         <security:intercept-url pattern="/advisor_reg_summary.htm" access="ROLE_OREG_REGISTRAR,ROLE_OREG_DEPT_ADMIN,ROLE_OREG_ADVISOR" />
                         <security:intercept-url pattern="/agreement.htm" access="ROLE_CURRENT_STUDENT" />
                   </security:filter-security-metadata-source>
                </property>
        </bean>

and the Spring Security framework would have invoked the access denied handler when a user who did not have this role tried to access the page. We could then write the access denied handler to show a page with a friendly message or perhaps redirect the user somewhere they are supposed to be instead.

The "pattern" attributes specify which URL(s) are to be restricted. Patterns can specify a specific page, as in the above examples, or can specify a range of URLs via wildcards. For example, the following pattern would restrict all pages under the "admin" folder to users with the "ADMIN" role:

    <security:intercept-url pattern="/admin/*" access="ROLE_ADMIN" />

Overlapping patterns can also be specified: the latter-defined patterns will override the earlier patterns. An example of this usage would be a section of a web site generally restricted to DINING users, but with certain pages also open to REGISTRAR users. We would define a general pattern to implement the DINING users restriction, and a second more specific pattern giving the REGISTRAR users access to particular pages:

    <security:intercept-url pattern="/dining/*" access="ROLE_DINING" />
    <security:intercept-url pattern="/dining/some_shared_page.htm" access="ROLE_DINING,ROLE_REGISTRAR" />
  • No labels