Security

When trouble-shooting security issues it's often useful to confirm who the user is and what, if any, additional information is associated with that user.

Previously this was possible (to a limited extent) by starting a client in debug mode and viewing the page source, which would contain information about the user in a comment at the bottom of the page. But as of Weave 2.6.5 there's also a link that will return all the available information about the user in a single response, that link is /weave/whoami. If you open that page you will see a response that provides all of the details for the user.

If the user is not logged in the page should indicate that the user is an anonymous user but will still provide some additional details, such as their IP address. If the user is logged in it will show their username and roles along with the other details. This can be particularly useful to verify that the roles that are associated with a user are the same as the role names that are being used in an ACL, or that the IP address being returned for a user is actually the users IP address and not something else, for example the IP address of a reverse proxy.

Overview

The front line for security in Weave is Acegi security (now Spring Security). Acegi security system is a formidable, easy-to-use alternative to writing custom security code for Java enterprise applications. Weave utilises the plugin nature of the Acegi to provide a highly customisable authentication mechanism while minimising the amount of security-specific code.


Starting with Weave version 2.5, a newer version of Acegi security, known as Spring Security is supported (at the time of this writing, Spring Security version 3.2). For more information on Spring security configuration, refer Spring Security.

Authentication and Authorisation

Authentication and authorisation are multi-stage processes. Firstly the user must be identified. By default they are an "anonymous" user, but this can be changed by users going to the login page (either directly themselves or being forced to by Weave) or by enabling Windows integrated authentication (which uses their Windows login username). Third-party authentication systems can be configured for this purpose via an Acegi security plugin.

Secondly, we need to determine what Roles the user has, again this can be done a number of ways, one of which is going to Active Directory (AD) and determining what AD Groups the user is a member of. In fact, any user attribute that's associated with a user in AD can be used to determine their role but group membership is the most common.

Thus, determining a user's identity and their roles occur outside of Weave and is handled by Acegi security.


Specifics of Windows authentication are covered here

Weave Access Control Lists

Once a user is authenticated and their roles are known, Weave Access Control Lists (ACLs) come in to play. ACLs provide a way of attaching an access decision to an object.

E.g. a) for object A: users with ROLE_X will be denied access but users with ROLE_Y will be allowed

        b) for object B: anonymous users and users with ROLE_X will be denied access but everyone else will be allowed access

As well as roles, a user's userid can also be used in an ACL when a specific users need to be targeted, either to remove access or grant it.

Refer to the section on Access Control List for more information.

Acegi Security System

The following sections describe details about how Acegi security works internally.

Acegi security system uses security filters to provide authentication and authorisation services to enterprise applications.
The framework offers several types of filters that you can configure according to your application requirements.

You can configure security filters for the following tasks:

  1. Prompt the user for login before accessing a secure resource.
  2. Authenticate the user by checking a security token such as a password.
  3. Check whether an authenticated user has the privilege to access a secure resource.
  4. Redirect a successfully authenticated and authorised user to the secure resource requested.
  5. Display an Access Denied page to a user who does not have the privilege to access a secure resource.
  6. Remember a successfully authenticated user on the server and set a secure cookie on the user's client. The next authentication can then be performed using the cookie and without asking the user to log in.
  7. Store authentication information in server-side session objects to securely serve subsequent requests for resources.
  8. Build and maintain a cache of security information in server-side objects to optimise performance.
  9. When the user signs out, destroy server-side objects maintained for the user's secure session.
  10. Communicate with a variety of back-end data storage services (like a directory service or a relational database) that are used to store users' security information and the ECM's access-control policies.

As this list suggests, Acegi filters allow you to do almost anything you might require to secure enterprise applications.

Architecture and components

This section introduces Acegi's components; next, you will learn how the framework uses inversion of control (IOC) and XML configuration files to combine components and express their dependencies.

The Big Four

Acegi consists of four main types of component: filters, managers, providers, and handlers.

Filters - These mostly high-level components provide common security services like authentication processing, session handling, and logout. Filters are only a high-level abstraction of security-related functionality: managers and providers are used to actually implement authentication processing and logout services.

