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.