Tuesday, November 24, 2009

Single Sign On with CAS Part 2 Integrating with Roller

Overview

 In part 2, we will go over how to integrate CAS 4 Single Sign On with Roller ( a open source blog engine , see roller.apache.com ).
 In this usage scenario we authenticate the user using CAS4 which in this case stores Username/password information in a separate User db from Roller's db.
So we will not be authenticating using Roller's db, however we will use Roller's db to determine what the users role / access rights are within the Roller application. (i.e Are they an editor, administrator, or do they not have a role yet).
Since Roller has implemented SSO for LDAP environment, we can utilize this and Roller will automatically create a role for a user if they do not have one yet. The default role is editor for their own blog.
The workflow for Roller integrating CAS 4 is as follows, user goes to a secured page on the roller application site, the user will get redirected to the
CAS 4 application site and be asked to login. After successful login, the user will be redirect back to where they started on the roller application site.
If they checked the remember me check box , then in the future, they will not have to login again until their remember me cookie expires.


Setting Up Your Development Environment
Roller uses Ant for compiling and deployment.
Depending on which IDE you use and what you development style is you may wish
to create a new empty roller_custom java project with Maven enabled if you want to use Maven dependency management instead using Ant and library references. I typically use Eclipse and Maven, so I created an empty roller_custom java project
and a new pom.xml, then enabled maven. This way I will be able to use Eclispe with Maven. I then built Roller using the ant build file (/roller/apps/weblogger/build.xml) to make sure Roller compiles correctly under ant first.  To install Roller's jars into your local Maven Repository , you will need to use the experimental ant build file, /roller/build-poms.xml). You will need to download maven-ant-tasks-2.0.10.jar, and install it to roller/tools/buildtime/maven/maven-ant-tasks-2.0.10.jar and make sure to update it reference location in /roller/build-poms.xml. Next, I referenced the Roller's jars and CAS4 client jar in my roller_custom pom.xml file, like so:
<dependency>
<groupid>org.apache.roller</groupid>
<artifactid>roller-core</artifactid>
<version>4.0</version>
<type>jar</type>
</dependency>
<dependency>
<groupid>org.apache.roller</groupid>
<artifactid>roller-business</artifactid>
<version>4.0</version>
<type>jar</type>
</dependency>
<dependency>
<groupid>org.apache.roller</groupid>
<artifactid>planet-business</artifactid>
<version>4.0</version>
<type>jar</type>
</dependency>
<dependency>
<groupid>org.apache.roller</groupid>
<artifactid>planet-web</artifactid>
<version>4.0</version>
<type>jar</type>
</dependency>
<dependency>
<groupid>org.apache.roller</groupid>
<artifactid>roller-web</artifactid>
<version>4.0</version>
<type>jar</type>
</dependency>
<dependency>
<groupid>org.jasig.cas</groupid>
<artifactid>cas-client-core</artifactid>
<version>3.1.5</version>
</dependency>
Unfortunately this next part is time consuming. You will need to reference all the .jars that Roller references in your Pom.xml under /roller/tools, Roller has a lot of references so it is time consuming.
But, with all this hard work, you now have Maven goodness, and easy debugging compatibilty using Eclipse with Jetty if you wish.

SSO Implementation
 Out of the box Roller supports SSO with LDAP. To use Spring Security with RememberMeServices we need to update