Managers - Managers manage lower-level security services offered by different providers.

Providers - A variety of providers are available to communicate with different types of data storage services, such as directory services, relational databases, or simple in-memory objects. This means you can store your user base and access control policies in any of these data storage services and Acegi's managers will select appropriate providers at run time.

Handlers - Tasks are sometimes broken up into multiple steps with each step performed by a specific handler. For example, Acegi's logout filter uses two handlers to sign out an HTTP client. One handler invalidates a user's HTTP session and another handler destroys the user's cookie. Having multiple handlers provides flexibility when configuring Acegi to work according to your application requirements. You can select the handlers of your choice to execute the steps required to secure your application.

Inversion of control

Acegi's components are dependent on each other to secure enterprise applications.
For example, an authentication processing filter requires an authentication manager to select an appropriate authentication provider. This means you must be able to express and manage the dependency of Acegi's components.

An IOC implementation is commonly used to manage the dependencies of Java components. IOC offers two important features:

  1. It provides a syntax to express which components are required in an application and how they depend on each other.
  2. It ensures that the required components are available at run time.

The XML configuration file

Acegi uses the popular open-source IOC implementation that comes with the Spring framework (see Resources) to manage its components. Spring uses an XML configuration file to express the dependency of components, similar to the following:

<beans>
    <bean id="filterChainProxy" class="org.acegisecurity.util.FilterChainProxy">
        <property name="filterInvocationDefinitionSource">
            <value> value here </value>
        </property>
    </bean>

    <bean id="authenticationProcessingFilter"
        class="org.acegisecurity.ui.webapp.AuthenticationProcessingFitler">
        <property name="authenticationManager" ref="authManager"/>
        <!-- Other properties -->
    </bean>

    <bean id="authManager"
        class="org.acegisecurity.providers.ProviderManager">
        <property name="providers">
            <!--  List of providers here -->
        </property>
    </bean>
    <!-- Other bean tags -->
</beans>

As you can see, the Spring XML configuration file used by Acegi contains a single <beans> tag that wraps a number of other <bean> tags. All Acegi components (that is, filters, managers, providers, etc.) are actually JavaBeans. Each <bean> tag in the XML configuration file represents a Spring  security component.

Further notes about the XML configuration file

The first thing you will note is that each <bean> tag has a class attribute that identifies the class that the component uses. The <bean> tag also has an id attribute that identifies the instance (Java object) acting as a Acegi component.

For instance, the first <bean> tag of the above example identifies a component instance named filterChainProxy which is an instance of a class named org.acegisecurity.util.FilterChainProxy.

The dependency of a bean is expressed using child tags of the <bean> tag. For example, notice the <property> child tag of the first <bean> tag. The <property> child tag defines values or other beans on which the <bean> tag depends.

So in the example, the <property> child tag of the first <bean> tag has a name attribute and a <value> child tag, which respectively define the name and value of the property on which the bean depends. Likewise, the second and third <bean> tags of the example define that a filter bean depends on a manager bean. The second <bean> tag represents the filter bean and the third <bean> tag represents the manager bean.

The <bean> tag for the filter contains a <property> child tag with two attributes, name and ref.

The name attribute defines a property of the filter bean and the ref attribute refers to the instance (name) of the manager bean.

The next section shows you how to configure Acegi filters in an XML configuration file.

Security filters

As previously mentioned, Acegi uses security filters to provide authentication and authorisation services to enterprise applications. You can use and configure various types of filters according to your application requirements. The following sections introduce the five most important Acegi filters.

Session Integration Filter

Acegi's Session Integration Filter (SIF) is normally the first filter you will configure.
SIF creates a security context object, which is a placeholder for security-related information.
Other Acegi filters save security information in the security context and also use the information available in the security context.

SIF creates the security context and calls other filters in the filter chain.
Other filters then retrieve the security context and make changes to it.
For example, the Authentication Processing Filter (which is discussed next) stores user information such as username, password, and e-mail address in the security context.

