diff --git a/cas-client-core/pom.xml b/cas-client-core/pom.xml
index 27855f6..3523168 100644
--- a/cas-client-core/pom.xml
+++ b/cas-client-core/pom.xml
@@ -2,7 +2,7 @@
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
org.jasig.cas
- 3.1.10
+ 3.1.11-SNAPSHOTcas-client4.0.0
@@ -10,50 +10,6 @@
cas-client-corejarJA-SIG CAS Client for Java - Core
-
- src/main/java
- src/test/java
-
-
- src/test/resources
- false
-
-
-
-
- org.apache.maven.plugins
- maven-compiler-plugin
-
- 1.4
- 1.4
-
-
-
- org.apache.maven.plugins
- maven-surefire-plugin
-
-
- **/*Tests*
-
-
-
-
- org.apache.maven.plugins
- maven-clover-plugin
-
- ${basedir}/src/test/clover/clover.license
-
-
-
- pre-site
-
- instrument
-
-
-
-
-
-
diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/authentication/AttributePrincipalImpl.java b/cas-client-core/src/main/java/org/jasig/cas/client/authentication/AttributePrincipalImpl.java
index e30ed93..27753dd 100644
--- a/cas-client-core/src/main/java/org/jasig/cas/client/authentication/AttributePrincipalImpl.java
+++ b/cas-client-core/src/main/java/org/jasig/cas/client/authentication/AttributePrincipalImpl.java
@@ -15,15 +15,12 @@ import java.util.Map;
* @version $Revision$ $Date$
* @since 3.1
*/
-public class AttributePrincipalImpl implements AttributePrincipal {
+public class AttributePrincipalImpl extends SimplePrincipal implements AttributePrincipal {
- private static final Log LOG = LogFactory.getLog(AttributePrincipalImpl.class);
+ private static final Log LOG = LogFactory.getLog(AttributePrincipalImpl.class);
/** Unique Id for Serialization */
- private static final long serialVersionUID = -8810123156070148535L;
-
- /** The unique identifier for this principal. */
- private final String name;
+ private static final long serialVersionUID = -1443182634624927187L;
/** Map of key/value pairs about this principal. */
private final Map attributes;
@@ -73,12 +70,11 @@ public class AttributePrincipalImpl implements AttributePrincipal {
* @param proxyRetriever the ProxyRetriever implementation to call back to the CAS server.
*/
public AttributePrincipalImpl(final String name, final Map attributes, final String proxyGrantingTicket, final ProxyRetriever proxyRetriever) {
- this.name = name;
+ super(name);
this.attributes = attributes;
this.proxyGrantingTicket = proxyGrantingTicket;
this.proxyRetriever = proxyRetriever;
- CommonUtils.assertNotNull(this.name, "name cannot be null.");
CommonUtils.assertNotNull(this.attributes, "attributes cannot be null.");
}
@@ -94,8 +90,4 @@ public class AttributePrincipalImpl implements AttributePrincipal {
LOG.debug("No ProxyGrantingTicket was supplied, so no Proxy Ticket can be retrieved.");
return null;
}
-
- public String getName() {
- return this.name;
- }
}
diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/authentication/SimpleGroup.java b/cas-client-core/src/main/java/org/jasig/cas/client/authentication/SimpleGroup.java
new file mode 100644
index 0000000..9bdad71
--- /dev/null
+++ b/cas-client-core/src/main/java/org/jasig/cas/client/authentication/SimpleGroup.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2010 The JA-SIG Collaborative. All rights reserved. See license
+ * distributed with this file and available online at
+ * http://www.ja-sig.org/products/cas/overview/license/index.html
+ */
+package org.jasig.cas.client.authentication;
+
+import java.security.Principal;
+import java.security.acl.Group;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+/**
+ * Simple security group implementation
+ *
+ * @author Marvin S. Addison
+ * @version $Revision$
+ * @since 3.1.11
+ *
+ */
+public final class SimpleGroup extends SimplePrincipal implements Group {
+
+ private static final long serialVersionUID = 1541943977571896383L;
+
+ private final Set members = new HashSet();
+
+ /**
+ * Creates a new group with the given name.
+ * @param name Group name.
+ */
+ public SimpleGroup(final String name) {
+ super(name);
+ }
+
+ public boolean addMember(final Principal user) {
+ return this.members.add(user);
+ }
+
+ public boolean isMember(final Principal member) {
+ return this.members.contains(member);
+ }
+
+ public Enumeration members() {
+ return new EnumerationAdapter(this.members.iterator());
+ }
+
+ public boolean removeMember(final Principal user) {
+ return this.members.remove(user);
+ }
+
+ public String toString() {
+ return super.toString() + ": " + members.toString();
+ }
+
+ /**
+ * Adapts a {@link java.util.Iterator} onto an {@link java.util.Enumeration}.
+ */
+ private static class EnumerationAdapter implements Enumeration {
+
+ /** Iterator backing enumeration operations */
+ private Iterator iterator;
+
+ /**
+ * Creates a new instance backed by the given iterator.
+ * @param i Iterator backing enumeration operations.
+ */
+ public EnumerationAdapter(final Iterator i) {
+ this.iterator = i;
+ }
+
+ public boolean hasMoreElements() {
+ return this.iterator.hasNext();
+ }
+
+ public Object nextElement() {
+ return this.iterator.next();
+ }
+ }
+}
diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/authentication/SimplePrincipal.java b/cas-client-core/src/main/java/org/jasig/cas/client/authentication/SimplePrincipal.java
new file mode 100644
index 0000000..832a06c
--- /dev/null
+++ b/cas-client-core/src/main/java/org/jasig/cas/client/authentication/SimplePrincipal.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2010 The JA-SIG Collaborative. All rights reserved. See license
+ * distributed with this file and available online at
+ * http://www.ja-sig.org/products/cas/overview/license/index.html
+ */
+package org.jasig.cas.client.authentication;
+
+import java.io.Serializable;
+import java.security.Principal;
+
+import org.jasig.cas.client.util.CommonUtils;
+
+/**
+ * Simple security principal implementation.
+ *
+ * @author Marvin S. Addison
+ * @version $Revision$
+ * @since 3.1.11
+ *
+ */
+public class SimplePrincipal implements Principal, Serializable {
+
+ /** SimplePrincipal.java */
+ private static final long serialVersionUID = -5645357206342793145L;
+
+ /** The unique identifier for this principal. */
+ private final String name;
+
+ /**
+ * Creates a new principal with the given name.
+ * @param name Principal name.
+ */
+ public SimplePrincipal(final String name) {
+ this.name = name;
+ CommonUtils.assertNotNull(this.name, "name cannot be null.");
+ }
+
+ public final String getName() {
+ return this.name;
+ }
+
+ public String toString() {
+ return getName();
+ }
+
+ public boolean equals(final Object o) {
+ if (o == null) {
+ return false;
+ } else if (!(o instanceof SimplePrincipal)) {
+ return false;
+ } else {
+ return getName().equals(((SimplePrincipal)o).getName());
+ }
+ }
+
+ public int hashCode() {
+ return 37 * getName().hashCode();
+ }
+}
diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/jaas/AssertionPrincipal.java b/cas-client-core/src/main/java/org/jasig/cas/client/jaas/AssertionPrincipal.java
new file mode 100644
index 0000000..3bc232a
--- /dev/null
+++ b/cas-client-core/src/main/java/org/jasig/cas/client/jaas/AssertionPrincipal.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2010 The JA-SIG Collaborative. All rights reserved. See license
+ * distributed with this file and available online at
+ * http://www.ja-sig.org/products/cas/overview/license/index.html
+ */
+package org.jasig.cas.client.jaas;
+
+import java.io.Serializable;
+
+import org.jasig.cas.client.authentication.SimplePrincipal;
+import org.jasig.cas.client.validation.Assertion;
+
+/**
+ * Principal implementation that contains the CAS ticket validation assertion.
+ *
+ * @author Marvin S. Addison
+ * @version $Revision$
+ * @since 3.1.11
+ *
+ */
+public class AssertionPrincipal extends SimplePrincipal implements Serializable {
+
+ /** AssertionPrincipal.java */
+ private static final long serialVersionUID = 2288520214366461693L;
+
+ private Assertion assertion;
+
+ /**
+ * Creates a new principal containing the CAS assertion.
+ *
+ * @param name Principal name.
+ * @param assertion CAS assertion.
+ */
+ public AssertionPrincipal(final String name, final Assertion assertion) {
+ super(name);
+ this.assertion = assertion;
+ }
+
+ /**
+ * @return CAS ticket validation assertion.
+ */
+ public Assertion getAssertion() {
+ return this.assertion;
+ }
+}
diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/jaas/CasLoginModule.java b/cas-client-core/src/main/java/org/jasig/cas/client/jaas/CasLoginModule.java
new file mode 100644
index 0000000..a7c7063
--- /dev/null
+++ b/cas-client-core/src/main/java/org/jasig/cas/client/jaas/CasLoginModule.java
@@ -0,0 +1,365 @@
+/*
+ * Copyright 2010 The JA-SIG Collaborative. All rights reserved. See license
+ * distributed with this file and available online at
+ * http://www.ja-sig.org/products/cas/overview/license/index.html
+ */
+package org.jasig.cas.client.jaas;
+
+import java.beans.BeanInfo;
+import java.beans.IntrospectionException;
+import java.beans.Introspector;
+import java.beans.PropertyDescriptor;
+import java.io.IOException;
+import java.security.acl.Group;
+import java.util.*;
+
+import javax.security.auth.Subject;
+import javax.security.auth.callback.Callback;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.callback.NameCallback;
+import javax.security.auth.callback.PasswordCallback;
+import javax.security.auth.callback.UnsupportedCallbackException;
+import javax.security.auth.login.LoginException;
+import javax.security.auth.spi.LoginModule;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.jasig.cas.client.authentication.SimpleGroup;
+import org.jasig.cas.client.authentication.SimplePrincipal;
+import org.jasig.cas.client.util.CommonUtils;
+import org.jasig.cas.client.util.ReflectUtils;
+import org.jasig.cas.client.validation.Assertion;
+import org.jasig.cas.client.validation.TicketValidator;
+
+/**
+ * JAAS login module that delegates to a CAS {@link TicketValidator} component
+ * for authentication, and on success populates a {@link Subject} with principal
+ * data including NetID and principal attributes. The module expects to be provided
+ * with the CAS ticket (required) and service (optional) parameters via
+ * {@link PasswordCallback} and {@link NameCallback}, respectively, by the
+ * {@link CallbackHandler} that is part of the JAAS framework in which the servlet
+ * resides.
+ *
+ *
+ * Module configuration options:
+ *
+ *
ticketValidatorClass - Fully-qualified class name of CAS ticket validator class.
+ *
casServerUrlPrefix - URL to root of CAS Web application context.
+ *
service (optional) - CAS service parameter that may be overridden by callback handler.
+ * NOTE: service must be specified by at least one component such that it is available at
+ * service ticket validation time
+ *
defaultRoles (optional) - Comma-delimited list of static roles applied to all
+ * authenticated principals.
+ *
roleAttributeNames (optional) - Comma-delimited list of attribute names that describe
+ * role data delivered to CAS in the service-ticket validation response that should be
+ * applied to the current authenticated principal.
+ *
principalGroupName (optional) - The name of a group principal containing the
+ * primary principal name of the current JAAS subject. The default value is "CallerPrincipal",
+ * which is suitable for JBoss.
+ *
roleGroupName (optional) - The name of a group principal containing all role data.
+ * The default value is "Roles", which is suitable for JBoss.
+ *
+ *
+ *
+ * Module options not explicitly listed above are treated as attributes of the
+ * given ticket validator class, e.g. tolerance in the following example.
+ *
+ *
+ * Sample jaas.config file entry for this module:
+ *
+ *
+ * @author Marvin S. Addison
+ * @version $Revision$
+ * @since 3.1.11
+ *
+ */
+public class CasLoginModule implements LoginModule {
+ /** Constant for login name stored in shared state. */
+ public static final String LOGIN_NAME = "javax.security.auth.login.name";
+
+ /**
+ * Default group name for storing caller principal.
+ * The default value supports JBoss, but is configurable to hopefully
+ * support other JEE containers.
+ */
+ public static final String DEFAULT_PRINCIPAL_GROUP_NAME = "CallerPrincipal";
+
+ /**
+ * Default group name for storing role membership data.
+ * The default value supports JBoss, but is configurable to hopefully
+ * support other JEE containers.
+ */
+ public static final String DEFAULT_ROLE_GROUP_NAME = "Roles";
+
+ /** Logger instance */
+ protected final Log log = LogFactory.getLog(getClass());
+
+ /** JAAS authentication subject */
+ protected Subject subject;
+
+ /** JAAS callback handler */
+ protected CallbackHandler callbackHandler;
+
+ /** CAS ticket validator */
+ protected TicketValidator ticketValidator;
+
+ /** CAS service parameter used if no service is provided via TextCallback on login */
+ protected String service;
+
+ /** CAS assertion */
+ protected Assertion assertion;
+
+ /** Login module shared state */
+ protected Map sharedState;
+
+ /** Roles to be added to all authenticated principals by default */
+ protected String[] defaultRoles;
+
+ /** Names of attributes in the CAS assertion that should be used for role data */
+ protected Set roleAttributeNames = new HashSet();
+
+ /** Name of JAAS Group containing caller principal */
+ protected String principalGroupName = DEFAULT_PRINCIPAL_GROUP_NAME;
+
+ /** Name of JAAS Group containing role data */
+ protected String roleGroupName = DEFAULT_ROLE_GROUP_NAME;
+
+
+ /**
+ * Initializes the CAS login module.
+ * @param subject Authentication subject.
+ * @param handler Callback handler.
+ * @param state Shared state map.
+ * @param options Login module options. The following are supported:
+ *
+ *
service - CAS service URL used for service ticket validation
+ *
ticketValidatorClass - fully-qualified class name of service ticket validator component
+ *
defaultRoles (optional) - comma-delimited list of roles to be added to all authenticated principals
+ *
roleAttributeNames (optional) - comma-delimited list of attributes in the CAS assertion that contain role data
+ *
principalGroupName (optional) - name of JAAS Group containing caller principal
+ *
roleGroupName (optional) - name of JAAS Group containing role data
+ *
+ */
+ public void initialize(final Subject subject, final CallbackHandler handler, final Map state, final Map options) {
+ this.callbackHandler = handler;
+ this.subject = subject;
+ this.sharedState = state;
+
+ String ticketValidatorClass = null;
+ final Iterator iter = options.keySet().iterator();
+ while (iter.hasNext()) {
+ final Object key = iter.next();
+ log.trace("Processing option " + key);
+ if ("service".equals(key)) {
+ this.service = (String) options.get(key);
+ log.debug("Set service=" + this.service);
+ } else if ("ticketValidatorClass".equals(key)) {
+ ticketValidatorClass = (String) options.get(key);
+ log.debug("Set ticketValidatorClass=" + ticketValidatorClass);
+ } else if ("defaultRoles".equals(key)) {
+ final String roles = (String) options.get(key);
+ log.trace("Got defaultRoles value " + roles);
+ this.defaultRoles = roles.split(",\\s*");
+ log.debug("Set defaultRoles=" + this.defaultRoles);
+ } else if ("roleAttributeNames".equals(key)) {
+ final String attrNames = (String) options.get(key);
+ log.trace("Got roleAttributeNames value " + attrNames);
+ final String[] attributes = attrNames.split(",\\s*");
+ this.roleAttributeNames.addAll(Arrays.asList(attributes));
+ log.debug("Set roleAttributeNames=" + this.roleAttributeNames);
+ } else if ("principalGroupName".equals(key)) {
+ this.principalGroupName = (String) options.get(key);
+ log.debug("Set principalGroupName=" + this.principalGroupName);
+ } else if ("roleGroupName".equals(key)) {
+ this.roleGroupName = (String) options.get(key);
+ log.debug("Set roleGroupName=" + this.principalGroupName);
+ }
+ }
+
+ CommonUtils.assertNotNull(ticketValidatorClass, "ticketValidatorClass is required.");
+ this.ticketValidator = createTicketValidator(ticketValidatorClass, options);
+ }
+
+ public boolean login() throws LoginException {
+ log.debug("Performing login.");
+ final NameCallback serviceCallback = new NameCallback("service");
+ final PasswordCallback ticketCallback = new PasswordCallback("ticket", false);
+ try {
+ this.callbackHandler.handle(new Callback[] { ticketCallback, serviceCallback });
+ } catch (final IOException e) {
+ log.info("Login failed due to IO exception in callback handler: " + e);
+ throw new LoginException("IO exception in callback handler: " + e);
+ } catch (final UnsupportedCallbackException e) {
+ log.info("Login failed due to unsupported callback: " + e);
+ throw new LoginException("Callback handler does not support PasswordCallback and TextInputCallback.");
+ }
+ if (ticketCallback.getPassword() != null) {
+ final String ticket = new String(ticketCallback.getPassword());
+ final String service = CommonUtils.isNotBlank(serviceCallback.getName()) ? serviceCallback.getName() : this.service;
+
+ if (CommonUtils.isBlank(service)) {
+ log.info("Login failed because required CAS service parameter not provided.");
+ throw new LoginException("Neither login module nor callback handler provided required service parameter.");
+ }
+ try {
+ log.debug("Attempting ticket validation with service=" + service + " and ticket=" + ticket);
+ this.assertion = this.ticketValidator.validate(ticket, service);
+ } catch (final Exception e) {
+ log.info("Login failed due to CAS ticket validation failure: " + e);
+ throw new LoginException("CAS ticket validation failed: " + e);
+ }
+ } else {
+ log.info("Login failed because callback handler did not provide CAS ticket.");
+ throw new LoginException("Callback handler did not provide CAS ticket.");
+ }
+ log.info("Login succeeded.");
+ return true;
+ }
+
+ public boolean abort() throws LoginException {
+ if (this.assertion != null) {
+ this.assertion = null;
+ return true;
+ }
+ return false;
+ }
+
+ public boolean commit() throws LoginException {
+ if (this.assertion != null) {
+ final AssertionPrincipal casPrincipal = new AssertionPrincipal(this.assertion.getPrincipal().getName(), this.assertion);
+ this.subject.getPrincipals().add(casPrincipal);
+
+ // Add group containing principal as sole member
+ // Supports JBoss JAAS use case
+ final Group principalGroup = new SimpleGroup(this.principalGroupName);
+ principalGroup.addMember(casPrincipal);
+ this.subject.getPrincipals().add(principalGroup);
+
+ // Add group principal containing role data
+ final Group roleGroup = new SimpleGroup(this.roleGroupName);
+ for (int i = 0; i < defaultRoles.length; i++) {
+ roleGroup.addMember(new SimplePrincipal(defaultRoles[i]));
+ }
+ final Map attributes = this.assertion.getPrincipal().getAttributes();
+ final Iterator nameIterator = attributes.keySet().iterator();
+ while (nameIterator.hasNext()) {
+ final Object key = nameIterator.next();
+ if (this.roleAttributeNames.contains(key)) {
+ // Attribute value is Object if singular or Collection if plural
+ final Object value = attributes.get(key);
+ if (value instanceof Collection) {
+ final Iterator valueIterator = ((Collection) value).iterator();
+ while (valueIterator.hasNext()) {
+ roleGroup.addMember(new SimplePrincipal(valueIterator.next().toString()));
+ }
+ } else {
+ roleGroup.addMember(new SimplePrincipal(value.toString()));
+ }
+ }
+ }
+ this.subject.getPrincipals().add(roleGroup);
+
+ // Place principal name in shared state for downstream JAAS modules (module chaining use case)
+ this.sharedState.put(LOGIN_NAME, casPrincipal.getName());
+
+ if (log.isDebugEnabled()) {
+ log.debug("Created JAAS subject with principals: " + subject.getPrincipals());
+ }
+ return true;
+ }
+ return false;
+ }
+
+ public boolean logout() throws LoginException {
+ if (this.assertion != null) {
+ log.debug("Performing logout.");
+ this.subject.getPrincipals().remove(this.assertion.getPrincipal());
+ // Remove all SimpleGroup principals
+ final Iterator iter = this.subject.getPrincipals().iterator();
+ while (iter.hasNext()) {
+ if (iter.next() instanceof SimpleGroup) {
+ iter.remove();
+ }
+ }
+ this.assertion = null;
+ log.info("Logout succeeded.");
+ return true;
+ }
+ return false;
+ }
+
+
+ /**
+ * Creates a {@link TicketValidator} instance from a class name and map of property name/value pairs.
+ * @param className Fully-qualified name of {@link TicketValidator} concrete class.
+ * @param propertyMap Map of property name/value pairs to set on validator instance.
+ * @return Ticket validator with properties set.
+ */
+ private TicketValidator createTicketValidator(final String className, final Map propertyMap) {
+ CommonUtils.assertTrue(propertyMap.containsKey("casServerUrlPrefix"), "Required property casServerUrlPrefix not found.");
+
+ final Class validatorClass = ReflectUtils.loadClass(className);
+ final TicketValidator validator = (TicketValidator) ReflectUtils.newInstance(validatorClass, new Object[] {propertyMap.get("casServerUrlPrefix")});
+
+ try {
+ final BeanInfo info = Introspector.getBeanInfo(validatorClass);
+ final Iterator iter = propertyMap.keySet().iterator();
+ while (iter.hasNext()) {
+ final String property = (String) iter.next();
+ if (!"casServerUrlPrefix".equals(property)) {
+ log.debug("Attempting to set TicketValidator property " + property);
+ final String value = (String) propertyMap.get(property);
+ final PropertyDescriptor pd = ReflectUtils.getPropertyDescriptor(info, property);
+ if (pd != null) {
+ ReflectUtils.setProperty(property, convertIfNecessary(pd, value), validator, info);
+ log.debug("Set " + property + "=" + value);
+ } else {
+ log.warn("Cannot find property " + property + " on " + className);
+ }
+ }
+ }
+ } catch (final IntrospectionException e) {
+ throw new RuntimeException("Error getting bean info for " + validatorClass);
+ }
+
+ return validator;
+ }
+
+ /**
+ * Attempts to do simple type conversion from a string value to the type expected
+ * by the given property.
+ *
+ * Currently only conversion to int, long, and boolean are supported.
+ *
+ * @param pd Property descriptor of target property to set.
+ * @param value Property value as a string.
+ * @return Value converted to type expected by property if a conversion strategy exists.
+ */
+ private static Object convertIfNecessary(final PropertyDescriptor pd, final String value) {
+ if (String.class.equals(pd.getPropertyType())) {
+ return value;
+ } else if (boolean.class.equals(pd.getPropertyType())) {
+ return Boolean.valueOf(value);
+ } else if (int.class.equals(pd.getPropertyType())) {
+ return new Integer(value);
+ } else if (long.class.equals(pd.getPropertyType())) {
+ return new Long(value);
+ } else {
+ throw new IllegalArgumentException(
+ "No conversion strategy exists for property " + pd.getName()
+ + " of type " + pd.getPropertyType());
+ }
+ }
+}
diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/jaas/ServiceAndTicketCallbackHandler.java b/cas-client-core/src/main/java/org/jasig/cas/client/jaas/ServiceAndTicketCallbackHandler.java
new file mode 100644
index 0000000..1f906c4
--- /dev/null
+++ b/cas-client-core/src/main/java/org/jasig/cas/client/jaas/ServiceAndTicketCallbackHandler.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2010 The JA-SIG Collaborative. All rights reserved. See license
+ * distributed with this file and available online at
+ * http://www.ja-sig.org/products/cas/overview/license/index.html
+ */
+package org.jasig.cas.client.jaas;
+
+import java.io.IOException;
+
+import javax.security.auth.callback.Callback;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.callback.NameCallback;
+import javax.security.auth.callback.PasswordCallback;
+import javax.security.auth.callback.UnsupportedCallbackException;
+
+/**
+ * Callback handler that provides the CAS service and ticket to a
+ * {@link NameCallback} and {@link PasswordCallback} respectively,
+ * which meets the requirements of the {@link CasLoginModule} JAAS module.
+ *
+ * @author Marvin S. Addison
+ * @version $Revision$
+ * @since 3.1.11
+ *
+ */
+public class ServiceAndTicketCallbackHandler implements CallbackHandler {
+
+ /** CAS service URL */
+ private final String service;
+
+ /** CAS service ticket */
+ private final String ticket;
+
+ /**
+ * Creates a new instance with the given service and ticket.
+ *
+ * @param service CAS service URL.
+ * @param ticket CAS service ticket.
+ */
+ public ServiceAndTicketCallbackHandler(final String service, final String ticket) {
+ this.service = service;
+ this.ticket = ticket;
+ }
+
+ public void handle(final Callback[] callbacks) throws IOException, UnsupportedCallbackException {
+ for (int i = 0; i < callbacks.length; i++) {
+ if (callbacks[i] instanceof NameCallback) {
+ ((NameCallback) callbacks[i]).setName(this.service);
+ } else if (callbacks[i] instanceof PasswordCallback) {
+ ((PasswordCallback) callbacks[i]).setPassword(this.ticket.toCharArray());
+ } else {
+ throw new UnsupportedCallbackException(callbacks[i], "Callback not supported.");
+ }
+ }
+ }
+
+}
diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/util/ReflectUtils.java b/cas-client-core/src/main/java/org/jasig/cas/client/util/ReflectUtils.java
new file mode 100644
index 0000000..0749ac9
--- /dev/null
+++ b/cas-client-core/src/main/java/org/jasig/cas/client/util/ReflectUtils.java
@@ -0,0 +1,141 @@
+/*
+ * Copyright 2010 The JA-SIG Collaborative. All rights reserved. See license
+ * distributed with this file and available online at
+ * http://www.ja-sig.org/products/cas/overview/license/index.html
+ */
+package org.jasig.cas.client.util;
+
+import java.beans.BeanInfo;
+import java.beans.IntrospectionException;
+import java.beans.Introspector;
+import java.beans.PropertyDescriptor;
+import java.lang.reflect.InvocationTargetException;
+
+/**
+ * Helper class with reflection utility methods.
+ *
+ * @author Marvin S. Addison
+ * @version $Revision$
+ * @since 3.1.11
+ *
+ */
+public final class ReflectUtils {
+
+ private ReflectUtils() {
+ // private constructor to prevent instanciation.
+ }
+
+ /**
+ * Attempts to create a class from a String.
+ * @param className the name of the class to create.
+ * @return the class. CANNOT be NULL.
+ * @throws IllegalArgumentException if the className does not exist.
+ */
+ public static Class loadClass(final String className) throws IllegalArgumentException {
+ try {
+ return Class.forName(className);
+ } catch (final ClassNotFoundException e) {
+ throw new IllegalArgumentException(className + " class not found.");
+ }
+ }
+
+
+ /**
+ * Creates a new instance of the given class by passing the given arguments
+ * to the constructor.
+ * @param className Name of class to be created.
+ * @param args Constructor arguments.
+ * @return New instance of given class.
+ */
+ public static Object newInstance(final String className, final Object[] args) {
+ try {
+ return newInstance(Class.forName(className), args);
+ } catch (final ClassNotFoundException e) {
+ throw new IllegalArgumentException(className + " not found");
+ }
+ }
+
+ /**
+ * Creates a new instance of the given class by passing the given arguments
+ * to the constructor.
+ * @param clazz Class of instance to be created.
+ * @param args Constructor arguments.
+ * @return New instance of given class.
+ */
+ public static Object newInstance(final Class clazz, final Object[] args) {
+ final Class[] argClasses = new Class[args.length];
+ for (int i = 0; i < args.length; i++) {
+ argClasses[i] = args[i].getClass();
+ }
+ try {
+ return clazz.getConstructor(argClasses).newInstance(args);
+ } catch (final Exception e) {
+ throw new IllegalArgumentException("Error creating new instance of " + clazz, e);
+ }
+ }
+
+ /**
+ * Gets the property descriptor for the named property on the given class.
+ * @param clazz Class to which property belongs.
+ * @param propertyName Name of property.
+ * @return Property descriptor for given property or null if no property with given
+ * name exists in given class.
+ */
+ public static PropertyDescriptor getPropertyDescriptor(final Class clazz, final String propertyName) {
+ try {
+ return getPropertyDescriptor(Introspector.getBeanInfo(clazz), propertyName);
+ } catch (final IntrospectionException e) {
+ throw new RuntimeException("Failed getting bean info for " + clazz, e);
+ }
+ }
+
+ /**
+ * Gets the property descriptor for the named property from the bean info describing
+ * a particular class to which property belongs.
+ * @param info Bean info describing class to which property belongs.
+ * @param propertyName Name of property.
+ * @return Property descriptor for given property or null if no property with given
+ * name exists.
+ */
+ public static PropertyDescriptor getPropertyDescriptor(final BeanInfo info, final String propertyName) {
+ for (int i = 0; i < info.getPropertyDescriptors().length; i++) {
+ final PropertyDescriptor pd = info.getPropertyDescriptors()[i];
+ if (pd.getName().equals(propertyName)) {
+ return pd;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Sets the given property on the target javabean using bean instrospection.
+ * @param propertyName Property to set.
+ * @param value Property value to set.
+ * @param target Target java bean on which to set property.
+ */
+ public static void setProperty(final String propertyName, final Object value, final Object target) {
+ try {
+ setProperty(propertyName, value, target, Introspector.getBeanInfo(target.getClass()));
+ } catch (final IntrospectionException e) {
+ throw new RuntimeException("Failed getting bean info on target javabean " + target, e);
+ }
+ }
+
+ /**
+ * Sets the given property on the target javabean using bean instrospection.
+ * @param propertyName Property to set.
+ * @param value Property value to set.
+ * @param target Target javabean on which to set property.
+ * @param info BeanInfo describing the target javabean.
+ */
+ public static void setProperty(final String propertyName, final Object value, final Object target, final BeanInfo info) {
+ try {
+ final PropertyDescriptor pd = getPropertyDescriptor(info, propertyName);
+ pd.getWriteMethod().invoke(target, new Object[] { value });
+ } catch (final InvocationTargetException e) {
+ throw new RuntimeException("Error setting property " + propertyName, e.getCause());
+ } catch (final Exception e) {
+ throw new RuntimeException("Error setting property " + propertyName, e);
+ }
+ }
+}
diff --git a/cas-client-core/src/test/java/org/jasig/cas/client/PublicTestHttpServer.java b/cas-client-core/src/test/java/org/jasig/cas/client/PublicTestHttpServer.java
index 1601c28..d5f0a48 100644
--- a/cas-client-core/src/test/java/org/jasig/cas/client/PublicTestHttpServer.java
+++ b/cas-client-core/src/test/java/org/jasig/cas/client/PublicTestHttpServer.java
@@ -1,6 +1,5 @@
package org.jasig.cas.client;
-
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
@@ -16,35 +15,28 @@ public final class PublicTestHttpServer extends Thread {
public byte[] content;
- private byte[] header;
+ private final byte[] header;
- private int port = 80;
+ private final int port;
- public String encoding;
+ public final String encoding;
- private PublicTestHttpServer(String data, String encoding, String MIMEType,
- int port) throws UnsupportedEncodingException {
+ private PublicTestHttpServer(String data, String encoding, String MIMEType, int port) throws UnsupportedEncodingException {
this(data.getBytes(encoding), encoding, MIMEType, port);
}
- private PublicTestHttpServer(byte[] data, String encoding, String MIMEType,
- int port) throws UnsupportedEncodingException {
-
+ private PublicTestHttpServer(byte[] data, String encoding, String MIMEType, int port) throws UnsupportedEncodingException {
this.content = data;
this.port = port;
this.encoding = encoding;
- String header = "HTTP/1.0 200 OK\r\n" + "Server: OneFile 1.0\r\n"
- // + "Content-length: " + this.content.length + "\r\n"
- + "Content-type: " + MIMEType + "\r\n\r\n";
+ String header = "HTTP/1.0 200 OK\r\n" + "Server: OneFile 1.0\r\n" + "Content-type: " + MIMEType + "\r\n\r\n";
this.header = header.getBytes("ASCII");
-
}
public static synchronized PublicTestHttpServer instance() {
if (httpServer == null) {
try {
- httpServer = new PublicTestHttpServer("test", "ASCII",
- "text/plain", 8085);
+ httpServer = new PublicTestHttpServer("test", "ASCII", "text/plain", 8085);
} catch (Exception e) {
throw new RuntimeException(e);
}
@@ -59,19 +51,16 @@ public final class PublicTestHttpServer extends Thread {
try {
ServerSocket server = new ServerSocket(this.port);
- System.out.println("Accepting connections on port "
- + server.getLocalPort());
+ System.out.println("Accepting connections on port " + server.getLocalPort());
while (true) {
Socket connection = null;
try {
connection = server.accept();
- OutputStream out = new BufferedOutputStream(connection
- .getOutputStream());
- InputStream in = new BufferedInputStream(connection
- .getInputStream());
+ final OutputStream out = new BufferedOutputStream(connection.getOutputStream());
+ final InputStream in = new BufferedInputStream(connection.getInputStream());
// read the first line only; that's all we need
- StringBuffer request = new StringBuffer(80);
+ final StringBuffer request = new StringBuffer(80);
while (true) {
int c = in.read();
if (c == '\r' || c == '\n' || c == -1)
@@ -89,7 +78,7 @@ public final class PublicTestHttpServer extends Thread {
out.write(this.content);
out.flush();
} // end try
- catch (IOException e) {
+ catch (final IOException e) {
// nothing to do with this IOException
} finally {
if (connection != null)
@@ -98,7 +87,7 @@ public final class PublicTestHttpServer extends Thread {
} // end while
} // end try
- catch (IOException e) {
+ catch (final IOException e) {
System.err.println("Could not start server. Port Occupied");
}
diff --git a/cas-client-core/src/test/java/org/jasig/cas/client/SerializationTests.java b/cas-client-core/src/test/java/org/jasig/cas/client/SerializationTests.java
new file mode 100644
index 0000000..03d00fb
--- /dev/null
+++ b/cas-client-core/src/test/java/org/jasig/cas/client/SerializationTests.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2010 The JA-SIG Collaborative. All rights reserved. See license
+ * distributed with this file and available online at
+ * http://www.ja-sig.org/products/cas/overview/license/index.html
+ */
+package org.jasig.cas.client;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.util.Collections;
+
+import junit.framework.Assert;
+import junit.framework.TestCase;
+
+import org.jasig.cas.client.authentication.AttributePrincipalImpl;
+import org.jasig.cas.client.authentication.SimpleGroup;
+import org.jasig.cas.client.authentication.SimplePrincipal;
+import org.jasig.cas.client.jaas.AssertionPrincipal;
+import org.jasig.cas.client.validation.AssertionImpl;
+
+/**
+ * Confirms serialization support for classes intended for session storage or
+ * other potential serialization use cases.
+ *
+ * @author Marvin S. Addison
+ * @version $Revision$
+ * @since 3.1.11
+ *
+ */
+public class SerializationTests extends TestCase {
+
+ public void testSerializeDeserialize() throws Exception {
+ final Object[] subjects = getTestSubjects();
+ for (int i = 0; i < subjects.length; i++) {
+ final ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
+ final ObjectOutputStream out = new ObjectOutputStream(byteOut);
+ try {
+ out.writeObject(subjects[i]);
+ } catch (Exception e) {
+ Assert.fail("Serialization failed for " + subjects[i]);
+ } finally {
+ out.close();
+ }
+
+ final ByteArrayInputStream byteIn = new ByteArrayInputStream(byteOut.toByteArray());
+ final ObjectInputStream in = new ObjectInputStream(byteIn);
+ try {
+ Assert.assertEquals(subjects[i], in.readObject());
+ } catch (Exception e) {
+ Assert.fail("Deserialization failed for " + subjects[i]);
+ } finally {
+ in.close();
+ }
+ }
+ }
+
+ private Object[] getTestSubjects() {
+ final SimplePrincipal simplePrincipal = new SimplePrincipal("simple");
+ final SimpleGroup simpleGroup = new SimpleGroup("group");
+ final AttributePrincipalImpl attributePrincipal =
+ new AttributePrincipalImpl("attr", Collections.singletonMap("LOA", "3"));
+ final AssertionPrincipal assertionPrincipal = new AssertionPrincipal(
+ "assertion",
+ new AssertionImpl(attributePrincipal, Collections.singletonMap("authenticationMethod", "username")));
+
+ return new Object[] {
+ simplePrincipal,
+ simpleGroup,
+ attributePrincipal,
+ assertionPrincipal,
+ };
+ }
+}
diff --git a/cas-client-core/src/test/java/org/jasig/cas/client/jaas/CasLoginModuleTests.java b/cas-client-core/src/test/java/org/jasig/cas/client/jaas/CasLoginModuleTests.java
new file mode 100644
index 0000000..298ac69
--- /dev/null
+++ b/cas-client-core/src/test/java/org/jasig/cas/client/jaas/CasLoginModuleTests.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright 2010 The JA-SIG Collaborative. All rights reserved. See license
+ * distributed with this file and available online at
+ * http://www.ja-sig.org/products/cas/overview/license/index.html
+ */
+package org.jasig.cas.client.jaas;
+
+import java.security.Principal;
+import java.security.acl.Group;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+import javax.security.auth.Subject;
+import javax.security.auth.login.LoginException;
+
+import org.jasig.cas.client.PublicTestHttpServer;
+
+import junit.framework.TestCase;
+
+/**
+ * Unit test for {@link CasLoginModule} class.
+ *
+ * @author Marvin S. Addison
+ * @version $Revision$
+ *
+ */
+public class CasLoginModuleTests extends TestCase {
+ private static final String CONST_CAS_SERVER_URL = "http://localhost:8085/";
+
+ private CasLoginModule module;
+
+ private Subject subject;
+
+ /** {@inheritDoc} */
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ module = new CasLoginModule();
+ subject = new Subject();
+ final Map options = new HashMap();
+ options.put("service", "https://service.example.com/webapp");
+ options.put("ticketValidatorClass", "org.jasig.cas.client.validation.Cas20ServiceTicketValidator");
+ options.put("casServerUrlPrefix", CONST_CAS_SERVER_URL);
+ options.put("proxyCallbackUrl", "https://service.example.com/webapp/proxy");
+ options.put("renew", "true");
+ options.put("defaultRoles", "ADMIN");
+ options.put("principalGroupName", "CallerPrincipal");
+ options.put("roleGroupName", "Roles");
+ module.initialize(
+ subject,
+ new ServiceAndTicketCallbackHandler("myService", "myTicket"),
+ new HashMap(),
+ options);
+ }
+
+ /**
+ * Test JAAS login success.
+ */
+ public void testLoginSuccess() throws Exception {
+ final String USERNAME = "username";
+ final String RESPONSE = ""
+ + ""
+ + USERNAME
+ + "";
+ PublicTestHttpServer.instance().content = RESPONSE
+ .getBytes(PublicTestHttpServer.instance().encoding);
+ module.login();
+ module.commit();
+ assertEquals(this.subject.getPrincipals().size(), 3);
+ assertTrue(hasPrincipalName(this.subject, AssertionPrincipal.class, USERNAME));
+ assertTrue(hasPrincipalName(this.subject, Group.class, "CallerPrincipal"));
+ assertTrue(hasPrincipalName(this.subject, Group.class, "Roles"));
+ }
+
+ /**
+ * Test JAAS login failure.
+ */
+ public void testLoginFailure() throws Exception {
+ final String RESPONSE = "Ticket ST-1856339-aA5Yuvrxzpv8Tau1cYQ7 not recognized";
+ PublicTestHttpServer.instance().content = RESPONSE.getBytes(PublicTestHttpServer.instance().encoding);
+ try {
+ module.login();
+ fail("Login did not throw LoginException as expected.");
+ } catch (Exception e) {
+ assertTrue(e instanceof LoginException);
+ }
+ }
+
+ private boolean hasPrincipalName(final Subject subject, final Class principalClass, final String name) {
+ final Set principals = subject.getPrincipals(principalClass);
+ final Iterator iter = principals.iterator();
+ while (iter.hasNext()) {
+ final Principal p = (Principal) iter.next();
+ if (p.getName().equals(name)) {
+ return true;
+ }
+ }
+ return false;
+ }
+}
diff --git a/cas-client-core/src/test/java/org/jasig/cas/client/util/ReflectUtilsTests.java b/cas-client-core/src/test/java/org/jasig/cas/client/util/ReflectUtilsTests.java
new file mode 100644
index 0000000..8ed5bf8
--- /dev/null
+++ b/cas-client-core/src/test/java/org/jasig/cas/client/util/ReflectUtilsTests.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2010 The JA-SIG Collaborative. All rights reserved. See license
+ * distributed with this file and available online at
+ * http://www.ja-sig.org/products/cas/overview/license/index.html
+ */
+package org.jasig.cas.client.util;
+
+import junit.framework.TestCase;
+
+/**
+ * Unit test for {@link ReflectUtils} class.
+ *
+ * @author Marvin S. Addison
+ * @version $Revision$
+ * @since 3.1.11
+ *
+ */
+public class ReflectUtilsTests extends TestCase {
+ /**
+ * Test method for {@link org.jasig.cas.client.util.ReflectUtils#newInstance(java.lang.String, java.lang.Object[])}.
+ */
+ public void testNewInstanceStringObjectArray() {
+ final Object result = ReflectUtils.newInstance(
+ "org.jasig.cas.client.validation.Cas10TicketValidator",
+ new Object[] {"https://localhost/cas"} );
+ assertNotNull(result);
+ }
+
+ /**
+ * Test method for {@link org.jasig.cas.client.util.ReflectUtils#setProperty(java.lang.String, java.lang.Object, java.lang.Object)}.
+ */
+ public void testSetPropertyStringObjectObject() {
+ final TestBean bean = new TestBean();
+
+ ReflectUtils.setProperty("count", new Integer(30000), bean);
+ assertEquals(30000, bean.getCount());
+
+ ReflectUtils.setProperty("name", "bob", bean);
+ assertEquals("bob", bean.getName());
+
+ ReflectUtils.setProperty("flag", Boolean.TRUE, bean);
+ assertTrue(bean.isFlag());
+ }
+
+ static class TestBean {
+ private int count;
+ private boolean flag;
+ private String name;
+
+ /**
+ * @return the count
+ */
+ public int getCount() {
+ return count;
+ }
+
+ /**
+ * @param count the count to set
+ */
+ public void setCount(int count) {
+ this.count = count;
+ }
+
+ /**
+ * @return the name
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * @param name the name to set
+ */
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ /**
+ * @return the flag
+ */
+ public boolean isFlag() {
+ return flag;
+ }
+
+ /**
+ * @param flag the flag to set
+ */
+ public void setFlag(boolean flag) {
+ this.flag = flag;
+ }
+
+ }
+}
diff --git a/cas-client-integration-atlassian/pom.xml b/cas-client-integration-atlassian/pom.xml
index 344d933..9a7161c 100644
--- a/cas-client-integration-atlassian/pom.xml
+++ b/cas-client-integration-atlassian/pom.xml
@@ -2,7 +2,7 @@
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
org.jasig.cas
- 3.1.10
+ 3.1.11-SNAPSHOTcas-client4.0.0
@@ -10,50 +10,7 @@
cas-client-integration-atlassianjarJA-SIG CAS Client for Java - Atlassian Integration
-
- src/main/java
- src/test/java
-
-
- src/test/resources
- false
-
-
-
-
- org.apache.maven.plugins
- maven-compiler-plugin
-
- 1.4
- 1.4
-
-
-
- org.apache.maven.plugins
- maven-surefire-plugin
-
-
- **/*Tests*
-
-
-
-
- org.apache.maven.plugins
- maven-clover-plugin
-
- ${basedir}/src/test/clover/clover.license
-
-
-
- pre-site
-
- instrument
-
-
-
-
-
-
+
atlassian-seraph
@@ -554,7 +511,8 @@
-
+
+
diff --git a/cas-client-integration-jboss/pom.xml b/cas-client-integration-jboss/pom.xml
new file mode 100644
index 0000000..2f607ee
--- /dev/null
+++ b/cas-client-integration-jboss/pom.xml
@@ -0,0 +1,42 @@
+
+
+ org.jasig.cas
+ 3.1.11-SNAPSHOT
+ cas-client
+
+ 4.0.0
+ org.jasig.cas
+ cas-client-integration-jboss
+ jar
+ JA-SIG CAS Client for Java - JBoss Integration
+
+
+
+ org.jasig.cas
+ cas-client-core
+ ${project.version}
+ compile
+
+
+ org.jboss.jbossas
+ jboss-as-tomcat
+ ${jboss.version}
+ provided
+
+
+
+
+
+
+ 5.1.0.GA
+
+
diff --git a/cas-client-integration-jboss/src/main/java/org/jasig/cas/client/jboss/authentication/WebAuthenticationFilter.java b/cas-client-integration-jboss/src/main/java/org/jasig/cas/client/jboss/authentication/WebAuthenticationFilter.java
new file mode 100644
index 0000000..9d8fe30
--- /dev/null
+++ b/cas-client-integration-jboss/src/main/java/org/jasig/cas/client/jboss/authentication/WebAuthenticationFilter.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2010 The JA-SIG Collaborative. All rights reserved. See license
+ * distributed with this file and available online at
+ * http://www.ja-sig.org/products/cas/overview/license/index.html
+ */
+package org.jasig.cas.client.jboss.authentication;
+
+import java.io.IOException;
+import java.security.GeneralSecurityException;
+
+import javax.servlet.FilterChain;
+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.jaas.AssertionPrincipal;
+import org.jasig.cas.client.util.AbstractCasFilter;
+import org.jasig.cas.client.util.CommonUtils;
+
+import org.jboss.web.tomcat.security.login.WebAuthentication;
+
+/**
+ * This servlet filter performs a programmatic JAAS login using the JBoss
+ * WebAuthentication class.
+ * The filter executes when it receives a CAS ticket and expects the
+ * {@link org.jasig.cas.client.jaas.CasLoginModule} JAAS module to perform the CAS
+ * ticket validation in order to produce an {@link AssertionPrincipal} from which
+ * the CAS assertion is obtained and inserted into the session to enable SSO.
+ *
+ * If a service init-param is specified for this filter, it supersedes
+ * the service defined for the {@link org.jasig.cas.client.jaas.CasLoginModule}.
+ *
+ * @author Daniel Fisher
+ * @author Marvin S. Addison
+ * @version $Revision$
+ * @since 3.1.11
+ */
+public final class WebAuthenticationFilter extends AbstractCasFilter {
+
+ public void doFilter(final ServletRequest servletRequest, final ServletResponse servletResponse, final FilterChain chain) throws IOException, ServletException {
+ final HttpServletRequest request = (HttpServletRequest) servletRequest;
+ final HttpServletResponse response = (HttpServletResponse) servletResponse;
+ final HttpSession session = request.getSession();
+ final String ticket = CommonUtils.safeGetParameter(request, getArtifactParameterName());
+
+ if (session != null && session.getAttribute(CONST_CAS_ASSERTION) == null && ticket != null) {
+ try {
+ final String service = constructServiceUrl(request, response);
+ log.debug("Attempting CAS ticket validation with service=" + service + " and ticket=" + ticket);
+ if (!new WebAuthentication().login(service, ticket)) {
+ log.debug("JBoss Web authentication failed.");
+ throw new GeneralSecurityException("JBoss Web authentication failed.");
+ }
+ if (request.getUserPrincipal() instanceof AssertionPrincipal) {
+ final AssertionPrincipal principal = (AssertionPrincipal) request.getUserPrincipal();
+ log.debug("Installing CAS assertion into session.");
+ session.setAttribute(CONST_CAS_ASSERTION, principal.getAssertion());
+ } else {
+ log.debug("Aborting -- principal is not of type AssertionPrincipal");
+ throw new GeneralSecurityException("JBoss Web authentication did not produce CAS AssertionPrincipal.");
+ }
+ } catch (final GeneralSecurityException e) {
+ response.sendError(HttpServletResponse.SC_FORBIDDEN, e.getMessage());
+ }
+ } else if (session != null && request.getUserPrincipal() == null) {
+ // There is evidence that in some cases the principal can disappear
+ // in JBoss despite a valid session.
+ // This block forces consistency between principal and assertion.
+ log.info("User principal not found. Removing CAS assertion from session to force reauthentication.");
+ session.removeAttribute(CONST_CAS_ASSERTION);
+ }
+ chain.doFilter(request, response);
+ }
+}
diff --git a/cas-client-support-distributed-ehcache/pom.xml b/cas-client-support-distributed-ehcache/pom.xml
index 8526939..4f0aa1a 100644
--- a/cas-client-support-distributed-ehcache/pom.xml
+++ b/cas-client-support-distributed-ehcache/pom.xml
@@ -5,7 +5,7 @@
cas-clientorg.jasig.cas
- 3.1.10
+ 3.1.11-SNAPSHOT4.0.0Jasig CAS Client for Java - Distributed Proxy Storage Support: EhCache
diff --git a/cas-client-support-distributed-memcached/pom.xml b/cas-client-support-distributed-memcached/pom.xml
index d4dc705..6d3c4dd 100644
--- a/cas-client-support-distributed-memcached/pom.xml
+++ b/cas-client-support-distributed-memcached/pom.xml
@@ -5,7 +5,7 @@
cas-clientorg.jasig.cas
- 3.1.10
+ 3.1.11-SNAPSHOT4.0.0
@@ -27,7 +27,7 @@
spymemcached
- 2.4.2
+ 2.5jarprovided
diff --git a/pom.xml b/pom.xml
index 9505754..4e7908f 100644
--- a/pom.xml
+++ b/pom.xml
@@ -1,7 +1,7 @@
4.0.0org.jasig.cas
- 3.1.10
+ 3.1.11-SNAPSHOTcas-clientpomJA-SIG CAS Client for Java
@@ -20,28 +20,7 @@
https://www.ja-sig.org/svn/cas-clients/java-client2006
-
-
- CAS Community Discussion List
- http://tp.its.yale.edu/mailman/listinfo/cas
- http://tp.its.yale.edu/mailman/listinfo/cas
- cas@tp.its.yale.edu
- http://tp.its.yale.edu/pipermail/cas/
-
- http://news.gmane.org/gmane.comp.java.jasig.cas.user
-
-
-
- CAS Developers Discussion List
- http://tp.its.yale.edu/mailman/listinfo/cas-dev
- http://tp.its.yale.edu/mailman/listinfo/cas-dev
- cas-dev@tp.its.yale.edu
- http://tp.its.yale.edu/pipermail/cas-dev/
-
- http://news.gmane.org/gmane.comp.java.jasig.cas.devel
-
-
-
+
battags
@@ -66,7 +45,7 @@
JA-SIG
- http://www.ja-sig.org
+ http://www.jasig.org
@@ -88,6 +67,30 @@
1.4
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+
+
+ **/*Tests*
+
+
+
+
+ org.apache.maven.plugins
+ maven-clover-plugin
+
+ ${basedir}/src/test/clover/clover.license
+
+
+
+ pre-site
+
+ instrument
+
+
+
+
@@ -129,6 +132,7 @@
cas-client-corecas-client-integration-atlassian
+ cas-client-integration-jbosscas-client-support-distributed-ehcachecas-client-support-distributed-memcached