the class: RollerUserDetailsService.java, to include the specific Role Name Prefix that Spring Security looks for.
Specifically, Spring Security looks for the prefix "ROLE_" in every role name.
Additionally, Roller has a property setting for Autoprovision a user's account, we therefore will use this to automatically create a User if the Account exists in our CAS User db , but not in our Roller db.
Therefore we updated RememberMeServices like this:
public class RollerUserDetailsService implements UserDetailsService {

//Spring Security uses special required rolePrefix, typically ROLE_
private String rolePrefix = "";

public RollerUserDetailsService()
{

}

/**
* Allows a default role prefix to be specified. If this is set to a non-empty value, then it is
* automatically prepended to any roles read in from the db. This may for example be used to add the
* ROLE_ prefix expected to exist in role names (by default) by some other Spring Security
* classes, in the case that the prefix is not already present in the db.
*
* @param rolePrefix the new prefix
*/
public void setRolePrefix(String rolePrefix) {
this.rolePrefix = rolePrefix;
}

protected String getRolePrefix() {
return rolePrefix;
}

public UserDetails loadUserByUsername(String userName)
throws UsernameNotFoundException, DataAccessException {
try {
Weblogger roller = WebloggerFactory.getWeblogger();
UserManager umgr = roller.getUserManager();
User userData = null;
if (userName.startsWith("http://")) {
if (userName.endsWith("/")) {
userName = userName.substring(0, userName.length() -1 );
}
try {
userData = umgr.getUserByAttribute(
UserAttribute.Attributes.OPENID_URL.toString(),
userName);
} catch (WebloggerException ex) {
throw new DataRetrievalFailureException("ERROR in user lookup", ex);
}
String name;
String password;
GrantedAuthority[] authorities;

// We are not throwing UsernameNotFound exception in case of
// openid authentication in order to recieve user SREG attributes
// from the authentication filter and save them
if (userData == null) {
authorities = new GrantedAuthority[1];
GrantedAuthority g = new GrantedAuthorityImpl("openidLogin");
authorities[0] = g;
name = "openid";
password = "openid";
} else {
authorities = getAuthorities(userData, umgr);
name = userData.getUserName();
password = userData.getPassword();
}
UserDetails usr = new org.springframework.security.userdetails.User(name, password, true, authorities);
return usr;

} else {
try {
userData = umgr.getUserByUserName(userName);
} catch (WebloggerException ex) {
throw new DataRetrievalFailureException("ERROR in user lookup", ex);
}
if (userData == null) {

//determine if autoProvisioning is enabled if so create User
if (WebloggerConfig.getBooleanProperty("users.sso.autoProvision.enabled"))
{
AutoProvision provisioner = RollerContext.getAutoProvision();
if(provisioner != null) {
boolean userProvisioned = provisioner.execute(userName);
if(userProvisioned) {
// try lookup again real quick
try{
userData = umgr.getUserByUserName(userName);
}
catch (WebloggerException e) {
throw new UsernameNotFoundException("ERROR no user: " + userName);
}
}
}
}
else
{
throw new UsernameNotFoundException("ERROR no user: " + userName);
}
}
}
GrantedAuthority[] authorities = getAuthorities(userData, umgr);
return new org.springframework.security.userdetails.User(userData.getUserName(), userData.getPassword(), true, authorities);

} catch (WebloggerException ex) {
throw new DataAccessResourceFailureException("ERROR: fetching roles", ex);
}


}

private GrantedAuthority[] getAuthorities(User userData, UserManager umgr) throws WebloggerException {
List roles = umgr.getRoles(userData);
GrantedAuthority[] authorities = new GrantedAuthorityImpl[roles.size()];

if(!rolePrefix.isEmpty())
{
authorities = new GrantedAuthorityImpl[roles.size()*2];
}

int i = 0;
for (String role : roles) {
//add Roller Security Role for use with non-Spring Security Implementations
authorities[i++] = new GrantedAuthorityImpl(role);
//add Spring Security Role
authorities[i++] = new GrantedAuthorityImpl(rolePrefix + role);
}
return authorities;
}

}
In addition, since we need to get the Roles for a user from Roller's db so we may need to implement a Custom RememberMeServices class.
Developers will probably need to implement their own custom class, if they created their RememberMe cookie not using the standard Spring Security Remember Me configuration.
Here is a brief code outline (snippet), if you for example you call your class:
RollerRememberMeServices. You will need to extend AbstractRememberMeServices class which is a part of Spring Security ( using Spring Security 2.0) and implement all the required methods.
public class RollerRememberMeServices extends AbstractRememberMeServices{


}
One of the key methods is: processAutoLoginCoookie,

 This method returns UserDetails object, within this method you will need to extract the username from the RememberMe cookie (this will vary depending on what you stored in your cookie value, some people will store username, some will store email, etc).
With the username you can the create a UserDetails object by doing something like this:
UserDetails userDetails = getUserDetailsService().loadUserByUsername(username);
Configuring those Config Files
Step 1 (optional , only if you wish to use Jetty as your debugging web server),
update your pom.xml file.
<plugin>
<groupId>org.mortbay.jetty</groupId>
<artifactId>jetty-maven-plugin</artifactId>
<version>7.0.0.1beta2</version>
<configuration>
<webAppConfig>
<contextPath>/roller_custom</contextPath>
<tempDirectory>${project.build.directory}/work</tempDirectory>
</webAppConfig>
<connectors>
<connector implementation="org.eclipse.jetty.server.nio.SelectChannelConnector">
<port>8090</port>
</connector>
</connectors>
</configuration>
<!--add dependencies as needed like jdbc drivers and logging-->
<!--sample-->
<!--<dependencies>
<dependency>
<groupId>postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>8.4-701.jdbc3</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.14</version>
</dependency>
</dependencies>-->
</plugin>


Step 2: Updated web.xml (added Spring Security and CAS4):
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">

<display-name>Roller Weblogger</display-name>

<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/security.xml,
/WEB-INF/jndi.xml
</param-value>
</context-param>

<filter>
<filter-name>struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.FilterDispatcher</filter-class>
</filter>

<!-- This is really strange, but for some reason it's needed to prevent
some problems with the file uploads not working intermittently -->
<filter>
<filter-name>struts2-cleanup</filter-name>
<filter-class>org.apache.struts2.dispatcher.ActionContextCleanUp</filter-class>
</filter>

<!--new-->
<filter>
<filter-name>CAS Single Sign Out Filter</filter-name>
<filter-class>org.jasig.cas.client.session.SingleSignOutFilter</filter-class>
</filter>

<!--original filter-->
<!--<filter>
<filter-name>securityFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
<init-param>
<param-name>targetBeanName</param-name>
<param-value>springSecurityFilterChain</param-value>
</init-param>
</filter>-->

<!--new-->
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>

<filter>
<filter-name>DebugFilter</filter-name>
<filter-class>org.apache.roller.weblogger.ui.core.filters.DebugFilter</filter-class>
</filter>

<filter>
<filter-name>PersistenceSessionFilter</filter-name>
<filter-class>org.apache.roller.weblogger.ui.core.filters.PersistenceSessionFilter</filter-class>
</filter>

<filter>
<filter-name>BootstrapFilter</filter-name>
<filter-class>org.apache.roller.weblogger.ui.core.filters.BootstrapFilter</filter-class>
</filter>

