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/*