I faced some problems (described at the end) but it was possible. The application-security.xml of our web application looks as follows.
1: <beans xmlns="http://www.springframework.org/schema/beans"
2: xmlns:s="http://www.springframework.org/schema/security"
3: xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4: xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
5: http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.0.xsd">
6: <s:http use-expressions="true">
7: <s:intercept-url pattern="/**" access="permitAll" />
8: <s:http-basic />
9: <s:logout />
10: </s:http>
11: <s:authentication-manager>
12: <s:authentication-provider ref="jaasAuthenticationProvider" user-service-ref="userDetailsService"/>
13: </s:authentication-manager>
14: <bean id="jaasAuthenticationProvider"
15: class="org.springframework.security.authentication.jaas.JaasAuthenticationProvider">
16: <property name="loginContextName">
17: <value>cspace</value> <!-- value should be same as in application-policy in JBoss login-config.xml -->
18: </property>
19: <property name="loginConfig">
20: <value>/WEB-INF/login.conf</value> <!-- filler, not used at runtime -->
21: </property>
22: <property name="callbackHandlers">
23: <list>
24: <bean class="org.springframework.security.authentication.jaas.JaasNameCallbackHandler"/>
25: <bean class="org.springframework.security.authentication.jaas.JaasPasswordCallbackHandler"/>
26: </list>
27: </property>
28: <property name="authorityGranters">
29: <list>
30: <bean class="org.collectionspace.authentication.spring.CSpaceAuthorityGranter"/>
31: </list>
32: </property>
33: </bean>
34: <bean id="userDetailsService" class="org.collectionspace.authentication.spring.CSpaceUserDetailsService">
35: </bean>
36: </beans>
Listing 1As you see, authentication-manager refers to jaasAuthenticationProvider (#12). This JAAS authentication provider is using the same value cspace for loginContextName (#16-18) as the value of the attribute named name (#1 Listing 2) in application-policy of JBoss's login-config.xml as shown below. This is important. This is how Spring security framework finds out the required JAAS login module from the JBoss environment and ties it to its own JAAS authentication provider.
1: <application-policy name="cspace">
2: <authentication>
3: <login-module code="org.collectionspace.authentication.jaas.CSpaceJBossDBLoginModule"
4: flag="required">
5: ...
6: </login-module>
7: </authentication>
8: </application-policy>
Listing 2From application-security.xml in Listing 1, you may also notice that I have configured the following two entities for CollectionSpace:
- CSpaceAuthorityGranter (#30). This class returns a set of strings. Each entry in the set represents a string for a role which is represented as Java Principal by the JAAS provider. Spring uses this string to create a corresponding AuthorityGranter.
- CSpaceUserDetailsService (#34). Even if you do not have additional attributes for a user (e.g. user profile), this entity needs to be configured. It is useful to obtain application specific information attached to the user. For example, in CollectionSpace, this service could retrieve information such as first name, last name, contact details, etc. from services such as the Person sevice.
The CollectionSpace authentication service is packaged as a jar. This jar includes CS database realm classes, JAAS login module and the above mentioned Spring security specific classes. This jar is copied to JBoss's domain lib, e.g. (server/cspace/lib) and is available from system classpath at runtime.
The application-security.xml is packaged with the war file. This war file is built using maven. Maven could package all the Spring specific dependencies when the war is built.
At runtime, Spring framework would complain with the following:
"Cannot convert value of type org.collectionspace.authentication.spring.CSpaceAuthorityGranter to required type org.springframework.security.authentication.jaas.AuthorityGranter for property authorityGranters[0] : no matching editors or conversion strategy found"
To overcome this, I used the following dependency while building the authentication service jar.
1: <spring.security.version>3.0.1.RELEASE</spring.security.version>
2: <dependency>
3: <groupId>org.springframework.security</groupId>
4: <artifactId>spring-security-core</artifactId>
5: <version>${spring.security.version}</version>
6: <scope>provided</scope>
7: </dependency>
Listing 3And the war was build using the following dependencies.
1: <properties>
2: <spring.version>3.0.0.RELEASE</spring.version>
3: <spring.security.version>3.0.1.RELEASE</spring.security.version>
4: </properties>
5: <!-- dependencies on spring security & framework are runtime deps only -->
6: <!-- the following list is kept to make sure domain has these packages -->
7: <!-- in the cspace/lib directory -->
8: <dependency>
9: <groupId>org.springframework.security</groupId>
10: <artifactId>spring-security-core</artifactId>
11: <version>${spring.security.version}</version>
12: <scope>provided</scope>
13: </dependency>
14: <dependency>
15: <groupId>org.springframework.security</groupId>
16: <artifactId>spring-security-config</artifactId>
17: <version>${spring.security.version}</version>
18: <scope>provided</scope>
19: </dependency>
20: <dependency>
21: <groupId>org.springframework.security</groupId>
22: <artifactId>spring-security-web</artifactId>
23: <version>${spring.security.version}</version>
24: <scope>provided</scope>
25: </dependency>
26: <dependency>
27: <groupId>org.springframework.security</groupId>
28: <artifactId>spring-security-acl</artifactId>
29: <version>${spring.security.version}</version>
30: <scope>provided</scope>
31: </dependency>
32: <dependency>
33: <groupId>org.springframework</groupId>
34: <artifactId>spring-context</artifactId>
35: <version>${spring.version}</version>
36: <scope>provided</scope>
37: </dependency>
38: <dependency>
39: <groupId>org.springframework</groupId>
40: <artifactId>spring-web</artifactId>
41: <version>${spring.version}</version>
42: <scope>provided</scope>
43: </dependency>
44: <dependency>
45: <groupId>org.springframework</groupId>
46: <artifactId>spring-webmvc</artifactId>
47: <version>${spring.version}</version>
48: <scope>provided</scope>
49: </dependency>
50: <dependency>
51: <groupId>org.springframework</groupId>
52: <artifactId>spring-aop</artifactId>
53: <version>${spring.version}</version>
54: <scope>provided</scope>
55: </dependency>
Listing 4Note that I have used dependency scope
My assumption here is that somehow the classes (esp. AuthorityGranter) pulled by maven while building the authentication provider jar and the war, both using default dependency scope, were not the same, even if I was using the same release versions for Spring security in both the poms. At one point I was using CI SNAPSHOTs for Spring security. Perhaps that might be the reason as the repository might be changing at the time. Dunno for sure.
If you know a better way to solve this problem, feel free to comment.
Hi,
ReplyDeleteCan you send me source code so i can try and implement the code to check error?
Hi,
ReplyDeleteCan you send me source code so i can try and implement the code to check error?