Authentication via URL parameter

While the security implications should be obvious, it's possible to setup the Acegi security configuration so that the user is authenticated via a parameter provided in the startup URL.

This requires the installation of a specific bundle, that adds the required functionality, along with changes to the security.xml file to make use of this functionality.

These changes do not necessarily replace any existing authentication methods, that is, you can use this to authenticate one set of users and continue to use other methods to authenticate other users.

Authenticating a user via a parameter provided in the startup URL could be handy if you wish to provide multiple configurations that are accessible based on the users roles and want to have read/write access to one group of users that must login with a username and password, but you want to provide easy read-only access to another group of users.

Installation

The UID Security bundle can be downloaded here.

Once downloaded it should be copied to the weave\platform\plugins directory, and a server restart will make it available.

Note that at this stage there will be no change or reduction in the security compared to before this bundle was installed, the security.xml file must be updated to indicate that the functionality provided by this bundle is to be used.

Configuration

The first change required to security.xml is to change the authenticationProcessingFilter.

Updating the authentication processing filter

Generally security.xml will be configured with org.acegisecurity.ui.webapp.AuthenticationProcessingFilter as the authenticationProcessingFilter, this needs to be replaced with com.cohga.server.security.uid.AuthenticationProcessingFilter.

So an existing authenticationProcessingFilter

<bean id="authenticationProcessingFilter" class="org.acegisecurity.ui.webapp.AuthenticationProcessingFilter">
	<property name="authenticationManager" ref="authenticationManager"/>
	<property name="authenticationFailureUrl" value="/login.html?failure=true"/>
	<property name="defaultTargetUrl" value="/index.html"/>
	<property name="filterProcessesUrl" value="/security/j_acegi_security_check.do"/>
	<property name="rememberMeServices" ref="rememberMeServices"/>
</bean>

would become

<bean id="authenticationProcessingFilter" class="com.cohga.server.security.uid.AuthenticationProcessingFilter">
	<property name="authenticationManager" ref="authenticationManager"/>
	<property name="authenticationFailureUrl" value="/login.html?failure=true"/>
	<property name="defaultTargetUrl" value="/index.html"/>
	<property name="filterProcessesUrl" value="/security/j_acegi_security_check.do"/>
	<property name="rememberMeServices" ref="rememberMeServices"/>
</bean>

The com.cohga.server.security.uid.AuthenticationProcessingFilter is an extension of the org.acegisecurity.ui.webapp.AuthenticationProcessingFilter that will check for a uid parameter in the URL and try and authenticate it.

The authentication process

The authentication process is the same as it was before the switch to the com.cohga.server.security.uid.AuthenticationProcessingFilter, that is the authenticationManager configured in the authenticationProcessingFilter will be called upon to validate that user information, in this case the uid parameters value (rather than a username/password provided by the normal login form).

The authenticationManager will try and lookup a userid and validate that the password for the userid is correct, via the users.properties file, LDAP, Active Directory, a JDBC database connection, etc., but in this situation we don't have a password to check. Actually, more correctly we do have a password, but it'll be empty, so unless the password corresponding to the userid is also empty no match will be found.

This means that you could just add users to be validated via the uid parameter to your existing authenticationManager source and just make sure that the password is blank for those users, and no further change would be required to security.xml to enable uid authentication.

You should make sure that passwords for users you don't want authenticated via uid are not empty if you're using com.cohga.server.security.uid.AuthenticationProcessingFilter, otherwise anyone will be able to login as that user.

Separating users

If you only have a handful of userids you want to be able to connect via the uid parameter and you don't want to, or can't, add users to the existing authenticationManager source then you can supplement the authenticationManager with a separate source of user details to validate against.

To do this you need to add a new authenticationProvider to the authenticationManager that points to a userDetailsService that provides the additional user list.

For example, assuming that we're currently using an LDAP server for user authentication, then we'd have an authenticationManager something like

