Holder for CAS Returned Information
The following class is used to hold the information returned in the CAS Assertion. I have pulled out the getters, setters, equals and toString.
package org.yfu.util.cas;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import javax.inject.Inject;
import org.apache.commons.lang.StringUtils;
import org.jasig.cas.client.validation.Assertion;
import org.jboss.solder.logging.Logger;
import org.picketlink.idm.api.User;
public class CASUserBean implements Serializable, User
{
private static final long serialVersionUID = 401263788421715826L;
@Inject
private Logger log;
private static final String STUDENT = "student";
// private static final String HOST_FAMILY = "hostfamily";
// private static final String PARTNER = "partner";
private static final String VOLUNTEER = "volunteer";
private static final String STAFF = "staff";
private static final String REWARDS = "Rewards";
private static final String TELEPHONE_NUMBER = "telephoneNumber";
private static final String DEPARTMENT = "department";
private static final String MAIL = "mail";
private static final String TITLE = "title";
private static final String ELECTRONIC_SIGNATURE = "electronicSignature";
private static final String USER_LEVEL = "userLevel";
private static final String POSTAL_CODE = "postalCode";
private static final String SECURITY_QUESTION_ANSWER = "securityQuestionAnswer";
private static final String SECURITY_QUESTION = "securityQuestion";
private static final String PFO = "pfo";
private static final String DISTINGUISHED_NAME = "distinguishedName";
private static final String USER_PRINCIPAL_NAME = "userPrincipalName";
private static final String NAME = "Name";
private Integer pfoId;
private String username;
private String name;
private List<String> groups = new ArrayList<String>();;
private String email;
private String securityQuestion;
private String securityQuestionAnswer;
private String postalCode;
private String electronicSignature;
private String title;
private String studentID;
private String department;
private String telephone;
private String userLevel;
private Date validUntilDate;
private Date validFromDate;
private String distinguishedName;
private boolean loggedIn;
private boolean staff;
private boolean volunteer;
public CASUserBean() {
}
public void init(Assertion assertion) {
if (assertion != null && assertion.getPrincipal() != null) {
this.validFromDate = assertion.getValidFromDate();
this.validUntilDate = assertion.getValidUntilDate();
Map<String, Object> attribs = assertion.getPrincipal().getAttributes();
this.department = (String) attribs.get(DEPARTMENT);
this.distinguishedName = (String) attribs.get(DISTINGUISHED_NAME);
this.electronicSignature = (String) attribs.get(ELECTRONIC_SIGNATURE);
this.email = (String) attribs.get(MAIL);
this.name = (String) attribs.get(NAME);
this.postalCode = (String) attribs.get(POSTAL_CODE);
this.securityQuestion = (String) attribs.get(SECURITY_QUESTION);
this.securityQuestionAnswer = (String) attribs.get(SECURITY_QUESTION_ANSWER);
this.studentID = (String) attribs.get(STUDENT);
this.telephone = (String) attribs.get(TELEPHONE_NUMBER);
this.title = (String) attribs.get(TITLE);
this.userLevel = (String) attribs.get(USER_LEVEL);
this.username = (String) attribs.get(USER_PRINCIPAL_NAME);
this.setLoggedIn(true);
String value = (String) attribs.get(PFO);
if (org.apache.commons.lang.StringUtils.isNotBlank(value)
&& org.apache.commons.lang.StringUtils.isNumeric(value)) {
this.pfoId = Integer.valueOf(value);
}
groups = new ArrayList<String>();
Object ldapGroups = attribs.get("group");
if (ldapGroups instanceof List) {
List<?> list = (List<?>) ldapGroups;
for (Object obj : list ) {
String group = (String) obj;
addRole(group);
}
} else {
addRole((String) ldapGroups);
}
value = getDistinguishedName();
if (StringUtils.contains(value, "DC=YFUUSA,DC=Local")) {
groups.add(STAFF);
}
setStaff(getGroups().contains(STAFF));
setVolunteer(getGroups().contains(VOLUNTEER));
}
}
private void addRole(String group) {
log.trace(group);
group = StringUtils.substringAfter(group, "CN=");
log.trace(group);
group = StringUtils.substringBefore(group, ",");
log.trace(group);
if (StringUtils.isNotBlank(group)) {
groups.add(group);
}
}
@Override
public String getKey() {
return getDistinguishedName();
}
@Override
public String getId() {
return "" + getPfoId();
}
}
Producer For CASUserBean
Nothing much interesting here. Just a simple producer. You could get away with out this I have it since I started not using Seam Security.
package org.yfu.util.cas;
import javax.enterprise.context.RequestScoped;
import javax.enterprise.context.SessionScoped;
import javax.enterprise.inject.Alternative;
import javax.enterprise.inject.New;
import javax.enterprise.inject.Produces;
import javax.inject.Inject;
import javax.inject.Named;
import javax.servlet.http.HttpSession;
import org.jasig.cas.client.util.AbstractCasFilter;
import org.jasig.cas.client.validation.Assertion;
import org.jboss.solder.servlet.http.HttpSessionStatus;
@RequestScoped @Alternative
public class CASUserProducer {
@Inject private HttpSessionStatus sessionStatus;
public CASUserProducer() {
}
@Produces
@Named("casUser")
@SessionScoped
public CASUserBean getCasUser(@New CASUserBean user) {
CASUserBean ret = user;
ret.setName("Not Logged in");
if (sessionStatus.isActive()) {
HttpSession session = sessionStatus.get();
Assertion assertion = (Assertion) session.getAttribute(AbstractCasFilter.CONST_CAS_ASSERTION);
if (assertion != null && assertion.getPrincipal() != null) {
user.init(assertion);
ret = user;
}
}
return ret;
}
}
Seam Security Authenticator
The need this little class so that we can tell Seam Security we are logged in. We also set the CASUserBean as our User.
package org.yfu.util.cas;
import javax.inject.Inject;
import javax.inject.Named;
import org.jboss.seam.security.BaseAuthenticator;
import org.jboss.seam.security.Identity;
public class CASSeamAuthenticator extends BaseAuthenticator
{
@Inject @Named("casUser") private CASUserBean casUser;
public CASSeamAuthenticator() {
}
@Override
public void authenticate() {
if (casUser != null && casUser.isLoggedIn()) {
setStatus(AuthenticationStatus.SUCCESS);
setUser(casUser);
}
}
@Override
public void postAuthenticate() {
}
}
A Servlet Filter
We now create a Servlet filter that will be placed after our CAS Servlet Filters. This is where we actually do the login (see line 38).
package org.jasig.cas.client.seam3.authentication;
import java.io.IOException;
import javax.inject.Inject;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.jasig.cas.client.util.AbstractCasFilter;
import org.jasig.cas.client.validation.Assertion;
import org.jboss.seam.security.Identity;
import org.yfu.util.cas.CASUserBean;
public class Seam3SecurityAuthenticationFilter implements Filter {
@Inject private Identity identity;
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse,
FilterChain chain) throws IOException, ServletException {
final HttpServletRequest request = (HttpServletRequest) servletRequest;
final HttpServletResponse response = (HttpServletResponse) servletResponse;
final HttpSession session = request.getSession(false);
final Assertion assertion = session != null ? (Assertion) session.getAttribute(AbstractCasFilter.CONST_CAS_ASSERTION) : null;
if (!identity.isLoggedIn() && assertion != null) {
identity.login(); // this is alway successful
CASUserBean user = (CASUserBean) identity.getUser();
// Now we will add LDAP Groups as Groups with a group type of group.
for (String group : user.getGroups()) {
identity.addGroup(group, "group");
}
}
chain.doFilter(request, response);
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void destroy() {
}
}
Include the filter in the web.xml
I included the CAS filters so that you can see them in order. The order of the filter mappings is vitally important.
CASWebAuthenticationFilter org.jasig.cas.client.jboss.authentication.WebAuthenticationFilter7 casServerLoginUrl https://login.yfu.org/cas/login serverName ${cas.serverName} CASAuthenticationFilter org.jasig.cas.client.authentication.AuthenticationFilter casServerLoginUrl https://login.yfu.org/cas/login serverName ${cas.serverName} CASSeam3SecurityFilter org.jasig.cas.client.seam3.authentication.Seam3SecurityAuthenticationFilter CASWebAuthenticationFilter /secured/* CASAuthenticationFilter /secured/* CASSeam3SecurityFilter /secured/*