Introduction
The following guide explains how we modified Sun Access Manager (AM) to implement CAS single sign on for the AM 7.1 proptected applications.
CAS Login Module
Create a module properties file named CASAMLoginModule.xml.
...
*Tips: for development purpose, you can put the jars and xml into amserver.war directly and redeploy it as a normal web application on your web container. The directory structure is as follows:
amserver.war\WEB-INF\lib\CASAMLoginModule.jar
amserver.war\WEB-INF\lib\casclient.jar
amserver.war\config\auth\default\CASAMLoginModule.xml
Configuring Access Manager
Login to Access Manager Console as amadmin, using the URL: http://<host>.<domain>:<port>/amserver/UI/Login.
...
Click on save button to save the changes in console.
Running the Login Module
Enter URL http://<host>.<domain>:<port>/amserver/UI/Login?module=CAS&goto=http://<host>.<domain>:<port>/portal/dt. (If you choose to use an organization other than the default, please specify that in the URL using the 'org' parameter.)
CASAMLoginModule.java
Code Block |
---|
package cas.am; import java.util.Map; import javax.security.auth.Subject; import javax.security.auth.callback.Callback; import javax.security.auth.login.LoginException; import com.sun.identity.authentication.spi.AMLoginModule; import com.sun.identity.authentication.spi.AuthLoginException; import javax.servlet.http.HttpServletRequest; import edu.yale.its.tp.cas.client.*; public class CASAMLoginModule extends AMLoginModule { private String userTokenId; private java.security.Principal userPrincipal = null; public CASAMLoginModule() throws LoginException{ System.out.println("CASAMLoginModule()"); } public void init(Subject subject, Map sharedState, Map options) { System.out.println("CASAMLoginModule initialization"); } /** * Returns a service ID (URL) as a composite of the preconfigured server * name and the runtime request. */ private String getService(HttpServletRequest request) throws AuthLoginException{ String casServerName = request.getServerName()+":"+request.getServerPort(); try { String service = Util.getService(request, casServerName); return service; } catch (Exception e){ throw new AuthLoginException(""); } } public int process(Callback[] callbacks, int state) throws AuthLoginException { int currentState = state; HttpServletRequest request = getHttpServletRequest(); String urlOfThisService = getService(request); //TODO remove hardcode of cas urls. String casLoginURL = "https://localhost:8443/cas/login"; String casValidateURL = "https://localhost:8443/cas/serviceValidate"; String loginFailureURL = casLoginURL + "?service=" + urlOfThisService; setLoginFailureURL(loginFailureURL); String ticket = request.getParameter("ticket"); if(ticket==null) { System.out.println("CASAMLoginModule Authentication No Ticket!"); throw new AuthLoginException("no ticket found!"); } String user = null; String errorCode = null; String errorMessage = null; /* instantiate a new ServiceTicketValidator */ ServiceTicketValidator sv = new ServiceTicketValidator(); /* set its parameters */ sv.setCasValidateUrl(casValidateURL); sv.setService(urlOfThisService); sv.setServiceTicket(ticket); /* contact CAS and validate */ try{ sv.validate(); } catch (Exception e) { System.out.println("CASAMLoginModule Authentication Validate Fail!"); throw new AuthLoginException(e.getMessage()); } if(sv.isAuthenticationSuccesful()) { user = sv.getUser(); } else { errorCode = sv.getErrorCode(); errorMessage = sv.getErrorMessage(); /* handle the error */ System.out.println("CASAMLoginModule Authentication Fail!" + errorMessage); throw new AuthLoginException(errorMessage); } /* The user is now authenticated. */ userTokenId = user; System.out.println("CASAMLoginModule Authentication Pass!"); return -1; } public java.security.Principal getPrincipal() { if (userPrincipal != null) { return userPrincipal; } else if (userTokenId != null) { userPrincipal = new CASAMPrincipal(userTokenId); return userPrincipal; } else { return null; } } } |
CASAMPrincipal.java
Code Block |
---|
package cas.am; import javax.security.auth.*; import javax.security.auth.login.*; import javax.security.auth.callback.*; import java.security.Principal; public class CASAMPrincipal implements Principal, java.io.Serializable { /** * @serial */ private String name; public CASAMPrincipal(String name) { if (name == null) throw new NullPointerException("illegal null input"); this.name = name; } /** * Return the username for this <code>CASAMPrincipal</code>. * * <p> * * @return the username for this <code>CASAMPrincipal</code> */ public String getName() { return name; } /** * Return a string representation of this <code>CASAMPrincipal</code>. * * <p> * * @return a string representation of this <code>CASAMPrincipal</code>. */ public String toString() { return("CASAMPrincipal: " + name); } /** * Compares the specified Object with this <code>CASAMPrincipal</code> * for equality. Returns true if the given object is also a * <code>CASAMPrincipal</code> and the two CASAMPrincipals * have the same username. * * <p> * * @param o Object to be compared for equality with this * <code>CASAMPrincipal</code>. * * @return true if the specified Object is equal equal to this * <code>CASAMPrincipal</code>. */ public boolean equals(Object o) { if (o == null) return false; if (this == o) return true; if (!(o instanceof CASAMPrincipal)) return false; CASAMPrincipal that = (CASAMPrincipal)o; if (this.getName().equals(that.getName())) return true; return false; } /** * Return a hash code for this <code>CASAMPrincipal</code>. * * <p> * * @return a hash code for this <code>CASAMPrincipal</code>. */ public int hashCode() { return name.hashCode(); } } |
CASAMLoginModule.xml
Code Block |
---|
<?xml version='1.0' encoding="UTF-8"?> <!DOCTYPE ModuleProperties PUBLIC "=//iPlanet//Authentication Module Properties XML Interface 1.0 DTD//EN" "jar://com/sun/identity/authentication/Auth_Module_Properties.dtd"> <ModuleProperties moduleName="CAS" version="1.0" > </ModuleProperties> |