<!--
Most app servers support compression, if yours doesn't then use this one,
but don't forget to uncomment the mapping below too.
<filter>
<filter-name>CompressionFilter</filter-name>
<filter-class>org.apache.roller.weblogger.ui.core.filters.CompressionFilter</filter-class>
</filter>
-->

<filter>
<filter-name>RequestMappingFilter</filter-name>
<filter-class>org.apache.roller.weblogger.ui.rendering.filters.RequestMappingFilter</filter-class>
</filter>

<filter>
<filter-name>InitFilter</filter-name>
<filter-class>org.apache.roller.weblogger.ui.core.filters.InitFilter</filter-class>
</filter>

<filter>
<filter-name>IPBanFilter</filter-name>
<filter-class>org.apache.roller.weblogger.ui.core.filters.IPBanFilter</filter-class>
</filter>

<filter>
<filter-name>SchemeEnforcementFilter</filter-name>
<filter-class>org.apache.roller.weblogger.ui.core.filters.SchemeEnforcementFilter</filter-class>
</filter>

<filter>
<filter-name>CharEncodingFilter</filter-name>
<filter-class>org.apache.roller.weblogger.ui.core.filters.CharEncodingFilter</filter-class>
</filter>


<!-- ******************************************
Filter mappings - order IS important here.
****************************************** -->

<!--
NOTE: Wherever "dispatcher" elements are specified in the filter mappings, they are
required for Servlet API 2.4 containers, such as Tomcat 5+ and Resin 3+, but should be
commented out for Servlet API 2.3 containers, like Tomcat 4.x and Resin 2.x.
-->

<!-- This filter ensures that the request encoding is set to UTF-8 before any
other processing forces request parsing using a default encoding.
Note: Any filters preceding this one MUST not cause request parsing. -->
<filter-mapping>
<filter-name>CharEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>REQUEST</dispatcher>
<dispatcher>FORWARD</dispatcher>
</filter-mapping>