<bean id="authenticationManager" class="org.acegisecurity.providers.ProviderManager">
	<property name="providers">
		<list>
			<ref local="ldapAuthenticationProvider"/>
			<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>

The list of authenticationProviders may be different, for example if you're just using user.properties to list users then it may contain a reference to a DaoAuthenticationProvider, or if you're using a database to store username and passwords it may contain a JdbcDaoSupport provider. The point here is that we're going to add another authenticationProvider that looks at a different list of users.

A simple authentication provider

Our first step is to create the new authenticationProvider, before we add it to the authenticationManager.

In our example where we're going to use a DaoAuthenticationProvider and have that look at a list of users embedded directly in security.xml. We could just as easily use a DaoAuthenticationProvider looking at a file called uid.properties, a JdbcDaoSupport looking at database tables, LdapAuthenticationProvider looking at sub-branch in our LDAP server.

To create our new authenticationProvider we need the DaoAuthenticationProvider along with a userDetailsService which we add with the following additions to security.xml

<bean id="uidAuthenticationProvider" class="org.acegisecurity.providers.dao.DaoAuthenticationProvider">
	<property name="userDetailsService" ref="uidDetailsService"/>
	<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="uidDetailsService" class="org.acegisecurity.userdetails.memory.InMemoryDaoImpl">
	<property name="userMap">
		<value>
			north=,ROLE_NORTH,ROLE_READONLY
			south=,ROLE_SOUTH,ROLE_READONLY
		</value>
	</property>
</bean>

Note the comma immediately after the equals sign for each user listed in the uidDetailsService.
This is important since the password is listed between the equals sign and the comma, which for our purposes when using a com.cohga.server.security.uid.AuthenticationProcessingFilter, needs to be empty.
Following this initial comma is a comma separated list of the roles that will be assigned to each user.

In our example above each user has 2 roles, this may or may not be the same way that your roles need to be configured, and is just one possible way of assigning roles to these users

This created the DaoAuthenticationProvider called uidAuthenticationProvider that references the list of users named uidDetailsService.

The final step would be to add this new authenticationProvider to the authenticationManager as by changing it to

<bean id="authenticationManager" class="org.acegisecurity.providers.ProviderManager">
	<property name="providers">
		<list>
			<ref local="uidAuthenticationProvider"/> <!-- NEW UID AUTHENTICATION PROVIDER -->
			<ref local="ldapAuthenticationProvider"/>
			<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>

Usage

Once we've switched over to the new authenticationProcessingFilter we should be able to start a specific Weave client configuration with an additional uid parameter, as follows

http://server:8080/weave/north_region.html?uid=north

And assuming that the appropriate access controls lists have been created referencing the correct roles, for example

<acl:acl id="editors">
	<entry type="deny">ROLE_READONLY</entry>
<acl:acl>

<acl:acl id="north">
	<entry type="allow">ROLE_NORTH</entry>
	<entry type="deny">*</entry>
<acl:acl>

<acl:acl id="south">
	<entry type="allow">ROLE_SOUTH</entry>
	<entry type="deny">*</entry>
<acl:acl>

You can then setup client configuration items similar to

<client:config id="north_region">
	<acl id="north"/>

	<!-- other configuration here -->

	<!-- add a tool only for users fully logged in -->
	<item action="example.editing.tool" acl="editors"/>

	<!-- rest of configuration here -->

</client:config>

<client:config id="south_region">
	<acl id="south"/>

	<!-- other configuration here -->

	<!-- add a tool only for users fully logged in -->
	<item action="example.editing.tool" acl="editors"/>

	<!-- rest of configuration here -->

</client:config>

Then assuming that your previous authenticationProvider assigned ROLE_NORTH and/or ROLE_SOUTH to other users, and does not assign ROLE_READONLY, then user logging in via the uid parameter won't have access to the example.editing.tool whereas those logging in via the previous methods will.

And, of course we can also attach these access control lists to other items, such as report, searches, etc.