When all the filters have finished processing, SIF checks the security context for updates.
If any filter has made changes to the security context, SIF saves the changes into a server-side session object. If no changes are found in the security context, SIF discards it.

SIF is configured in the XML configuration file as follows:

<bean id="httpSessionContextIntegrationFilter"        
     class="org.acegisecurity.context.HttpSessionContextIntegrationFilter"/>

Authentication Processing Filter

Acegi uses the Authentication Processing Filter (APF) for authentication.
APF uses an authentication (or login) form, in which a user enters a username and password and triggers authentication.

APF performs all back-end authentication processing tasks such as extracting the username and password from the client request, reading the user's parameters from the back-end user base, and using the information to authenticate the user.

When you configure APF, you must provide the following parameters:

  • Authentication manager specifies the authentication manager to be used to manage authentication providers.
  • Filter processes URL specifies the URL to be accessed when the client presses the Sign In button on the login form. Upon receiving a request for this URL, Spriong security invokes APF.
  • Default target URL specifies the page to be presented to the user if authentication and authorisation is successful.
  • Authentication failure URL specifies the page the user sees if authentication fails.

APF fetches the username, password and other information from the user's request object. It then passes this information to the authentication manager. The authentication manager uses an appropriate provider to read detailed user information (such as username, password, e-mail address and the user's access rights or privileges) from the back-end user base, authenticates the user, and stores the information in an Authentication object.

Finally, APF saves the Authentication object in the security context created earlier by SIF.
The Authentication object stored in the security context will be used later to make authorization decisions.

Configure APF as shown in the following example:

<bean id="authenticationProcessingFilter"
    class="org.acegisecurity.ui.webapp.AuthenticationProcessingFilter">
    <property name="authenticationManager"
        ref="authenticationManager" />
    <property name="filterProcessesUrl"
        value="/j_acegi_security_check" />
    <property name="defaultTargetUrl"
        value="/protected/protected1.jsp" />
    <property name="authenticationFailureUrl"
        value="/login.jsp?login_error=1" />
</bean>

You can see from this code that APF depends on the four parameters discussed in "The Big Four".
Each parameter is configured as a <property> tag in the example.

Logout Processing Filter

Acegi uses a Logout Processing Filer (LPF) to manage logout processing. LPF operates when a logout request comes from a client. It identifies the logout request from the URL invoked by the client.

LPF is configured as shown in the following example:

<bean id="logoutFilter" class="org.acegisecurity.ui.logout.LogoutFilter">
    <constructor-arg value="/logoutSuccess.jsp"/>
    <constructor-arg>
        <list>
            <bean class="org.acegisecurity.ui.logout.SecurityContextLogoutHandler"/>
        </list>
    </constructor-arg>
</bean>

You can see that LPF takes two parameters in its constructor: the logout success URL (/logoutSuccess.jsp) and a list of handlers. The logout success URL is used to redirect the client after the logout process is complete. Handlers perform the actual logout process; I have configured only one handler because it is enough to invalidate the HTTP session.

Exception Translation Filter

The Exception Translation Filter (ETF) handles exceptional cases in the authentication and authorization procedure, such as when authorization fails. In these exceptional cases, ETF decides what to do.

For example, if a non-authenticated user attempts to access a protected resource, ETF serves the login page inviting the user to authenticate.

Similarly, in case of authorization failure, you can configure ETF to serve an Access Denied page.

ETF is configured as shown in the followign example:

<bean id="exceptionTranslationFilter"
    class="org.acegisecurity.ui.ExceptionTranslationFilter">
    <property name="authenticationEntryPoint">
        <bean 
            class="org.acegisecurity.ui.webapp.AuthenticationProcessingFilterEntryPoint">
            <property name="loginFormUrl" value="/login.jsp" />
        </bean>
    </property>
    <property name="accessDeniedHandler">
        <bean class="org.acegisecurity.ui.AccessDeniedHandlerImpl">
            <property name="errorPage" value="/accessDenied.jsp" />
        </bean>
    </property>
