Documentation for Crowd 1.6. Documentation for other versions of Crowd is available too.
AppFuse provides a sweet starting point for developing web applications. You choose the frameworks, AppFuse generates the skeleton application.
At its core, the web security of AppFuse 2.0.2+ applications relies on the modular and extensible Spring Security authentication framework. In this tutorial, we look at a basic integration of Crowd with Spring Security, using an application generated by AppFuse.
Spring Security was formerly known as Acegi
Prerequisites
This tutorial assumes you have installed Crowd 1.6 or later and are using Appfuse 2.0.2 or later.
In this tutorial, we will be using the Struts2-basic archetype to create the project, but the other types should be similar. For more information, consult the AppFuse quickstart guide. In particular, it outlines the database requirements for AppFuse.
mvn archetype:create -DarchetypeGroupId=org.appfuse.archetypes \ -DarchetypeArtifactId=appfuse-basic-struts \ -DremoteRepositories=http://static.appfuse.org/releases -DarchetypeVersion=2.0.2 \ -DgroupId=com.mycompany.app -DartifactId=myproject
cd myproject mvn appfuse:full-source
mvn clean install
mvn jetty:run-war -Dmaven.test.skip
http://localhost:8080/
ctrl+c
Add appfuse
as an application via the Crowd Console. See Adding an Application for more information.
Open up the pom.xml
and add the Crowd client libraries as a project dependency:
<dependencies> <dependency> <groupId>com.atlassian.crowd</groupId> <artifactId>crowd-integration-client</artifactId> <version>1.6</version> </dependency> ... </dependencies>
You will also need to create the file myproject/src/main/resources/crowd.properties
:
application.name appfuse application.password password application.login.url http://localhost:8095/crowd/ crowd.server.url http://localhost:8095/crowd/services/ session.isauthenticated session.isauthenticated session.tokenkey session.tokenkey session.validationinterval 0 session.lastvalidation session.lastvalidation
In particular, the application name and password must match the values defined for the application added in Step 2.
Finally, copy the STANDALONE/client/conf/crowd-ehcache.xml
to myproject/src/main/resources/crowd-ehcache.xml
. This file defines the cache properties, such as cache timeouts, used when accessing data from the Crowd server.
Before modifying the security configuration, you will need to add the Spring configuration file to wire up the Crowd client beans. Add the applicationContext-CrowdClient.xml
configuration file to the list of contextConfigLocations
in myproject/src/main/webapp/WEB-INF/web.xml
:
<context-param> <param-name>contextConfigLocation</param-name> <param-value> classpath:/applicationContext-resources.xml classpath:/applicationContext-dao.xml classpath:/applicationContext-service.xml classpath*:/applicationContext.xml classpath:/applicationContext-CrowdClient.xml /WEB-INF/applicationContext*.xml /WEB-INF/xfire-servlet.xml /WEB-INF/security.xml </param-value> </context-param>
AppFuse neatly stores all the Spring Security configuration in myproject/src/main/webapp/WEB-INF/security.xml
. In order to get centralised authentication, we will need to set up Spring Security to use Crowd components for user information. Edit the beans in security.xml
:
<beans:bean id="crowdUserDetailsService" class="com.atlassian.crowd.integration.springsecurity.user.CrowdUserDetailsServiceImpl"> <beans:property name="authenticationManager" ref="crowdAuthenticationManager"/> <beans:property name="groupMembershipManager" ref="crowdGroupMembershipManager"/> <beans:property name="userManager" ref="crowdUserManager"/> <beans:property name="authorityPrefix" value="ROLE_"/> </beans:bean>
<beans:bean id="crowdAuthenticationProvider" class="com.atlassian.crowd.integration.springsecurity.RemoteCrowdAuthenticationProvider"> <custom-authentication-provider /> <beans:constructor-arg ref="crowdAuthenticationManager"/> <beans:constructor-arg ref="httpAuthenticator"/> <beans:constructor-arg ref="crowdUserDetailsService"/> </beans:bean>
<!-- <authentication-provider user-service-ref="userDao"> <password-encoder ref="passwordEncoder"/> </authentication-provider> -->
mvn clean install
mvn jetty:run-war -Dmaven.test.skip
http://localhost:8080/
.USER
and ADMIN
. You will need to add these groups and assign the user as a member of the groups. These Crowd group names map to the Spring Security authorisation roles defined in the AppFuse application.Congratulations. You have centralised authentication
Application-level centralised user management
One quirk you may notice is that you can't view the profile details of users who exist in Crowd, but did not exist in AppFuse prior to the Crowd integration. Although it's possible to authenticate a Crowd user 'dude' and still run AppFuse as 'dude', 'dude' will not be in AppFuse's local database. AppFuse makes use of a database-backed user management system. In order to achieve application-level centralised user management, AppFuse will need to delegate its calls to create, retrieve, update and delete users to Crowd via Crowd's remote API. This will prevent data redundancy and eliminate the hassle of data synchronisation. This is beyond the scope of this short tutorial.
Enabling single sign-on (SSO) requires quite a bit more tweaking of the security.xml
:
<http/>
element:
auto-config
attribute and add an entry-point-ref="crowdAuthenticationProcessingFilterEntryPoint"
attribute to the http element.<form-login>
element.<http lowercase-comparisons="false" entry-point-ref="crowdAuthenticationProcessingFilterEntryPoint"> <!-- note: no auto-config attribute! --> <!--intercept-url pattern="/images/*" filters="none"/> <intercept-url pattern="/styles/*" filters="none"/> <intercept-url pattern="/scripts/*" filters="none"/--> <intercept-url pattern="/admin/*" access="ROLE_ADMIN"/> <intercept-url pattern="/passwordHint.html*" access="ROLE_ANONYMOUS,ROLE_ADMIN,ROLE_USER"/> <intercept-url pattern="/signup.html*" access="ROLE_ANONYMOUS,ROLE_ADMIN,ROLE_USER"/> <intercept-url pattern="/a4j.res/*.html*" access="ROLE_ANONYMOUS,ROLE_ADMIN,ROLE_USER"/> <!-- APF-737, OK to remove line below if you're not using JSF --> <intercept-url pattern="/**/*.html*" access="ROLE_ADMIN,ROLE_USER"/> <!-- <form-login login-page="/login.jsp" authentication-failure-url="/login.jsp?error=true" login-processing-url="/j_security_check"/> --> <remember-me user-service-ref="userDao" key="e37f4b31-0c45-11dd-bd0b-0800200c9a66"/> </http>
<authentication-manager alias="authenticationManager"/> <beans:bean id="crowdAuthenticationProcessingFilterEntryPoint" class="org.springframework.security.ui.webapp.AuthenticationProcessingFilterEntryPoint"> <beans:property name="loginFormUrl" value="/login.jsp"/> </beans:bean> <beans:bean id="crowdAuthenticationProcessingFilter" class="com.atlassian.crowd.integration.springsecurity.CrowdSSOAuthenticationProcessingFilter"> <custom-filter position="AUTHENTICATION_PROCESSING_FILTER"/> <beans:property name="httpAuthenticator" ref="httpAuthenticator"/> <beans:property name="authenticationManager" ref="authenticationManager"/> <beans:property name="authenticationFailureUrl" value="/login.jsp?error=true"/> <beans:property name="defaultTargetUrl" value="/"/> <beans:property name="filterProcessesUrl" value="/j_security_check"/> </beans:bean>
<beans:bean id="crowdLogoutHandler" class="com.atlassian.crowd.integration.springsecurity.CrowdLogoutHandler"> <beans:property name="httpAuthenticator" ref="httpAuthenticator"/> </beans:bean> <beans:bean id="logoutFilter" class="org.springframework.security.ui.logout.LogoutFilter"> <custom-filter position="LOGOUT_FILTER"/> <beans:constructor-arg value="/index.jsp"/> <beans:constructor-arg> <beans:list> <beans:ref bean="crowdLogoutHandler"/> <beans:bean class="org.springframework.security.ui.logout.SecurityContextLogoutHandler"/> </beans:list> </beans:constructor-arg> <beans:property name="filterProcessesUrl" value="/logout.jsp"/> </beans:bean>
mvn jetty:run-war -Dmaven.test.skip=true
SSO will only work for users that are able to authenticate with both appplications and are authorised to use both applications. Try out the following:
Congratulations, you have SSO