<!-- Ip Banning is mapped for comment and trackbacks only.
Note: this filter does nothing if an ip ban list is not configured. -->
<filter-mapping>
<filter-name>IPBanFilter</filter-name>
<url-pattern>/roller-ui/rendering/comment/*</url-pattern>
<dispatcher>FORWARD</dispatcher>
</filter-mapping>
<filter-mapping>
<filter-name>IPBanFilter</filter-name>
<url-pattern>/roller-ui/rendering/trackback/*</url-pattern>
<dispatcher>FORWARD</dispatcher>
</filter-mapping>

<!-- Scheme enforcement. Only here until we get Acegi scheme enforcement working -->
<filter-mapping>
<filter-name>SchemeEnforcementFilter</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>REQUEST</dispatcher>
</filter-mapping>

<filter-mapping>
<filter-name>CAS Single Sign Out Filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

<!-- Original Security filters - controls secure access to different parts of Roller -->
<!--<filter-mapping>
<filter-name>securityFilter</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>REQUEST</dispatcher>
<dispatcher>FORWARD</dispatcher>
</filter-mapping>-->

<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

<filter-mapping>
<filter-name>BootstrapFilter</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>REQUEST</dispatcher>
</filter-mapping>

<!-- Map everything to the PersistenceSessionFilter.
NOTE: Any filters preceding this one MUST NOT use persistence sessions.-->
<filter-mapping>
<filter-name>PersistenceSessionFilter</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>REQUEST</dispatcher>
</filter-mapping>

<!-- Init filter. performs some initialization on first request -->
<filter-mapping>
<filter-name>InitFilter</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>REQUEST</dispatcher>
</filter-mapping>

<!-- Request mapping. this is what allows the urls to work -->
<filter-mapping>
<filter-name>RequestMappingFilter</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>REQUEST</dispatcher>
</filter-mapping>

<!--
Most app servers support compression, if yours doesn't then use this one,
but don't forget to uncomment the filter definition above too.
<filter-mapping>
<filter-name>CompressionFilter</filter-name>
<url-pattern>/roller-ui/rendering/page/*</url-pattern>
<dispatcher>FORWARD</dispatcher>
</filter-mapping>
<filter-mapping>
<filter-name>CompressionFilter</filter-name>
<url-pattern>/roller-ui/rendering/feed/*</url-pattern>
<dispatcher>FORWARD</dispatcher>
</filter-mapping>
-->

<!-- Struts2 -->
<filter-mapping>
<filter-name>struts2-cleanup</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>REQUEST</dispatcher>
<dispatcher>FORWARD</dispatcher>
</filter-mapping>

<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>REQUEST</dispatcher>
<dispatcher>FORWARD</dispatcher>
</filter-mapping>


<!-- Context Listeners -->
<!--new-->
<listener>
<listener-class>org.jasig.cas.client.session.SingleSignOutHttpSessionListener</listener-class>
</listener>

<listener>
<listener-class>org.apache.roller.weblogger.ui.core.RollerSession</listener-class>
</listener>

<listener>
<listener-class>org.apache.roller.weblogger.ui.core.RollerContext</listener-class>
</listener>

<listener>
<listener-class>org.apache.tiles.web.startup.TilesListener</listener-class>
</listener>


<!-- Servlet Definitions -->
<servlet>
<servlet-name>PageServlet</servlet-name>
<servlet-class>org.apache.roller.weblogger.ui.rendering.servlets.PageServlet</servlet-class>
<load-on-startup>5</load-on-startup>
</servlet>

<servlet>
<servlet-name>FeedServlet</servlet-name>
<servlet-class>org.apache.roller.weblogger.ui.rendering.servlets.FeedServlet</servlet-class>
<load-on-startup>5</load-on-startup>
</servlet>

<servlet>
<servlet-name>ResourceServlet</servlet-name>
<servlet-class>org.apache.roller.weblogger.ui.rendering.servlets.ResourceServlet</servlet-class>
<load-on-startup>5</load-on-startup>
</servlet>

<servlet>
<servlet-name>MediaResourceServlet</servlet-name>
<servlet-class>org.apache.roller.weblogger.ui.rendering.servlets.MediaResourceServlet</servlet-class>
<load-on-startup>5</load-on-startup>
</servlet>

<servlet>
<servlet-name>SearchServlet</servlet-name>
<servlet-class>org.apache.roller.weblogger.ui.rendering.servlets.SearchServlet</servlet-class>
<load-on-startup>5</load-on-startup>
</servlet>

<servlet>
<servlet-name>OpenSearchServlet</servlet-name>
<servlet-class>org.apache.roller.weblogger.webservices.opensearch.OpenSearchServlet</servlet-class>
<load-on-startup>10</load-on-startup>
</servlet>

<servlet>
<servlet-name>CommentServlet</servlet-name>
<servlet-class>org.apache.roller.weblogger.ui.rendering.servlets.CommentServlet</servlet-class>
<load-on-startup>7</load-on-startup>
</servlet>

<servlet>
<servlet-name>TrackbackServlet</servlet-name>
<servlet-class>org.apache.roller.weblogger.ui.rendering.servlets.TrackbackServlet</servlet-class>
<load-on-startup>7</load-on-startup>
</servlet>

<servlet>
<servlet-name>RSDServlet</servlet-name>
<servlet-class>org.apache.roller.weblogger.ui.rendering.servlets.RSDServlet</servlet-class>
<load-on-startup>7</load-on-startup>
</servlet>

<servlet>
<servlet-name>PlanetFeedServlet</servlet-name>
<servlet-class>org.apache.roller.weblogger.ui.rendering.servlets.PlanetFeedServlet</servlet-class>
<load-on-startup>7</load-on-startup>
</servlet>

<servlet>
<servlet-name>CommentAuthenticatorServlet</servlet-name>
<servlet-class>org.apache.roller.weblogger.ui.rendering.servlets.CommentAuthenticatorServlet</servlet-class>
<load-on-startup>7</load-on-startup>
</servlet>

<servlet>
<servlet-name>PreviewServlet</servlet-name>
<servlet-class>org.apache.roller.weblogger.ui.rendering.servlets.PreviewServlet</servlet-class>
<load-on-startup>9</load-on-startup>
</servlet>

<servlet>
<servlet-name>PreviewResourceServlet</servlet-name>
<servlet-class>org.apache.roller.weblogger.ui.rendering.servlets.PreviewResourceServlet</servlet-class>
<load-on-startup>9</load-on-startup>
</servlet>

<servlet>
<servlet-name>PreviewThemeImageServlet</servlet-name>
<servlet-class>org.apache.roller.weblogger.ui.rendering.servlets.PreviewThemeImageServlet</servlet-class>
<load-on-startup>9</load-on-startup>
</servlet>

<servlet>
<servlet-name>RedirectServlet</servlet-name>
<servlet-class>org.apache.roller.weblogger.ui.rendering.velocity.deprecated.RedirectServlet</servlet-class>
<load-on-startup>9</load-on-startup>
</servlet>

<servlet>
<servlet-name>StrutsRedirectServlet</servlet-name>
<servlet-class>org.apache.roller.weblogger.ui.struts2.util.StrutsRedirectServlet</servlet-class>
<load-on-startup>9</load-on-startup>
</servlet>

<servlet>
<servlet-name>AtomServlet</servlet-name>
<servlet-class>com.sun.syndication.propono.atom.server.AtomServlet</servlet-class>
</servlet>

<servlet>
<servlet-name>CommentDataServlet</servlet-name>
<servlet-class>org.apache.roller.weblogger.ui.struts2.ajax.CommentDataServlet</servlet-class>
</servlet>

<servlet>
<servlet-name>UserDataServlet</servlet-name>
<servlet-class>org.apache.roller.weblogger.ui.struts2.ajax.UserDataServlet</servlet-class>
</servlet>

<servlet>
<servlet-name>AdminServlet</servlet-name>
<servlet-class>org.apache.roller.weblogger.webservices.adminprotocol.AdminServlet</servlet-class>
</servlet>

<servlet>
<servlet-name>TagDataServlet</servlet-name>
<servlet-class>org.apache.roller.weblogger.webservices.tagdata.TagDataServlet</servlet-class>
</servlet>


<servlet>
<servlet-name>XmlRpcServlet</servlet-name>
<servlet-class>org.apache.xmlrpc.webserver.XmlRpcServlet</servlet-class>
<init-param>
<description>
Sets, whether the servlet supports vendor extensions for XML-RPC.
</description>
<param-name>enabledForExtensions</param-name>
<param-value>true</param-value>
</init-param>
</servlet>


<!-- BEGIN OAUTH -->

<servlet>
<servlet-name>RequestTokenServlet</servlet-name>
<servlet-class>org.apache.roller.weblogger.webservices.oauth.RequestTokenServlet</servlet-class>
</servlet>

<servlet>
<servlet-name>AuthorizationServlet</servlet-name>
<servlet-class>org.apache.roller.weblogger.webservices.oauth.AuthorizationServlet</servlet-class>
</servlet>

<servlet>
<servlet-name>AccessTokenServlet</servlet-name>
<servlet-class>org.apache.roller.weblogger.webservices.oauth.AccessTokenServlet</servlet-class>
</servlet>

<servlet-mapping>
<servlet-name>RequestTokenServlet</servlet-name>
<url-pattern>/roller-services/oauth/requestToken</url-pattern>
</servlet-mapping>

<servlet-mapping>
<servlet-name>AuthorizationServlet</servlet-name>
<url-pattern>/roller-services/oauth/authorize</url-pattern>
</servlet-mapping>

<servlet-mapping>
<servlet-name>AccessTokenServlet</servlet-name>
<url-pattern>/roller-services/oauth/accessToken</url-pattern>
</servlet-mapping>

<!-- END OAUTH -->

<!-- Rendering Servlets -->
<servlet-mapping>
<servlet-name>PageServlet</servlet-name>
<url-pattern>/roller-ui/rendering/page/*</url-pattern>
</servlet-mapping>

<servlet-mapping>
<servlet-name>FeedServlet</servlet-name>
<url-pattern>/roller-ui/rendering/feed/*</url-pattern>
</servlet-mapping>

<servlet-mapping>
<servlet-name>ResourceServlet</servlet-name>
<url-pattern>/roller-ui/rendering/resources/*</url-pattern>
</servlet-mapping>

<servlet-mapping>
<servlet-name>MediaResourceServlet</servlet-name>
<url-pattern>/roller-ui/rendering/media-resources/*</url-pattern>
</servlet-mapping>

<servlet-mapping>
<servlet-name>CommentServlet</servlet-name>
<url-pattern>/roller-ui/rendering/comment/*</url-pattern>
</servlet-mapping>

<servlet-mapping>
<servlet-name>TrackbackServlet</servlet-name>
<url-pattern>/roller-ui/rendering/trackback/*</url-pattern>
</servlet-mapping>

<servlet-mapping>
<servlet-name>RSDServlet</servlet-name>
<url-pattern>/roller-ui/rendering/rsd/*</url-pattern>
</servlet-mapping>

<servlet-mapping>
<servlet-name>SearchServlet</servlet-name>
<url-pattern>/roller-ui/rendering/search/*</url-pattern>
</servlet-mapping>

<servlet-mapping>
<servlet-name>PlanetFeedServlet</servlet-name>
<url-pattern>/planetrss/*</url-pattern>
</servlet-mapping>

<servlet-mapping>
<servlet-name>CommentAuthenticatorServlet</servlet-name>
<url-pattern>/CommentAuthenticatorServlet</url-pattern>
</servlet-mapping>


<!-- Preview Servlets -->
<servlet-mapping>
<servlet-name>PreviewServlet</servlet-name>
<url-pattern>/roller-ui/authoring/preview/*</url-pattern>
</servlet-mapping>

<servlet-mapping>
<servlet-name>PreviewResourceServlet</servlet-name>
<url-pattern>/roller-ui/authoring/previewresource/*</url-pattern>
</servlet-mapping>

<servlet-mapping>
<servlet-name>PreviewThemeImageServlet</servlet-name>
<url-pattern>/roller-ui/authoring/previewtheme</url-pattern>
</servlet-mapping>


<!-- Servlets for supporting Ajax -->
<servlet-mapping>
<servlet-name>CommentDataServlet</servlet-name>
<url-pattern>/roller-ui/authoring/commentdata/*</url-pattern>
</servlet-mapping>

<servlet-mapping>
<servlet-name>UserDataServlet</servlet-name>
<url-pattern>/roller-ui/authoring/userdata/*</url-pattern>
</servlet-mapping>


<!-- Web Service Servlets -->
<servlet-mapping>
<servlet-name>XmlRpcServlet</servlet-name>
<url-pattern>/roller-services/xmlrpc</url-pattern>
</servlet-mapping>

<servlet-mapping>
<servlet-name>AtomServlet</servlet-name>
<url-pattern>/roller-services/app/*</url-pattern>
</servlet-mapping>

<servlet-mapping>
<servlet-name>AdminServlet</servlet-name>
<url-pattern>/roller-services/rap/*</url-pattern>
</servlet-mapping>

<servlet-mapping>
<servlet-name>TagDataServlet</servlet-name>
<url-pattern>/roller-services/tagdata/*</url-pattern>
</servlet-mapping>

<servlet-mapping>
<servlet-name>OpenSearchServlet</servlet-name>
<url-pattern>/roller-services/opensearch/*</url-pattern>
</servlet-mapping>


<!-- Redirect Support for pre-3.0 urls -->
<servlet-mapping>
<servlet-name>RedirectServlet</servlet-name>
<url-pattern>/language/*</url-pattern>
</servlet-mapping>

<servlet-mapping>
<servlet-name>RedirectServlet</servlet-name>
<url-pattern>/comments/*</url-pattern>
</servlet-mapping>

<servlet-mapping>
<servlet-name>RedirectServlet</servlet-name>
<url-pattern>/resources/*</url-pattern>
</servlet-mapping>

<servlet-mapping>
<servlet-name>RedirectServlet</servlet-name>
<url-pattern>/rsd/*</url-pattern>
</servlet-mapping>

<servlet-mapping>
<servlet-name>RedirectServlet</servlet-name>
<url-pattern>/flavor/*</url-pattern>
</servlet-mapping>

<servlet-mapping>
<servlet-name>RedirectServlet</servlet-name>
<url-pattern>/rss/*</url-pattern>
</servlet-mapping>

<servlet-mapping>
<servlet-name>RedirectServlet</servlet-name>
<url-pattern>/atom/*</url-pattern>
</servlet-mapping>

<servlet-mapping>
<servlet-name>RedirectServlet</servlet-name>
<url-pattern>/page/*</url-pattern>
</servlet-mapping>

<servlet-mapping>
<servlet-name>RedirectServlet</servlet-name>
<url-pattern>/search/*</url-pattern>
</servlet-mapping>

<servlet-mapping>
<servlet-name>RedirectServlet</servlet-name>
<url-pattern>/xmlrpc/*</url-pattern>
</servlet-mapping>

<servlet-mapping>
<servlet-name>RedirectServlet</servlet-name>
<url-pattern>/editor/*</url-pattern>
</servlet-mapping>

<servlet-mapping>
<servlet-name>RedirectServlet</servlet-name>
<url-pattern>/admin/*</url-pattern>
</servlet-mapping>

<!-- Redirect support for some old struts1 urls -->
<servlet-mapping>
<servlet-name>StrutsRedirectServlet</servlet-name>
<url-pattern>/roller-ui/yourWebsites.do</url-pattern>
</servlet-mapping>

<servlet-mapping>
<servlet-name>StrutsRedirectServlet</servlet-name>
<url-pattern>/roller-ui/authoring/commentManagement.do</url-pattern>
</servlet-mapping>


<session-config>
<session-timeout>30</session-timeout>
</session-config>

<welcome-file-list>
<welcome-file>home.jsp</welcome-file>
<welcome-file>index.jsp</welcome-file>
<welcome-file>index.html</welcome-file>
</welcome-file-list>

<error-page>
<exception-type>java.lang.Exception</exception-type>
<location>/roller-ui/errors/error.jsp</location>
</error-page>

<error-page>
<error-code>403</error-code>
<location>/roller-ui/errors/403.jsp</location>
</error-page>

<error-page>
<error-code>404</error-code>
<location>/roller-ui/errors/404.jsp</location>
</error-page>


<!-- jndi resources -->
<!--<resource-ref>
<res-ref-name>jdbc/rollerdb</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>-->

<!--<resource-ref>
<res-ref-name>mail/Session</res-ref-name>
<res-type>javax.mail.Session</res-type>
<res-auth>Container</res-auth>
</resource-ref>-->

</web-app>
<!-- BEGIN: example config. for using Container Managed Authentication

<security-constraint>
<web-resource-collection>
<web-resource-name>Weblog admin and editor resources</web-resource-name>
<url-pattern>/roller-ui/createWeblog.rol</url-pattern>
<url-pattern>/roller-ui/authoring/*</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>weblog-admin</role-name>
<role-name>weblog-user</role-name>
</auth-constraint>
</security-constraint>

<security-constraint>
<web-resource-collection>
<web-resource-name>Weblog admin and editor HTTPS resources</web-resource-name>
<url-pattern>/roller-ui/login-redirect.jsp</url-pattern>
<url-pattern>/roller-ui/login-redirect.rol</url-pattern>
<url-pattern>/roller-ui/authoring/userdata</url-pattern>
<url-pattern>/roller-ui/authoring/membersInvite.rol</url-pattern>
<url-pattern>/roller-ui/authoring/membersInvite!save.rol</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>weblog-admin</role-name>
<role-name>weblog-user</role-name>
</auth-constraint>
<user-data-constraint>
<transport-guarantee>CONFIDENTIAL</transport-guarantee>
</user-data-constraint>
</security-constraint>

<security-constraint>
<web-resource-collection>
<web-resource-name>Global Admin resources</web-resource-name>
<url-pattern>/roller-ui/admin/*</url-pattern>
<url-pattern>/rewrite-status.rol</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>weblog-admin</role-name>
</auth-constraint>
</security-constraint>

<security-constraint>
<web-resource-collection>
<web-resource-name>Gobal Admin HTTPS resources</web-resource-name>
<url-pattern>/roller-ui/admin/userAdmin.rol</url-pattern>
<url-pattern>/roller-ui/admin/createUser.rol</url-pattern>
<url-pattern>/roller-ui/admin/createUser!save.rol</url-pattern>
<url-pattern>/roller-ui/admin/modifyUser.rol</url-pattern>
<url-pattern>/roller-ui/admin/modifyUser!save.rol</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>weblog-admin</role-name>
</auth-constraint>
<user-data-constraint>
<transport-guarantee>CONFIDENTIAL</transport-guarantee>
</user-data-constraint>
</security-constraint>

<security-constraint>
<web-resource-collection>
<web-resource-name>editor res</web-resource-name>
<url-pattern>/roller-ui/menu.rol</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>weblog-user</role-name>
</auth-constraint>
</security-constraint>

<security-constraint>
<web-resource-collection>
<web-resource-name>Editor HTTPS resources</web-resource-name>
<url-pattern>/roller-ui/profile.rol</url-pattern>
<url-pattern>/roller-ui/profile!save.rol</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>weblog-user</role-name>
</auth-constraint>
<user-data-constraint>
<transport-guarantee>CONFIDENTIAL</transport-guarantee>
</user-data-constraint>
</security-constraint>

<security-constraint>
<web-resource-collection>
<web-resource-name>HTTPS resources</web-resource-name>
<url-pattern>/roller-ui/login.rol</url-pattern>
<url-pattern>/roller-ui/register.rol</url-pattern>
<url-pattern>/roller-ui/register!save.rol</url-pattern>
</web-resource-collection>
<user-data-constraint>
<transport-guarantee>CONFIDENTIAL</transport-guarantee>
</user-data-constraint>
</security-constraint>

<login-config>
<auth-method>FORM</auth-method>
<realm-name>Roller_UserRealm</realm-name>
<form-login-config>
<form-login-page>/roller-ui/login.rol</form-login-page>
<form-error-page>/roller-ui/login.rol?error=true</form-error-page>
</form-login-config>
</login-config>

<security-role>
<role-name>weblog-admin</role-name>
</security-role>

<security-role>
<role-name>weblog-user</role-name>
</security-role>

END: example config. for using Container Managed Authentication -->

Step 3: Updated Security.xml:
<?xml version="1.0" encoding="UTF-8"?>

<beans:beans xmlns="http://www.springframework.org/schema/security"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:jee="http://www.springframework.org/schema/jee"
xsi:schemaLocation="http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-2.0.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-2.5.xsd">



<!-- new -->
<!--access roles : ROLE_USER,ROLE_SUPERVISOR -->
<http entry-point-ref="casProcessingFilterEntryPoint">
<intercept-url pattern="/images/**" filters="none"/>
<intercept-url pattern="/scripts/**" filters="none"/>
<intercept-url pattern="/styles/**" filters="none"/>
<intercept-url pattern="/roller-ui/login-redirect**" access="ROLE_admin,ROLE_editor" />
<!--<intercept-url pattern="/roller-ui/login-redirect**" access="IS_AUTHENTICATED_ANONYMOUSLY,ROLE_admin,ROLE_editor"/>-->
<intercept-url pattern="/roller-ui/profile**" access="ROLE_admin,ROLE_editor"/>
<intercept-url pattern="/roller-ui/createWeblog**" access="ROLE_admin,ROLE_editor"/>
<intercept-url pattern="/roller-ui/menu**" access="ROLE_admin,ROLE_editor"/>
<intercept-url pattern="/roller-ui/authoring/**" access="ROLE_admin,ROLE_editor"/>
<intercept-url pattern="/roller-ui/admin/**" access="ROLE_admin"/>
<intercept-url pattern="/rewrite-status*" access="ROLE_admin"/>
<intercept-url pattern="/roller-ui/user.do*" access="ROLE_USER"/>
<anonymous />
<http-basic />
</http>








<!-- ======================== CENTRAL AUTHENTICATION SERVICE (CAS) ======================= -->


<!--new-->
<beans:bean id="casProcessingFilter" class="org.springframework.security.ui.cas.CasProcessingFilter">
<custom-filter after="CAS_PROCESSING_FILTER"/>
<beans:property name="authenticationManager" ref="authenticationManager"/>
<beans:property name="authenticationFailureUrl" value="/roller-ui/login.rol?error=true"/>
<beans:property name="defaultTargetUrl" value="/"/>
<beans:property name="rememberMeServices" ref="rememberMeServices" />
<beans:property name="filterProcessesUrl" value="/j_spring_cas_security_check"/>
</beans:bean>

<beans:bean id="casProcessingFilterEntryPoint" class="org.springframework.security.ui.cas.CasProcessingFilterEntryPoint">

<beans:property name="loginUrl" value="http://localhost:8080/cas/login"/>

<beans:property name="serviceProperties" ref="serviceProperties"/>
</beans:bean>



<!--new-->
<beans:bean id="casAuthenticationProvider" class="org.springframework.security.providers.cas.CasAuthenticationProvider">
<custom-authentication-provider />
<beans:property name="userDetailsService" ref="userRollerService"/>
<beans:property name="serviceProperties" ref="serviceProperties" />
<beans:property name="ticketValidator">
<beans:bean class="org.jasig.cas.client.validation.Cas20ServiceTicketValidator">
<beans:constructor-arg index="0" value="http://localhost:8080/cas" />
</beans:bean>
</beans:property>
<beans:property name="key" value="an_id_for_this_auth_provider_only"/>
</beans:bean>


<beans:bean id="proxyGrantingTicketStorage" class="org.jasig.cas.client.proxy.ProxyGrantingTicketStorageImpl" />


<beans:bean id="serviceProperties" class="org.springframework.security.ui.cas.ServiceProperties">
<beans:property name="service" value="http://localj.endurotracker.com:8090/roller_custom/j_spring_cas_security_check"/>
<beans:property name="sendRenew" value="false"/>
</beans:bean>

<!-- Read users from Roller API -->

<beans:bean id="userRollerService"
class="org.apache.roller.weblogger.ui.core.security.RollerUserDetailsService" >
<beans:property name="rolePrefix" value="ROLE_"/>
</beans:bean>

<!--FOR TESTING/DEBUGGING ONLY-->
<!--<user-service id="userService">
<user name="rod" password="rod" authorities="ROLE_SUPERVISOR,ROLE_USER" />
<user name="dianne" password="dianne" authorities="ROLE_SUPERVISOR,ROLE_USER" />
<user name="scott" password="scott" authorities="ROLE_SUPERVISOR,ROLE_USER" />
</user-service>-->




<!--RememberMe Configurations -->
<beans:bean id="rememberMeProcessingFilter" class="org.springframework.security.ui.rememberme.RememberMeProcessingFilter">
<custom-filter position="REMEMBER_ME_FILTER" />
<beans:property name="authenticationManager" ref="authenticationManager" />
<beans:property name="rememberMeServices" ref="rememberMeServices" />
</beans:bean>



<!-- your customizations -->
<!--
Activates various annotations to be detected in bean classes:
Spring's @Required and @Autowired, as well as JSR 250's @Resource.
-->
<context:annotation-config />


<!--Try adding this-->
<aop:aspectj-autoproxy />

<!-- Turn on @Required -->
<beans:bean class="org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor" />



<beans:bean id="securityService"
class="yourPackage.SecurityService">
<beans:property name="usersDao" ref="usersDao" />
</beans:bean>

<!-- Note: if your usersDao uses sessionFactory you will need to add sessionFactory bean as well, this is just for illustration purposes-->
<beans:bean id="usersDao"
class="yourPackage.UsersDao">
<beans:property name="sessionFactory" ref="sessionFactory"/>
</beans:bean>

<beans:bean id="usersInRolesDao"
class="yourPackage.UsersInRolesDao">
<beans:property name="sessionFactory" ref="sessionFactory"/>
</beans:bean>

<beans:bean id="userService" class="yourPackage.UserService">
<beans:property name="usersDao" ref="usersDao" />
<beans:property name="authMgr" ref="authenticationManager"/>
<beans:property name="userCache" ref="userCache" />
<beans:property name="messageSource" ref="messageSource" />
<beans:property name="userTokenCache" ref="userTokenCache"/>
</beans:bean>

<beans:bean id="rememberMeAuthenticationProvider" class="org.springframework.security.providers.rememberme.RememberMeAuthenticationProvider">
<custom-authentication-provider />
<beans:property name="key" value="CHANGE_THIS_2" />
</beans:bean>


<beans:bean id="authenticationManager" class="org.springframework.security.providers.ProviderManager">
<beans:property name="providers">
<beans:list>
<beans:ref local="casAuthenticationProvider" />
<beans:bean class="org.springframework.security.providers.anonymous.AnonymousAuthenticationProvider">
<beans:property name="key" value="CHANGE_THIS_1" />
</beans:bean>
<beans:ref local="rememberMeAuthenticationProvider" />
</beans:list>
</beans:property>
</beans:bean>


<!--NOTE : Don't forget to implement a RollerRememberMeServices class, unless you use the Plain vanilla Spring Security RemberMeServices class -->
<!--plain vanilla using regular Spring Security-->
<!--<bean id="rememberMeServices" class="org.springframework.security.ui.rememberme.TokenBasedRememberMeServices">
<property name="userDetailsService" ref="usersDao"/>
<property name="key" value="CHANGE_THIS_2"/>
</bean>-->


<beans:bean id="rememberMeServices" class="org.apache.roller.weblogger.business.rememberme.RollerRememberMeServices">
<beans:property name="userDetailsService" ref="userRollerService" />
<beans:property name="userService" ref="userService" />
<beans:property name="key" value="CHANGE_THIS_2" />
<beans:property name="parameter" value="_spring_security_remember_me" />
<beans:property name="cookieName" value="SPRING_SECURITY_REMEMBER_ME_COOKIE" />
<beans:property name="cookieDomain" value=".yourwebsite.com" />
<beans:property name="tokenValiditySeconds" value="1209600" />
</beans:bean>


<beans:bean id="passwordEncoder" class="yourPackage.PasswordEncoder">
<beans:property name="passwordFormatforBean" value="Hashed" />
</beans:bean>

<beans:bean id="userTokenCache" class="org.springframework.cache.ehcache.EhCacheFactoryBean">
<beans:property name="cacheManager" ref="cacheManager" />
<beans:property name="cacheName" value = "yourPackage.UserTokenCache"/>
</beans:bean>

<beans:bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
<beans:property name="configLocation" value="classpath:ehcache.xml" />
</beans:bean>

<beans:bean id="userCacheBackend" class="org.springframework.cache.ehcache.EhCacheFactoryBean">
<beans:property name="cacheManager" ref="cacheManager" />
<beans:property name="cacheName" value="userCache" />
</beans:bean>

<beans:bean id="userCache" class="org.springframework.security.providers.dao.cache.EhCacheBasedUserCache">
<beans:property name="cache">
<beans:ref local="userCacheBackend" />
</beans:property>
</beans:bean>



</beans:beans>


Integrating Roller with CAS 4 Completed !

No comments:

Post a Comment