</bean>

As you can see from the above example, ETF takes two parameters named authenticationEntryPoint and accessDeniedHandler. The authenticationEntryPoint property specifies the login page and the accessDeniedHandler specifies the Access Denied page.

Interceptor filters

Acegi's interceptor filters are used to make authorization decisions. You need to configure interceptor filters to act after APF has performed a successful authentication. Interceptors use your application's access control policy to make authorisation decisions.

Later we will show you how to design access control policies, how to host them on a directory service, and how to configure Acegi to read your access control policy. For the moment however, we will stick to showing you how to configure a simple access control policy using Acegi.

You can divide configuring a simple access control policy into two steps:

  1. Writing the access control policy.
  2. Configuring Acegi's interceptor filter according to the policy.

Step # Writing a simple access control policy

Start by looking at the next example, which shows how to define a user and the user's role:

    alice=123,ROLE_HEAD_OF_ENGINEERING

The access control policy shown above defines a user named alice, whose password is 123 and whose role is ROLE_HEAD_OF_ENGINEERING.

Step 2. Configuring Acegi's interceptor filter

Interceptor filters use three components to make authorisation decisions, which I have configured in the next example:

<bean id="filterInvocationInterceptor"
    class="org.acegisecurity.intercept.web.FilterSecurityInterceptor">
    <property name="authenticationManager" ref="authenticationManager" />
    <property name="accessDecisionManager" ref="accessDecisionManager" />
    <property name="objectDefinitionSource">
        <value>
            CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
            PATTERN_TYPE_APACHE_ANT
            /protected/**=ROLE_HEAD_OF_ENGINEERING
            /**=IS_AUTHENTICATED_ANONYMOUSLY
        </value>
    </property>
    <!--  More properties of the interceptor filter -->
</bean>

As the example shows, the three components you need to configure are the authenticationManager, accessDecisionManager and objectDefinitionSource:

  • The authenticationManager component is the same as the authentication manager discussed when we introduced the Authentication Processing Filter. The interceptor filter can use the authenticationManager to re-authenticate a client during the authorization process.
  • The accessDecisionManager component manages the process of authorization, which will be discussed further later.
  • The objectDefinitionSource component contains access control definitions according to which authorization will take place. For example, the objectDefinitionSource property in the example contains two URLs (/protected/* and /) in its value. The value defines roles for these URLs. The role for the /protected/ URL is ROLE_HEAD_OF_ENGINEERING. You can define any roles you like, according to your application requirements.

Recall from the previous example that you defined ROLE_HEAD_OF_ENGINEERING for the user named alice. This means alice will be able to access the /protected/* URL.

How filters work

As you have learned already, Acegi's components are dependent on each other to secure your applications. Later you will see how to configure Acegi to apply security filters in a specific order, thus creating a chain of filters. For this purpose, Acegi maintains a filter chain object which wraps all the filters you have configured to secure your application.

The following steps describe the life cycle of the filter chain:

  1. A browser client sends an HTTP request to your application.
  2. The container receives the HTTP request and creates a request object that wraps information contained in the HTTP request. The container also creates a response object, which different filters can process to prepare an HTTP response for the requesting client. The container then invokes Acegi's filter chain proxy, which is a proxy filter. The proxy knows the sequences of actual filters to be applied. When the container invokes the proxy, it passes request, response, and filter chain objects to it.
  3. The proxy filter invokes the first filter in the filter chain, passing request, response, and filter chain objects to the filter.
  4. Filters in the chain do their processing one by one. A filter can terminate its processing at any time by calling the next filter in the chain. A filter may even choose to not perform any processing at all. For example, APF might terminate its processing upon discovering that an incoming request did not require authentication.
  5. When authentication filters have finished processing they pass request and response objects to the interceptor filter configured in your application.
  6. The interceptor decides whether the requesting client is authorized to access the requested resource.
  7. The interceptor transfers control to your application. For example, the JSP page requested by the client in case of successful authentication and authorization.
  8. Your application writes contents over the response object.
  9. The response object is now ready. The container translates the response object into an HTTP response and sends the response to the requesting client.

To help you further understand Acegi filters we will give you a closer look at the operation of two of them: the Session Integration Filter and the Authentication Processing Filter.

How SIF creates a security context

How SIF creates a security context:

  1. Acegi's filter chain proxy invokes SIF and passes request, response, and filter chain objects to it. Note that normally you will configure SIF as the first filter in the filter chain.
  2. SIF checks whether it has already processed this Web request or not. If it finds that it has, it does no further processing and transfers control to the next filter in the filter chain (see Step 4 below). If SIF finds that this is the first time it has been called during the given Web request, it sets a flag, which will be used next time to indicate that SIF has been called.
  3. SIF checks whether a session object exists and contains a security context. It retrieves the security context from the session object and places it in a temporary placeholder called security context holder. If the session object does not exist, SIF creates a new security context and puts it in the security context holder. Note that the security context holder exists in the application scope so that it is accessible to other security filters.
  4. SIF calls the next filter in the filter chain.
  5. Other filters may edit the security context.
  6. SIF receives control after the filter chain processing is complete.
  7. SIF checks whether any other filter changed the security context during its processing. For example, APF may have stored user details in the security context. If so, it updates the security context in the session object. This means that any changes made to the security context during filter chain processing now reside in the session object.

How APF authenticates a user

How APF authenticates a users:

  1. The previous filter in the filter chain passes request, response, and filter chain objects to APF.
  2. APF creates an authentication token with the username, password, and other information fetched from the request object.
  3. APF passes the authentication token to the authentication manager.
  4. The authentication manager may contain one or more authentication providers. Each provider supports exactly one type of authentication. The manager checks which of its providers support the authentication token it received from APF.
  5. The authentication manager passes the authentication token to the provider suitable for authentication.
  6. The authentication provider extracts the username from the authentication token and passes it to a service called user cache service. Acegi maintains a cache of users who have been authenticated. The next time the user signs in, Acegi can load his or her details (such as username, password, and privileges) from the cache instead of reading from back-end data storage. This improves performance.
  7. The user cache service checks whether details of the user exist in the cache.
  8. The user cache service returns the details of the user to the authentication provider. If the cache does not contain user details, it returns null.
  9. The authentication provider checks whether the cache service returned details of the user or null.
  10. If the cache returned null, the authentication provider passes the username (extracted in Step 6) to another service called user details service.
  11. The user details service communicates with the back-end data storage (such as a directory service) that contains details of the user.
  12. The user details service returns details of the user or throws an authentication exception if it cannot find details of the user.
  13. If either the user cache service or the user details service returns valid user details, the authentication provider matches the security token (such as a password) supplied by the user with the password returned by the cache or user details service. If a match is found, the authentication provider returns the details of the user to the authentication manager. Otherwise, it throws an authentication exception.
  14. The authentication manager returns details of the user back to APF. The user is now successfully authenticated.
  15. APF saves the user details in the security context created in Step 3 shown in the previous section.
  16. APF transfers control to the next filter in the filter chain.

A simple Weave configuration

You have learned quite a bit about Acegi so far, so we will now have a look at what you can do with what you have learned so far.

Securing Weave requires protecting certain resources, and if a user attempts to access any of the protected resources they will be presented with a login page. When the user signs in using the login page, the application automatically redirects to the requested protected resource.

The user can go directly to the login page, in which case the application presents the login page where the user can sign in. After signing in, the application redirects the user to a start page which is the default resource presented whenever the user signs in without requesting a particular resource.

Configuring Weave

For Weave the XML file that contains the beans used to configure Acegi is called security.xml and is stored in the same directory as the main config.xml file.

The following shows a simple security.xml file that secures Weave with information contained directly within the security.xml file itself

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">

<beans>
	<bean id="filterChainProxy" class="org.acegisecurity.util.FilterChainProxy">
		<property name="filterInvocationDefinitionSource">
			<!-- we use a different filter chain for requests sent to /server/request because they're JSON based requests
				and we want to send back a JSON formatted response if something goes wrong, so the only difference
				between the two filter chains is the exception translation filter -->
			<value>
				CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
				PATTERN_TYPE_APACHE_ANT
				/server/request/**=httpSessionContextIntegrationFilter,authenticationProcessingFilter,securityContextHolderAwareRequestFilter,rememberMeProcessingFilter,anonymousProcessingFilter,jsonExceptionTranslationFilter,filterInvocationInterceptor
				/**=httpSessionContextIntegrationFilter,authenticationProcessingFilter,securityContextHolderAwareRequestFilter,rememberMeProcessingFilter,anonymousProcessingFilter,exceptionTranslationFilter,filterInvocationInterceptor
			</value>
		</property>
	</bean>

	<bean id="httpSessionContextIntegrationFilter" class="org.acegisecurity.context.HttpSessionContextIntegrationFilter"/>

	<bean id="authenticationProcessingFilter" class="org.acegisecurity.ui.webapp.AuthenticationProcessingFilter">
		<property name="authenticationManager" ref="authenticationManager"/>
		<!-- A bundle must be available that provides the /login HttpContext that contains the login page with the login form -->
		<property name="authenticationFailureUrl" value="/login.html?failure=true"/>
		<property name="defaultTargetUrl" value="/"/>
		<!-- The bundle that provides the /security HttpContext is provided by the Cohga security bundle -->
		<property name="filterProcessesUrl" value="/security/j_acegi_security_check.do"/>
		<property name="rememberMeServices" ref="rememberMeServices"/>
	</bean>
   
	<bean id="securityContextHolderAwareRequestFilter" class="org.acegisecurity.wrapper.SecurityContextHolderAwareRequestFilter"/>

	<bean id="rememberMeProcessingFilter" class="org.acegisecurity.ui.rememberme.RememberMeProcessingFilter">
		<property name="authenticationManager" ref="authenticationManager"/>
		<property name="rememberMeServices" ref="rememberMeServices"/>
	</bean>

	<bean id="anonymousProcessingFilter" class="org.acegisecurity.providers.anonymous.AnonymousProcessingFilter">
		<property name="key" value="changeThis"/>
		<property name="userAttribute" value="anonymous,ROLE_ANONYMOUS"/>
	</bean>

	<!-- Problems between the user and the server will be handled with this filter, it converts the error to a format suitable for display directly to the user, i.e. an HTML page -->
	<bean id="exceptionTranslationFilter" class="org.acegisecurity.ui.ExceptionTranslationFilter">
		<property name="authenticationEntryPoint">
			<bean class="org.acegisecurity.ui.webapp.AuthenticationProcessingFilterEntryPoint">
				<property name="loginFormUrl" value="/login.html"/>
				<property name="forceHttps" value="false"/>
			</bean>
		</property>
		<property name="accessDeniedHandler">
			<bean class="org.acegisecurity.ui.AccessDeniedHandlerImpl">
				<property name="errorPage" value="/login.html?accessDenied=true"/>
			</bean>
		</property>
	</bean>

	<!-- Problems between the client and the server will be handled with this filter, it converts the error to a format that the client and decode and understand, i.e. a JSON response -->
	<bean id="jsonExceptionTranslationFilter" class="org.acegisecurity.ui.ExceptionTranslationFilter">
		<property name="authenticationEntryPoint">
			<bean class="org.acegisecurity.ui.webapp.AuthenticationProcessingFilterEntryPoint">
				<property name="loginFormUrl" value="/login/execute.do"/>
				<property name="forceHttps" value="false"/>
			</bean>
		</property>
		<property name="accessDeniedHandler">
			<bean class="org.acegisecurity.ui.AccessDeniedHandlerImpl">
				<property name="errorPage" value="/login/execute.do?accessDenied=true"/>
			</bean>
		</property>
	</bean>

	<bean id="filterInvocationInterceptor" class="org.acegisecurity.intercept.web.FilterSecurityInterceptor">
		<property name="authenticationManager" ref="authenticationManager"/>
		<property name="accessDecisionManager">
			<bean class="org.acegisecurity.vote.AffirmativeBased">
				<property name="allowIfAllAbstainDecisions" value="false"/>
				<property name="decisionVoters">
					<list>
						<bean class="org.acegisecurity.vote.RoleVoter"/>
						<bean class="org.acegisecurity.vote.AuthenticatedVoter"/>
					</list>
				</property>
			</bean>
		</property>
		<!-- Make sure that user is at least anonymous before getting access, Weave will do further checks based on ACLs to see if the user must login -->
		<property name="objectDefinitionSource">
			<value>
				CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
				PATTERN_TYPE_APACHE_ANT
				/server/status=ROLE_ADMIN
				/private.html=ROLE_USER
				/**=IS_AUTHENTICATED_ANONYMOUSLY
			</value>
		</property>
	</bean>

	<bean id="rememberMeServices" class="org.acegisecurity.ui.rememberme.TokenBasedRememberMeServices">
		<property name="userDetailsService" ref="userDetailsService"/>
		<property name="key" value="changeThis"/>
	</bean>

	<bean id="authenticationManager" class="org.acegisecurity.providers.ProviderManager">
		<property name="providers">
			<list>
				<ref local="daoAuthenticationProvider"/>
				<bean class="org.acegisecurity.providers.anonymous.AnonymousAuthenticationProvider">
					<property name="key" value="changeThis"/>
				</bean>
				<bean class="org.acegisecurity.providers.rememberme.RememberMeAuthenticationProvider">
					<property name="key" value="changeThis"/>
				</bean>
			</list>
		</property>
	</bean>

	<bean id="daoAuthenticationProvider" class="org.acegisecurity.providers.dao.DaoAuthenticationProvider">
		<property name="userDetailsService" ref="userDetailsService"/>
		<property name="userCache">
			<bean class="org.acegisecurity.providers.dao.cache.EhCacheBasedUserCache">
				<property name="cache">
					<bean class="org.springframework.cache.ehcache.EhCacheFactoryBean">
						<property name="cacheManager">
							<bean class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"/>
						</property>
						<property name="cacheName" value="userCache"/>
					</bean>
				</property>
			</bean>
		</property>
	</bean>

	<bean id="userDetailsService" class="org.acegisecurity.userdetails.memory.InMemoryDaoImpl">
		<property name="userMap">
			<value>
				alice=123,ROLE_USER
				bob=password,ROLE_USER,disabled
				carol=secret,ROLE_USER
				ted,abc,ROLE_USER,ROLE_ADMIN
			</value>
		</property>
	</bean>

</beans>

The above example is a fairly basic security filter that stores user information directly in the file but one thing to note here is that only one client is actually protected, private.

If there is more than one client configured for Weave then a user could have access to that one because from the above configuration the user will be logged on anonymously unless they have previously gone to the login page, or if they accessed the 'private' client directly.

So what is actually going on then? Well the important parts here are the two lines in the objectDefinitionSource:

/private.html=ROLE_USER
/**=IS_AUTHENTICATED_ANONYMOUSLY

Taking the second line first, this specifies that any resource (not previously matched) requires that the user be (at least) an anonymous user, but because of the first line any request for a resource matching private.html require that the user be part of the ROLE_USERS group, which means that they'll have to login to get the the private client since the user must access private.html to get to the private client.

Obviously there is more to the first line than meets the eye. It turns out that this URL is interpreted by the server as being requests to load a specific client configuration (called private in the above example) from config.xml.

So for our above example we can assume that the config.xml file contains at least something similar to the following:

<?xml version="1.0" encoding="UTF-8"?>
<config 
	xmlns="urn:com.cohga.server.config#1.0"
	xmlns:client="urn:com.cohga.html.client#1.0"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:xsd="http://www.w3.org/2001/XMLSchema">

	<client:config id="private">
		<client:default>true</client:default>
		<client:debug>false</client:debug>
		<client:title>Weave Private HTML Client</client:title>
		...
		
	</client:client>
</client>

Further, if we wish to provide a public and private client then we could add an additional client configuration, as follows:

<?xml version="1.0" encoding="UTF-8"?>
<config 
	xmlns="urn:com.cohga.server.config#1.0"
	xmlns:client="urn:com.cohga.html.client#1.0"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:xsd="http://www.w3.org/2001/XMLSchema">

	<client:config id="private">
		<client:default>false</client:default>
		<client:debug>false</client:debug>
		<client:title>Weave Private Client</client:title>
		...
		
	</client:client>

	<client:config id="public">
		<client:default>true</client:default>
		<client:debug>false</client:debug>
		<client:title>Weave Public Client</client:title>
		...
		
	</client:client>
</client>

Now the user has two different client configurations available, private and public, and they can access private using the URL /weave/private.html and public using /weave/public.html.
And, because of the way we have setup Acegi they will be asked to login to access private but will have direct access to public.

Of course this can be extended to provide multiple clients, both secure and un-secure, but creating different client configurations in config.xml and adding additional lines to the objectDefinitionSource.

Note that in future this may change and the security information provided in th objectDefinitionSource will be provided to Acegi based on the ACLs configured in config.xml rather than having to duplicate the information (see Access Control Lists later for more information). And, if fact by using ACLs in config.xml you can get by with just the IS_AUTHENTICATED_ANONYMOUSLY line and leave the config.xml file to determine who can access the client config, the disadvantage to this is that currently if the Weave server determines that the user does not have access to a client config then it will redirect the user to the login page, whereas if Acegi performs the access control then it may try perform the user authentication through some other means, for example using NTLM.

Roles

By using different roles, different users can be granted access to different client configurations.

For example, assuming we have three clients configured in client.xml, public, internal and private, and we want anyone including the public to have access to public, we want anyone except the public to have access to internal and we only want a small group of people to have access to private, then our objectDefinitionSource would be:

/private.html=ROLE_ADMINISTRATOR
/internal.html=ROLE_USER,ROLE_ADMINISTRATOR
/**=IS_AUTHENTICATED_ANONYMOUSLY

Then we would update our userDetailsService to include the new USER_ADMINISTRATORS role for those users who should get access to the private client (note that we have also given administrators access to the internal client).

<bean id="userDetailsService" class="org.acegisecurity.userdetails.memory.InMemoryDaoImpl">
	<property name="userMap">
		<value>
			alice=123,ROLE_USER,ROLE_ADMINISTRATOR
			bob=password,ROLE_USER,disabled
			carol=secret,ROLE_USER
			ted,abc,ROLE_USER
		</value>
	</property>
</bean>

Access Control Lists

As mentioned in the introduction, the second half of the security system requires the configuration of Access Control Lists (ACL) to restrict access to items you wish to protect.

When a process initiated by the user attempts to access a restricted item (which is anything with an ACL attached) the groups that the user belongs are checked against the ACL to determine if the user should be given access to the item.

ACL's can be setup to either deny access to everything and selectively enable access, or to allow access to everything and selectively deny access. The former is more secure and recommended.

An ACL provides a list of groups that can either be denied access or allowed access and are processed linearly until there is a match that positively denies or grants approval. Also, there is a special group, anonymous, that can be used to allow or deny access to users that are logged in anonymously.

Additionally, ACL's can reference other ACL's to provide a hierarchy with recursive checking performed to determine accessibility.

ACL's can be setup either in-line, that is included directly in the item they're guarding access to, or can configured individually and referenced by an item.

IMPORTANT NOTE

THERE IS NO ACCESS CONTROL AT ALL UNLESS AT LEAST ONE ACL IS DEFINED

This means that a default installation will provide no access control to any items until at least one ACL is defined, even if it is default.acl.

Once at least one ACL is defined then access control restrictions will be enabled. This mean that if you are creating a public (or non-sensitive) installation then you do not need to worry about access control lists at all.

It is recommended that if you are going to have any sensitive information then the default ACL should be enabled first and set to deny access to everyone.