parent
8de11b4830
commit
863df03211
|
|
@ -0,0 +1,64 @@
|
|||
<assembly>
|
||||
<id>release</id>
|
||||
<formats>
|
||||
<format>zip</format>
|
||||
<format>tar.gz</format>
|
||||
</formats>
|
||||
<includeBaseDirectory>true</includeBaseDirectory>
|
||||
<fileSets>
|
||||
<fileSet>
|
||||
<lineEnding>unix</lineEnding>
|
||||
<useDefaultExcludes>true</useDefaultExcludes>
|
||||
<useStrictFiltering>false</useStrictFiltering>
|
||||
<directory>${basedir}</directory>
|
||||
<outputDirectory></outputDirectory>
|
||||
<includes>
|
||||
<include>*.xml</include>
|
||||
<include>*.txt</include>
|
||||
</includes>
|
||||
</fileSet>
|
||||
</fileSets>
|
||||
<moduleSets>
|
||||
<moduleSet>
|
||||
<includes></includes>
|
||||
<sources>
|
||||
<fileSets>
|
||||
<fileSet>
|
||||
<directory>src</directory>
|
||||
<outputDirectory>src</outputDirectory>
|
||||
<lineEnding>unix</lineEnding>
|
||||
<useDefaultExcludes>true</useDefaultExcludes>
|
||||
</fileSet>
|
||||
|
||||
<fileSet>
|
||||
<lineEnding>unix</lineEnding>
|
||||
<useDefaultExcludes>true</useDefaultExcludes>
|
||||
<includes>
|
||||
<include>*.xml</include>
|
||||
</includes>
|
||||
</fileSet>
|
||||
|
||||
<fileSet>
|
||||
<lineEnding>unix</lineEnding>
|
||||
<directory>target/site/apidocs/</directory>
|
||||
<useDefaultExcludes>true</useDefaultExcludes>
|
||||
<outputDirectory>docs</outputDirectory>
|
||||
<includes>
|
||||
<include>**/*</include>
|
||||
</includes>
|
||||
</fileSet>
|
||||
</fileSets>
|
||||
|
||||
<includeModuleDirectory>true</includeModuleDirectory>
|
||||
<useDefaultExcludes>true</useDefaultExcludes>
|
||||
</sources>
|
||||
<binaries>
|
||||
<outputDirectory>modules</outputDirectory>
|
||||
<includeDependencies>true</includeDependencies>
|
||||
<unpack>false</unpack>
|
||||
<useDefaultExcludes>true</useDefaultExcludes>
|
||||
<includes />
|
||||
</binaries>
|
||||
</moduleSet>
|
||||
</moduleSets>
|
||||
</assembly>
|
||||
|
|
@ -0,0 +1,95 @@
|
|||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<parent>
|
||||
<groupId>org.jasig.cas</groupId>
|
||||
<version>3.1-RC3</version>
|
||||
<artifactId>cas-client</artifactId>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.jasig.cas</groupId>
|
||||
<artifactId>cas-client-core</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<name>JA-SIG CAS Client for Java - Core</name>
|
||||
<build>
|
||||
<sourceDirectory>src/main/java</sourceDirectory>
|
||||
<testSourceDirectory>src/test/java</testSourceDirectory>
|
||||
<testResources>
|
||||
<testResource>
|
||||
<directory>src/test/resources</directory>
|
||||
<filtering>false</filtering>
|
||||
</testResource>
|
||||
</testResources>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<source>1.4</source>
|
||||
<target>1.4</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<configuration>
|
||||
<includes>
|
||||
<include>**/*Tests*</include>
|
||||
</includes>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-clover-plugin</artifactId>
|
||||
<configuration>
|
||||
<licenseLocation>${basedir}/src/test/clover/clover.license</licenseLocation>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>pre-site</phase>
|
||||
<goals>
|
||||
<goal>instrument</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>xml-security</groupId>
|
||||
<artifactId>xmlsec</artifactId>
|
||||
<version>1.3.0</version>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.opensaml</groupId>
|
||||
<artifactId>opensaml</artifactId>
|
||||
<version>1.1b</version>
|
||||
<type>jar</type>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-beans</artifactId>
|
||||
<version>2.5.1</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-core</artifactId>
|
||||
<version>2.5.1</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-context</artifactId>
|
||||
<version>2.5.1</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
package org.jasig.cas.client.authentication;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.security.Principal;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Extension to the standard Java Principal that includes a way to retrieve proxy tickets for a particular user
|
||||
* and attributes.
|
||||
* <p>
|
||||
* Developer's who don't want their code tied to CAS merely need to work with the Java Principal then. Working with
|
||||
* the CAS-specific features requires knowledge of the AttributePrincipal class.
|
||||
*
|
||||
* @author Scott Battaglia
|
||||
* @version $Revision$ $Date$
|
||||
* @since 3.1
|
||||
*/
|
||||
public interface AttributePrincipal extends Principal, Serializable {
|
||||
|
||||
/**
|
||||
* Retrieves a CAS proxy ticket for this specific principal.
|
||||
*
|
||||
* @param service the service we wish to proxy this user to.
|
||||
* @return a String representing the proxy ticket.
|
||||
*/
|
||||
String getProxyTicketFor(String service);
|
||||
|
||||
/**
|
||||
* The Map of key/value pairs associated with this principal.
|
||||
* @return the map of key/value pairs associated with this principal.
|
||||
*/
|
||||
Map getAttributes();
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,95 @@
|
|||
package org.jasig.cas.client.authentication;
|
||||
|
||||
import org.jasig.cas.client.proxy.ProxyRetriever;
|
||||
import org.jasig.cas.client.util.CommonUtils;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Concrete implementation of the AttributePrincipal interface.
|
||||
*
|
||||
* @author Scott Battaglia
|
||||
* @version $Revision$ $Date$
|
||||
* @since 3.1
|
||||
*/
|
||||
public class AttributePrincipalImpl implements AttributePrincipal {
|
||||
|
||||
/** Unique Id for Serialization */
|
||||
private static final long serialVersionUID = -8810123156070148535L;
|
||||
|
||||
/** The unique identifier for this principal. */
|
||||
private final String name;
|
||||
|
||||
/** Map of key/value pairs about this principal. */
|
||||
private final Map attributes;
|
||||
|
||||
/** The CAS 2 ticket used to retrieve a proxy ticket. */
|
||||
private final String proxyGrantingTicket;
|
||||
|
||||
/** The method to retrieve a proxy ticket from a CAS server. */
|
||||
private final ProxyRetriever proxyRetriever;
|
||||
|
||||
/**
|
||||
* Constructs a new principal with an empty map of attributes.
|
||||
*
|
||||
* @param name the unique identifier for the principal.
|
||||
*/
|
||||
public AttributePrincipalImpl(final String name) {
|
||||
this(name, Collections.EMPTY_MAP);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new principal with the supplied name and attributes.
|
||||
*
|
||||
* @param name the unique identifier for the principal.
|
||||
* @param attributes the key/value pairs for this principal.
|
||||
*/
|
||||
public AttributePrincipalImpl(final String name, final Map attributes) {
|
||||
this(name, attributes, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new principal with the supplied name and the proxying capabilities.
|
||||
*
|
||||
* @param name the unique identifier for the principal.
|
||||
* @param proxyGrantingTicket the ticket associated with this principal.
|
||||
* @param proxyRetriever the ProxyRetriever implementation to call back to the CAS server.
|
||||
*/
|
||||
public AttributePrincipalImpl(final String name, final String proxyGrantingTicket, final ProxyRetriever proxyRetriever) {
|
||||
this(name, Collections.EMPTY_MAP, proxyGrantingTicket, proxyRetriever);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new principal witht he supplied name, attributes, and proxying capabilities.
|
||||
*
|
||||
* @param name the unique identifier for the principal.
|
||||
* @param attributes the key/value pairs for this principal.
|
||||
* @param proxyGrantingTicket the ticket associated with this principal.
|
||||
* @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;
|
||||
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.");
|
||||
}
|
||||
|
||||
public Map getAttributes() {
|
||||
return this.attributes;
|
||||
}
|
||||
|
||||
public String getProxyTicketFor(String service) {
|
||||
if (proxyGrantingTicket != null) {
|
||||
return this.proxyRetriever.getProxyTicketIdFor(this.proxyGrantingTicket, service);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,117 @@
|
|||
/*
|
||||
* Copyright 2007 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 org.jasig.cas.client.util.AbstractCasFilter;
|
||||
import org.jasig.cas.client.util.CommonUtils;
|
||||
import org.jasig.cas.client.validation.Assertion;
|
||||
|
||||
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 java.io.IOException;
|
||||
|
||||
/**
|
||||
* Filter implementation to intercept all requests and attempt to authenticate
|
||||
* the user by redirecting them to CAS (unless the user has a ticket).
|
||||
* <p>
|
||||
* This filter allows you to specify the following parameters (at either the context-level or the filter-level):
|
||||
* <ul>
|
||||
* <li><code>casServerLoginUrl</code> - the url to log into CAS, i.e. https://cas.rutgers.edu/login</li>
|
||||
* <li><code>renew</code> - true/false on whether to use renew or not.</li>
|
||||
* <li><code>gateway</code> - true/false on whether to use gateway or not.</li>
|
||||
* </ul>
|
||||
*
|
||||
* <p>Please see AbstractCasFilter for additional properties.</p>
|
||||
*
|
||||
* @author Scott Battaglia
|
||||
* @version $Revision: 11768 $ $Date: 2007-02-07 15:44:16 -0500 (Wed, 07 Feb 2007) $
|
||||
* @since 3.0
|
||||
*/
|
||||
public class AuthenticationFilter extends AbstractCasFilter {
|
||||
|
||||
public static final String CONST_CAS_GATEWAY = "_const_cas_gateway_";
|
||||
|
||||
/**
|
||||
* The URL to the CAS Server login.
|
||||
*/
|
||||
private String casServerLoginUrl;
|
||||
|
||||
/**
|
||||
* Whether to send the renew request or not.
|
||||
*/
|
||||
private boolean renew = false;
|
||||
|
||||
/**
|
||||
* Whether to send the gateway request or not.
|
||||
*/
|
||||
private boolean gateway = false;
|
||||
|
||||
protected void initInternal(final FilterConfig filterConfig) throws ServletException {
|
||||
super.initInternal(filterConfig);
|
||||
setCasServerLoginUrl(getPropertyFromInitParams(filterConfig, "casServerLoginUrl", null));
|
||||
setRenew(Boolean.parseBoolean(getPropertyFromInitParams(filterConfig, "renew", "false")));
|
||||
setGateway(Boolean.parseBoolean(getPropertyFromInitParams(filterConfig, "gateway", "false")));
|
||||
}
|
||||
|
||||
public void init() {
|
||||
super.init();
|
||||
CommonUtils.assertNotNull(this.casServerLoginUrl, "casServerLoginUrl cannot be null.");
|
||||
}
|
||||
|
||||
public final void doFilter(final ServletRequest servletRequest, final ServletResponse servletResponse, final FilterChain filterChain) throws IOException, ServletException {
|
||||
final HttpServletRequest request = (HttpServletRequest) servletRequest;
|
||||
final HttpServletResponse response = (HttpServletResponse) servletResponse;
|
||||
final HttpSession session = request.getSession(false);
|
||||
final String ticket = request.getParameter(getArtifactParameterName());
|
||||
final Assertion assertion = session != null ? (Assertion) session
|
||||
.getAttribute(CONST_CAS_ASSERTION) : null;
|
||||
final boolean wasGatewayed = session != null
|
||||
&& session.getAttribute(CONST_CAS_GATEWAY) != null;
|
||||
|
||||
if (CommonUtils.isBlank(ticket) && assertion == null && !wasGatewayed) {
|
||||
log.debug("no ticket and no assertion found");
|
||||
if (this.gateway) {
|
||||
log.debug("setting gateway attribute in session");
|
||||
request.getSession(true).setAttribute(CONST_CAS_GATEWAY, "yes");
|
||||
}
|
||||
|
||||
final String serviceUrl = constructServiceUrl(request, response);
|
||||
final String urlToRedirectTo = CommonUtils.constructRedirectUrl(this.casServerLoginUrl, getServiceParameterName(), serviceUrl, this.renew, this.gateway);
|
||||
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("redirecting to \"" + urlToRedirectTo + "\"");
|
||||
}
|
||||
|
||||
response.sendRedirect(urlToRedirectTo);
|
||||
return;
|
||||
}
|
||||
|
||||
if (session != null) {
|
||||
log.debug("removing gateway attribute from session");
|
||||
session.setAttribute(CONST_CAS_GATEWAY, null);
|
||||
}
|
||||
|
||||
filterChain.doFilter(request, response);
|
||||
}
|
||||
|
||||
public final void setRenew(final boolean renew) {
|
||||
this.renew = renew;
|
||||
}
|
||||
|
||||
public final void setGateway(final boolean gateway) {
|
||||
this.gateway = gateway;
|
||||
}
|
||||
|
||||
public final void setCasServerLoginUrl(final String casServerLoginUrl) {
|
||||
this.casServerLoginUrl = casServerLoginUrl;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,106 @@
|
|||
/*
|
||||
* Copyright 2007 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.proxy;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.jasig.cas.client.util.CommonUtils;
|
||||
import org.jasig.cas.client.util.XmlUtils;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.net.URLEncoder;
|
||||
|
||||
/**
|
||||
* Implementation of a ProxyRetriever that follows the CAS 2.0 specification.
|
||||
* For more information on the CAS 2.0 specification, please see the <a
|
||||
* href="http://www.ja-sig.org/products/cas/overview/protocol/index.html">specification
|
||||
* document</a>.
|
||||
* <p/>
|
||||
* In general, this class will make a call to the CAS server with some specified
|
||||
* parameters and receive an XML response to parse.
|
||||
*
|
||||
* @author Scott Battaglia
|
||||
* @version $Revision: 11729 $ $Date: 2007-09-26 14:22:30 -0400 (Tue, 26 Sep 2007) $
|
||||
* @since 3.0
|
||||
*/
|
||||
public final class Cas20ProxyRetriever implements ProxyRetriever {
|
||||
|
||||
/**
|
||||
* Instance of Commons Logging.
|
||||
*/
|
||||
private final Log log = LogFactory.getLog(this.getClass());
|
||||
|
||||
/**
|
||||
* Url to CAS server.
|
||||
*/
|
||||
private final String casServerUrl;
|
||||
|
||||
/**
|
||||
* Main Constructor.
|
||||
*
|
||||
* @param casServerUrl the URL to the CAS server (i.e. http://localhost/cas/)
|
||||
*/
|
||||
public Cas20ProxyRetriever(final String casServerUrl) {
|
||||
CommonUtils.assertNotNull(casServerUrl,
|
||||
"casServerUrl cannot be null.");
|
||||
this.casServerUrl = casServerUrl;
|
||||
}
|
||||
|
||||
public String getProxyTicketIdFor(final String proxyGrantingTicketId,
|
||||
final String targetService) {
|
||||
|
||||
final String url = constructUrl(proxyGrantingTicketId, targetService);
|
||||
HttpURLConnection conn = null;
|
||||
try {
|
||||
final URL constructedUrl = new URL(url);
|
||||
conn = (HttpURLConnection) constructedUrl.openConnection();
|
||||
|
||||
final BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
|
||||
|
||||
String line;
|
||||
final StringBuffer stringBuffer = new StringBuffer(255);
|
||||
final String response;
|
||||
|
||||
synchronized (stringBuffer) {
|
||||
while ((line = in.readLine()) != null) {
|
||||
stringBuffer.append(line);
|
||||
}
|
||||
response = stringBuffer.toString();
|
||||
}
|
||||
|
||||
final String error = XmlUtils.getTextForElement(response,
|
||||
"proxyFailure");
|
||||
|
||||
if (CommonUtils.isNotEmpty(error)) {
|
||||
log.debug(error);
|
||||
return null;
|
||||
}
|
||||
|
||||
return XmlUtils.getTextForElement(response, "proxyTicket");
|
||||
} catch (final Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
} finally {
|
||||
if (conn != null) {
|
||||
conn.disconnect();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String constructUrl(final String proxyGrantingTicketId,
|
||||
final String targetService) {
|
||||
try {
|
||||
return this.casServerUrl + "proxy" + "?pgt="
|
||||
+ proxyGrantingTicketId + "&targetService="
|
||||
+ URLEncoder.encode(targetService, "UTF-8");
|
||||
} catch (final UnsupportedEncodingException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* Copyright 2007 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.proxy;
|
||||
|
||||
/**
|
||||
* Interface for the storage and retrieval of ProxyGrantingTicketIds by mapping
|
||||
* them to a specific ProxyGrantingTicketIou.
|
||||
*
|
||||
* @author Scott Battaglia
|
||||
* @version $Revision: 11729 $ $Date: 2007-09-26 14:22:30 -0400 (Tue, 26 Sep 2007) $
|
||||
* @since 3.0
|
||||
*/
|
||||
public interface ProxyGrantingTicketStorage {
|
||||
|
||||
/**
|
||||
* Method to save the ProxyGrantingTicket to the backing storage facility.
|
||||
*
|
||||
* @param proxyGrantingTicketIou used as the key
|
||||
* @param proxyGrantingTicket used as the value
|
||||
*/
|
||||
public void save(String proxyGrantingTicketIou, String proxyGrantingTicket);
|
||||
|
||||
/**
|
||||
* Method to retrieve a ProxyGrantingTicket based on the
|
||||
* ProxyGrantingTicketIou. Note that implementations are not guaranteed to
|
||||
* return the same result if retrieve is called twice with the same
|
||||
* proxyGrantingTicketIou.
|
||||
*
|
||||
* @param proxyGrantingTicketIou used as the key
|
||||
* @return the ProxyGrantingTicket Id or null if it can't be found
|
||||
*/
|
||||
public String retrieve(String proxyGrantingTicketIou);
|
||||
}
|
||||
|
|
@ -0,0 +1,145 @@
|
|||
/*
|
||||
* Copyright 2007 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.proxy;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Implementation of {@link ProxyGrantingTicketStorage} that is backed by a
|
||||
* HashMap that keeps a ProxyGrantingTicket for a specified amount of time.
|
||||
* <p/>
|
||||
* A cleanup thread is run periodically to clean out the HashMap.
|
||||
*
|
||||
* @author Scott Battaglia
|
||||
* @version $Revision: 11729 $ $Date: 2007-09-26 14:22:30 -0400 (Tue, 26 Sep 2007) $
|
||||
* @since 3.0
|
||||
*/
|
||||
public final class ProxyGrantingTicketStorageImpl implements
|
||||
ProxyGrantingTicketStorage {
|
||||
|
||||
/**
|
||||
* Default timeout in milliseconds.
|
||||
*/
|
||||
private static final long DEFAULT_TIMEOUT = 60000;
|
||||
|
||||
/**
|
||||
* Map that stores the PGTIOU to PGT mappings.
|
||||
*/
|
||||
private final Map cache = new HashMap();
|
||||
|
||||
/**
|
||||
* Constructor set the timeout to the default value.
|
||||
*/
|
||||
public ProxyGrantingTicketStorageImpl() {
|
||||
this(DEFAULT_TIMEOUT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the amount of time to hold on to a ProxyGrantingTicket if its never
|
||||
* been retrieved.
|
||||
*
|
||||
* @param timeout the time to hold on to the ProxyGrantingTicket
|
||||
*/
|
||||
public ProxyGrantingTicketStorageImpl(final long timeout) {
|
||||
final Thread thread = new ProxyGrantingTicketCleanupThread(
|
||||
timeout, this.cache);
|
||||
thread.setDaemon(true);
|
||||
thread.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* NOTE: you can only retrieve a ProxyGrantingTicket once with this method.
|
||||
* Its removed after retrieval.
|
||||
*/
|
||||
public String retrieve(final String proxyGrantingTicketIou) {
|
||||
final ProxyGrantingTicketHolder holder = (ProxyGrantingTicketHolder) this.cache
|
||||
.get(proxyGrantingTicketIou);
|
||||
|
||||
if (holder == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
this.cache.remove(holder);
|
||||
|
||||
return holder.getProxyGrantingTicket();
|
||||
}
|
||||
|
||||
public void save(final String proxyGrantingTicketIou,
|
||||
final String proxyGrantingTicket) {
|
||||
final ProxyGrantingTicketHolder holder = new ProxyGrantingTicketHolder(
|
||||
proxyGrantingTicket);
|
||||
|
||||
this.cache.put(proxyGrantingTicketIou, holder);
|
||||
}
|
||||
|
||||
private final class ProxyGrantingTicketHolder {
|
||||
|
||||
private final String proxyGrantingTicket;
|
||||
|
||||
private final long timeInserted;
|
||||
|
||||
protected ProxyGrantingTicketHolder(final String proxyGrantingTicket) {
|
||||
this.proxyGrantingTicket = proxyGrantingTicket;
|
||||
this.timeInserted = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
public String getProxyGrantingTicket() {
|
||||
return this.proxyGrantingTicket;
|
||||
}
|
||||
|
||||
final boolean isExpired(final long timeout) {
|
||||
return System.currentTimeMillis() - this.timeInserted > timeout;
|
||||
}
|
||||
}
|
||||
|
||||
private final class ProxyGrantingTicketCleanupThread extends Thread {
|
||||
|
||||
private final long timeout;
|
||||
|
||||
private final Map cache;
|
||||
|
||||
public ProxyGrantingTicketCleanupThread(final long timeout,
|
||||
final Map cache) {
|
||||
this.timeout = timeout;
|
||||
this.cache = cache;
|
||||
}
|
||||
|
||||
public void run() {
|
||||
|
||||
while (true) {
|
||||
try {
|
||||
Thread.sleep(this.timeout);
|
||||
} catch (final InterruptedException e) {
|
||||
// nothing to do
|
||||
}
|
||||
|
||||
final List itemsToRemove = new ArrayList();
|
||||
|
||||
synchronized (this.cache) {
|
||||
for (final Iterator iter = this.cache.keySet().iterator(); iter
|
||||
.hasNext();) {
|
||||
final Object key = iter.next();
|
||||
final ProxyGrantingTicketHolder holder = (ProxyGrantingTicketHolder) this.cache
|
||||
.get(key);
|
||||
|
||||
if (holder.isExpired(this.timeout)) {
|
||||
itemsToRemove.add(key);
|
||||
}
|
||||
}
|
||||
|
||||
for (final Iterator iter = itemsToRemove.iterator(); iter
|
||||
.hasNext();) {
|
||||
this.cache.remove(iter.next());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* Copyright 2007 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.proxy;
|
||||
|
||||
/**
|
||||
* Interface to abstract the retrieval of a proxy ticket to make the
|
||||
* implementation a black box to the client.
|
||||
*
|
||||
* @author Scott Battaglia
|
||||
* @version $Revision: 11729 $ $Date: 2007-09-26 14:22:30 -0400 (Tue, 26 Sep 2007) $
|
||||
* @since 3.0
|
||||
*/
|
||||
public interface ProxyRetriever {
|
||||
|
||||
/**
|
||||
* Retrieves a proxy ticket for a specific targetService.
|
||||
*
|
||||
* @param proxyGrantingTicketId the ProxyGrantingTicketId
|
||||
* @param targetService the service we want to proxy.
|
||||
* @return the ProxyTicket Id if Granted, null otherwise.
|
||||
*/
|
||||
String getProxyTicketIdFor(String proxyGrantingTicketId,
|
||||
String targetService);
|
||||
}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
<html>
|
||||
<body>
|
||||
<p>The proxy package includes a servlet to act as a proxy receptor,
|
||||
an interface for ProxyGrantingTicketStorage and an abstraction for
|
||||
retrieving proxy tickets.</p>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* Copyright 2007 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.session;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.http.HttpSession;
|
||||
|
||||
/**
|
||||
* HashMap backed implementation of SessionMappingStorage.
|
||||
*
|
||||
* @author Scott Battaglia
|
||||
* @version $Revision$ $Date$
|
||||
* @since 3.1
|
||||
*
|
||||
*/
|
||||
public final class HashMapBackedSessionMappingStorage implements
|
||||
SessionMappingStorage {
|
||||
|
||||
/**
|
||||
* Maps the ID from the CAS server to the Session.
|
||||
*/
|
||||
private final Map MANAGED_SESSIONS = new HashMap();
|
||||
|
||||
/**
|
||||
* Maps the Session ID to the key from the CAS Server.
|
||||
*/
|
||||
private final Map ID_TO_SESSION_KEY_MAPPING = new HashMap();
|
||||
|
||||
public void addSessionById(String mappingId, HttpSession session) {
|
||||
ID_TO_SESSION_KEY_MAPPING.put(session.getId(), mappingId);
|
||||
MANAGED_SESSIONS.put(mappingId, session);
|
||||
|
||||
}
|
||||
|
||||
public void removeBySessionById(String sessionId) {
|
||||
final String key = (String) ID_TO_SESSION_KEY_MAPPING.get(sessionId);
|
||||
MANAGED_SESSIONS.remove(key);
|
||||
ID_TO_SESSION_KEY_MAPPING.remove(sessionId);
|
||||
}
|
||||
|
||||
public HttpSession removeSessionByMappingId(String mappingId) {
|
||||
final HttpSession session = (HttpSession) MANAGED_SESSIONS.get(mappingId);
|
||||
|
||||
if (session != null) {
|
||||
removeBySessionById(session.getId());
|
||||
}
|
||||
|
||||
return session;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* Copyright 2007 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.session;
|
||||
|
||||
import javax.servlet.http.HttpSession;
|
||||
|
||||
/**
|
||||
* Stores the mapping between sessions and keys to be retrieved later.
|
||||
*
|
||||
* @author Scott Battaglia
|
||||
* @version $Revision$ $Date$
|
||||
* @since 3.1
|
||||
*
|
||||
*/
|
||||
public interface SessionMappingStorage {
|
||||
|
||||
/**
|
||||
* Remove the HttpSession based on the mappingId.
|
||||
*
|
||||
* @param mappingId the id the session is keyed under.
|
||||
* @return the HttpSession if it exists.
|
||||
*/
|
||||
HttpSession removeSessionByMappingId(String mappingId);
|
||||
|
||||
/**
|
||||
* Remove a session by its Id.
|
||||
* @param sessionId the id of the session.
|
||||
*/
|
||||
void removeBySessionById(String sessionId);
|
||||
|
||||
/**
|
||||
* Add a session by its mapping Id.
|
||||
* @param mappingId the id to map the session to.
|
||||
* @param session the HttpSession.
|
||||
*/
|
||||
void addSessionById(String mappingId, HttpSession session);
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,92 @@
|
|||
/*
|
||||
* Copyright 2007 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.session;
|
||||
|
||||
import org.jasig.cas.client.util.AbstractConfigurationFilter;
|
||||
import org.jasig.cas.client.util.CommonUtils;
|
||||
import org.jasig.cas.client.util.XmlUtils;
|
||||
|
||||
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.HttpSession;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Implements the Single Sign Out protocol. It handles registering the session and destroying the session.
|
||||
*
|
||||
* @author Scott Battaglia
|
||||
* @version $Revision$ $Date$
|
||||
* @since 3.1
|
||||
*/
|
||||
public final class SingleSignOutFilter extends AbstractConfigurationFilter {
|
||||
|
||||
/**
|
||||
* The name of the artifact parameter. This is used to capture the session identifier.
|
||||
*/
|
||||
private String artifactParameterName = "ticket";
|
||||
|
||||
private static SessionMappingStorage SESSION_MAPPING_STORAGE = new HashMapBackedSessionMappingStorage();
|
||||
|
||||
public void init(final FilterConfig filterConfig) throws ServletException {
|
||||
setArtifactParameterName(getPropertyFromInitParams(filterConfig, "artifactParameterName", "ticket"));
|
||||
|
||||
init();
|
||||
}
|
||||
|
||||
public void init() {
|
||||
CommonUtils.assertNotNull(this.artifactParameterName, "artifactParameterName cannot be null.");
|
||||
CommonUtils.assertNotNull(SESSION_MAPPING_STORAGE, "sessionMappingStorage cannote be null.");
|
||||
}
|
||||
|
||||
public void setArtifactParameterName(final String artifactParameterName) {
|
||||
this.artifactParameterName = artifactParameterName;
|
||||
}
|
||||
|
||||
public void doFilter(final ServletRequest servletRequest, final ServletResponse servletResponse, final FilterChain filterChain) throws IOException, ServletException {
|
||||
final HttpServletRequest request = (HttpServletRequest) servletRequest;
|
||||
|
||||
if ("POST".equals(request.getMethod())) {
|
||||
final String logoutRequest = request.getParameter("logoutRequest");
|
||||
|
||||
if (CommonUtils.isNotBlank(logoutRequest)) {
|
||||
final String sessionIdentifier = XmlUtils.getTextForElement(logoutRequest, "SessionIndex");
|
||||
|
||||
if (CommonUtils.isNotBlank(sessionIdentifier)) {
|
||||
final HttpSession session = SESSION_MAPPING_STORAGE.removeSessionByMappingId(sessionIdentifier);
|
||||
|
||||
if (session != null) {
|
||||
session.invalidate();
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
final String artifact = request.getParameter(this.artifactParameterName);
|
||||
final HttpSession session = request.getSession();
|
||||
if (CommonUtils.isNotBlank(artifact)) {
|
||||
SESSION_MAPPING_STORAGE.addSessionById(artifact, session);
|
||||
}
|
||||
}
|
||||
|
||||
filterChain.doFilter(servletRequest, servletResponse);
|
||||
}
|
||||
|
||||
public void setSessionMappingStorage(final SessionMappingStorage storage) {
|
||||
SESSION_MAPPING_STORAGE = storage;
|
||||
}
|
||||
|
||||
public static SessionMappingStorage getSessionMappingStorage() {
|
||||
return SESSION_MAPPING_STORAGE;
|
||||
}
|
||||
|
||||
public void destroy() {
|
||||
// nothing to do
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* Copyright 2007 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.session;
|
||||
|
||||
import javax.servlet.http.HttpSession;
|
||||
import javax.servlet.http.HttpSessionEvent;
|
||||
import javax.servlet.http.HttpSessionListener;
|
||||
|
||||
/**
|
||||
* Listener to detect when an HTTP session is destroyed and remove it from the map of
|
||||
* managed sessions. Also allows for the programmatic removal of sessions.
|
||||
* <p>
|
||||
* Enables the CAS Single Sign out feature.
|
||||
*
|
||||
* Scott Battaglia
|
||||
* @version $Revision$ Date$
|
||||
* @since 3.1
|
||||
*/
|
||||
public final class SingleSignOutHttpSessionListener implements HttpSessionListener {
|
||||
|
||||
private SessionMappingStorage SESSION_MAPPING_STORAGE;
|
||||
|
||||
public void sessionCreated(final HttpSessionEvent event) {
|
||||
// nothing to do at the moment
|
||||
}
|
||||
|
||||
public void sessionDestroyed(final HttpSessionEvent event) {
|
||||
if (SESSION_MAPPING_STORAGE == null) {
|
||||
SESSION_MAPPING_STORAGE = getSessionMappingStorage();
|
||||
}
|
||||
final HttpSession session = event.getSession();
|
||||
SESSION_MAPPING_STORAGE.removeBySessionById(session.getId());
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains a {@link SessionMappingStorage} object. Assumes this method will always return the same
|
||||
* instance of the object. It assumes this because it generally lazily calls the method.
|
||||
*
|
||||
* @return the SessionMappingStorage
|
||||
*/
|
||||
protected static SessionMappingStorage getSessionMappingStorage() {
|
||||
return SingleSignOutFilter.getSessionMappingStorage();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,102 @@
|
|||
package org.jasig.cas.client.util;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import javax.servlet.FilterConfig;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
/**
|
||||
* Abstract filter that contains code that is common to all CAS filters.
|
||||
* <p>
|
||||
* The following filter options can be configured (either at the context-level or filter-level).
|
||||
* <ul>
|
||||
* <li><code>serverName</code> - the name of the CAS server, in the format: localhost:8080 or localhost:8443 or localhost</li>
|
||||
* <li><code>service</code> - the completely qualified service url, i.e. https://localhost/cas-client/app</li>
|
||||
* </ul>
|
||||
* <p>Please note that one of the two above parameters must be set.</p>
|
||||
*
|
||||
* @author Scott Battaglia
|
||||
* @version $Revision$ $Date$
|
||||
* @since 3.1
|
||||
*/
|
||||
public abstract class AbstractCasFilter extends AbstractConfigurationFilter {
|
||||
|
||||
/** Represents the constant for where the assertion will be located in memory. */
|
||||
public static final String CONST_CAS_ASSERTION = "_const_cas_assertion_";
|
||||
|
||||
/** Instance of commons logging for logging purposes. */
|
||||
protected final Log log = LogFactory.getLog(getClass());
|
||||
|
||||
/** Defines the parameter to look for for the artifact. */
|
||||
private String artifactParameterName = "ticket";
|
||||
|
||||
/** Defines the parameter to look for for the service. */
|
||||
private String serviceParameterName = "service";
|
||||
|
||||
/**
|
||||
* The name of the server. Should be in the following format: {protocol}:{hostName}:{port}.
|
||||
* Standard ports can be excluded. */
|
||||
private String serverName;
|
||||
|
||||
/** The exact url of the service. */
|
||||
private String service;
|
||||
|
||||
public final void init(final FilterConfig filterConfig) throws ServletException {
|
||||
setServerName(getPropertyFromInitParams(filterConfig, "serverName", null));
|
||||
setService(getPropertyFromInitParams(filterConfig, "service", null));
|
||||
setArtifactParameterName(getPropertyFromInitParams(filterConfig, "artifactParameterName", "ticket"));
|
||||
setServiceParameterName(getPropertyFromInitParams(filterConfig, "serviceParameterName", "service"));
|
||||
|
||||
initInternal(filterConfig);
|
||||
init();
|
||||
}
|
||||
|
||||
/** Controls the ordering of filter initialization and checking by defining a method that runs before the init. */
|
||||
protected void initInternal(final FilterConfig filterConfig) throws ServletException {
|
||||
// template method
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialization method. Called by Filter's init method or by Spring.
|
||||
*/
|
||||
public void init() {
|
||||
CommonUtils.assertNotNull(this.artifactParameterName, "artifactParameterName cannot be null.");
|
||||
CommonUtils.assertNotNull(this.serviceParameterName, "serviceParameterName cannot be null.");
|
||||
CommonUtils.assertTrue(CommonUtils.isNotEmpty(this.serverName) || CommonUtils.isNotEmpty(this.service), "serverName or service must be set.");
|
||||
}
|
||||
|
||||
public final void destroy() {
|
||||
// nothing to do
|
||||
}
|
||||
|
||||
protected final String constructServiceUrl(final HttpServletRequest request, final HttpServletResponse response) {
|
||||
return CommonUtils.constructServiceUrl(request, response, this.service, this.serverName, this.artifactParameterName);
|
||||
}
|
||||
|
||||
public final void setServerName(final String serverName) {
|
||||
this.serverName = serverName;
|
||||
}
|
||||
|
||||
public final void setService(final String service) {
|
||||
this.service = service;
|
||||
}
|
||||
|
||||
public final void setArtifactParameterName(final String artifactParameterName) {
|
||||
this.artifactParameterName = artifactParameterName;
|
||||
}
|
||||
|
||||
public final void setServiceParameterName(final String serviceParameterName) {
|
||||
this.serviceParameterName = serviceParameterName;
|
||||
}
|
||||
|
||||
public final String getArtifactParameterName() {
|
||||
return this.artifactParameterName;
|
||||
}
|
||||
|
||||
public final String getServiceParameterName() {
|
||||
return this.serviceParameterName;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
package org.jasig.cas.client.util;
|
||||
|
||||
import javax.servlet.Filter;
|
||||
import javax.servlet.FilterConfig;
|
||||
|
||||
/**
|
||||
* Abstracts out the ability to configure the filters from the initial properties provided.
|
||||
*
|
||||
* @author Scott Battaglia
|
||||
* @version $Revision$ $Date$
|
||||
* @since 3.1
|
||||
*/
|
||||
public abstract class AbstractConfigurationFilter implements Filter {
|
||||
|
||||
/**
|
||||
* Retrieves the property from the FilterConfig. First it checks the FilterConfig's initParameters to see if it
|
||||
* has a value.
|
||||
* If it does, it returns that, otherwise it trieves the ServletContext's initParameters and returns that value if any.
|
||||
*
|
||||
* @param filterConfig the Filter Configuration.
|
||||
* @param propertyName the property to retrieve.
|
||||
* @return the property value, following the above conventions. It will always return the more specific value (i.e.
|
||||
* filter vs. context).
|
||||
*/
|
||||
protected final String getPropertyFromInitParams(final FilterConfig filterConfig, final String propertyName, final String defaultValue) {
|
||||
final String value = filterConfig.getInitParameter(propertyName);
|
||||
|
||||
if (CommonUtils.isNotBlank(value)) {
|
||||
return value;
|
||||
}
|
||||
|
||||
final String value2 = filterConfig.getServletContext().getInitParameter(propertyName);
|
||||
|
||||
if (CommonUtils.isNotBlank(value2)) {
|
||||
return value2;
|
||||
}
|
||||
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* Copyright 2007 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 org.jasig.cas.client.validation.Assertion;
|
||||
|
||||
/**
|
||||
* Static holder that places Assertion in a threadlocal.
|
||||
*
|
||||
* @author Scott Battaglia
|
||||
* @version $Revision: 11728 $ $Date: 2007-09-26 14:20:43 -0400 (Tue, 26 Sep 2007) $
|
||||
* @since 3.0
|
||||
*/
|
||||
public class AssertionHolder {
|
||||
|
||||
/**
|
||||
* ThreadLocal to hold the Assertion for Threads to access.
|
||||
*/
|
||||
private static final ThreadLocal threadLocal = new ThreadLocal();
|
||||
|
||||
|
||||
/**
|
||||
* Retrieve the assertion from the ThreadLocal.
|
||||
*/
|
||||
public static Assertion getAssertion() {
|
||||
return (Assertion) threadLocal.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the Assertion to the ThreadLocal.
|
||||
*/
|
||||
public static void setAssertion(final Assertion assertion) {
|
||||
threadLocal.set(assertion);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the ThreadLocal.
|
||||
*/
|
||||
public static void clear() {
|
||||
threadLocal.set(null);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* Copyright 2007 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 org.jasig.cas.client.validation.Assertion;
|
||||
|
||||
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.HttpSession;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Places the assertion in a ThreadLocal such that other resources can access it that do not have access to the web tier session.
|
||||
*
|
||||
* @author Scott Battaglia
|
||||
* @version $Revision: 11728 $ $Date: 2007-09-26 14:20:43 -0400 (Tue, 26 Sep 2007) $
|
||||
* @since 3.0
|
||||
*/
|
||||
public final class AssertionThreadLocalFilter implements Filter {
|
||||
|
||||
public void init(final FilterConfig filterConfig) throws ServletException {
|
||||
// nothing to do here
|
||||
}
|
||||
|
||||
public void doFilter(final ServletRequest servletRequest, final ServletResponse servletResponse, final FilterChain filterChain) throws IOException, ServletException {
|
||||
final HttpServletRequest request = (HttpServletRequest) servletRequest;
|
||||
final HttpSession session = request.getSession(false);
|
||||
final Assertion assertion = (Assertion) (session != null ? session.getAttribute(AbstractCasFilter.CONST_CAS_ASSERTION) : null);
|
||||
|
||||
try {
|
||||
AssertionHolder.setAssertion(assertion);
|
||||
filterChain.doFilter(servletRequest, servletResponse);
|
||||
} finally {
|
||||
AssertionHolder.clear();
|
||||
}
|
||||
}
|
||||
|
||||
public void destroy() {
|
||||
// nothing to do
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,200 @@
|
|||
/*
|
||||
* Copyright 2007 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 org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* Common utilities so that we don't need to include Commons Lang.
|
||||
*
|
||||
* @author Scott Battaglia
|
||||
* @version $Revision: 11729 $ $Date: 2007-09-26 14:22:30 -0400 (Tue, 26 Sep 2007) $
|
||||
* @since 3.0
|
||||
*/
|
||||
public final class CommonUtils {
|
||||
|
||||
/** Instance of Commons Logging. */
|
||||
private static final Log LOG = LogFactory.getLog(CommonUtils.class);
|
||||
|
||||
private CommonUtils() {
|
||||
// nothing to do
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the object is null or not. If it is, throw an exception and
|
||||
* display the message.
|
||||
*
|
||||
* @param object the object to check.
|
||||
* @param message the message to display if the object is null.
|
||||
*/
|
||||
public static void assertNotNull(final Object object, final String message) {
|
||||
if (object == null) {
|
||||
throw new IllegalArgumentException(message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the collection is null or empty. If it is, throw an
|
||||
* exception and display the message.
|
||||
*
|
||||
* @param c the collecion to check.
|
||||
* @param message the message to display if the object is null.
|
||||
*/
|
||||
public static void assertNotEmpty(final Collection c, final String message) {
|
||||
assertNotNull(c, message);
|
||||
if (c.isEmpty()) {
|
||||
throw new IllegalArgumentException(message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert that the statement is true, otherwise throw an exception with the
|
||||
* provided message.
|
||||
*
|
||||
* @param cond the codition to assert is true.
|
||||
* @param message the message to display if the condition is not true.
|
||||
*/
|
||||
public static void assertTrue(final boolean cond, final String message) {
|
||||
if (!cond) {
|
||||
throw new IllegalArgumentException(message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether the String is null or of length 0.
|
||||
*
|
||||
* @param string the string to check
|
||||
* @return true if its null or length of 0, false otherwise.
|
||||
*/
|
||||
public static boolean isEmpty(final String string) {
|
||||
return string == null || string.length() == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the String is not empty. A string is not empty if it is not
|
||||
* null and has a length > 0.
|
||||
*
|
||||
* @param string the string to check
|
||||
* @return true if it is not empty, false otherwise.
|
||||
*/
|
||||
public static boolean isNotEmpty(final String string) {
|
||||
return !isEmpty(string);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if a String is blank or not. A String is blank if its empty or
|
||||
* if it only contains spaces.
|
||||
*
|
||||
* @param string the string to check
|
||||
* @return true if its blank, false otherwise.
|
||||
*/
|
||||
public static boolean isBlank(final String string) {
|
||||
return isEmpty(string) || string.trim().length() == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if a string is not blank. A string is not blank if it contains
|
||||
* at least one non-whitespace character.
|
||||
*
|
||||
* @param string the string to check.
|
||||
* @return true if its not blank, false otherwise.
|
||||
*/
|
||||
public static boolean isNotBlank(final String string) {
|
||||
return !isBlank(string);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs the URL to use to redirect to the CAS server.
|
||||
*
|
||||
* @param casServerLoginUrl the CAS Server login url.
|
||||
* @param serviceParameterName the name of the parameter that defines the service.
|
||||
* @param serviceUrl the actual service's url.
|
||||
* @param renew whether we should send renew or not.
|
||||
* @param gateway where we should send gateway or not.
|
||||
* @return the fully constructed redirect url.
|
||||
*/
|
||||
public static final String constructRedirectUrl(final String casServerLoginUrl, final String serviceParameterName, final String serviceUrl, final boolean renew, final boolean gateway) {
|
||||
try {
|
||||
return casServerLoginUrl + "?" + serviceParameterName + "="
|
||||
+ URLEncoder.encode(serviceUrl, "UTF-8")
|
||||
+ (renew ? "&renew=true" : "")
|
||||
+ (gateway ? "&gateway=true" : "");
|
||||
} catch (final UnsupportedEncodingException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a service url from the HttpServletRequest or from the given
|
||||
* serviceUrl. Prefers the serviceUrl provided if both a serviceUrl and a
|
||||
* serviceName.
|
||||
*
|
||||
* @param request the HttpServletRequest
|
||||
* @param response the HttpServletResponse
|
||||
* @return the service url to use.
|
||||
*/
|
||||
public static final String constructServiceUrl(final HttpServletRequest request,
|
||||
final HttpServletResponse response, final String service, final String serverName, final String artifactParameterName) {
|
||||
if (CommonUtils.isNotBlank(service)) {
|
||||
return response.encodeURL(service);
|
||||
}
|
||||
|
||||
final StringBuffer buffer = new StringBuffer();
|
||||
|
||||
synchronized (buffer) {
|
||||
if (!serverName.startsWith("https://") && !serverName.startsWith("http://")) {
|
||||
buffer.append(request.isSecure() ? "https://" : "http://");
|
||||
}
|
||||
|
||||
buffer.append(serverName);
|
||||
buffer.append(request.getRequestURI());
|
||||
|
||||
if (CommonUtils.isNotBlank(request.getQueryString())) {
|
||||
final int location = request.getQueryString().indexOf(
|
||||
artifactParameterName + "=");
|
||||
|
||||
if (location == 0) {
|
||||
final String returnValue = response.encodeURL(buffer
|
||||
.toString());
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug("serviceUrl generated: " + returnValue);
|
||||
}
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
buffer.append("?");
|
||||
|
||||
if (location == -1) {
|
||||
buffer.append(request.getQueryString());
|
||||
} else if (location > 0) {
|
||||
final int actualLocation = request.getQueryString()
|
||||
.indexOf("&" + artifactParameterName + "=");
|
||||
|
||||
if (actualLocation == -1) {
|
||||
buffer.append(request.getQueryString());
|
||||
} else if (actualLocation > 0) {
|
||||
buffer.append(request.getQueryString().substring(0,
|
||||
actualLocation));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final String returnValue = response.encodeURL(buffer.toString());
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug("serviceUrl generated: " + returnValue);
|
||||
}
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,83 @@
|
|||
/*
|
||||
* Copyright 2007 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 org.jasig.cas.client.validation.Assertion;
|
||||
|
||||
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.HttpServletRequestWrapper;
|
||||
import javax.servlet.http.HttpSession;
|
||||
import java.io.IOException;
|
||||
import java.security.Principal;
|
||||
|
||||
/**
|
||||
* Implementation of a filter that wraps the normal HttpServletRequest with a
|
||||
* wrapper that overrides the getRemoteUser method to retrieve the user from the
|
||||
* CAS Assertion.
|
||||
* <p/>
|
||||
* This filter needs to be configured in the chain so that it executes after
|
||||
* both the authentication and the validation filters.
|
||||
*
|
||||
* @author Scott Battaglia
|
||||
* @version $Revision: 11729 $ $Date: 2007-09-26 14:22:30 -0400 (Tue, 26 Sep 2007) $
|
||||
* @since 3.0
|
||||
*/
|
||||
public final class HttpServletRequestWrapperFilter implements Filter {
|
||||
|
||||
public void destroy() {
|
||||
// nothing to do
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps the HttpServletRequest in a wrapper class that delegates
|
||||
* <code>request.getRemoteUser</code> to the underlying Assertion object
|
||||
* stored in the user session.
|
||||
*/
|
||||
public void doFilter(final ServletRequest servletRequest,
|
||||
final ServletResponse servletResponse, final FilterChain filterChain)
|
||||
throws IOException, ServletException {
|
||||
final Principal principal = retrievePrincipalFromSessionOrRequest(servletRequest);
|
||||
|
||||
filterChain.doFilter(new CasHttpServletRequestWrapper(
|
||||
(HttpServletRequest) servletRequest, principal), servletResponse);
|
||||
}
|
||||
|
||||
protected Principal retrievePrincipalFromSessionOrRequest(final ServletRequest servletRequest) {
|
||||
final HttpServletRequest request = (HttpServletRequest) servletRequest;
|
||||
final HttpSession session = request.getSession(false);
|
||||
final Assertion assertion = (Assertion) (session == null ? request.getAttribute(AbstractCasFilter.CONST_CAS_ASSERTION) : session.getAttribute(AbstractCasFilter.CONST_CAS_ASSERTION));
|
||||
|
||||
return assertion == null ? null : assertion.getPrincipal();
|
||||
}
|
||||
|
||||
public void init(final FilterConfig filterConfig) throws ServletException {
|
||||
// nothing to do
|
||||
}
|
||||
|
||||
final class CasHttpServletRequestWrapper extends HttpServletRequestWrapper {
|
||||
|
||||
private final Principal principal;
|
||||
|
||||
CasHttpServletRequestWrapper(final HttpServletRequest request, final Principal principal) {
|
||||
super(request);
|
||||
this.principal = principal;
|
||||
}
|
||||
|
||||
public Principal getUserPrincipal() {
|
||||
return this.principal;
|
||||
}
|
||||
|
||||
public String getRemoteUser() {
|
||||
return getUserPrincipal().getName();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,158 @@
|
|||
/*
|
||||
* Copyright 2007 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 org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.xml.sax.Attributes;
|
||||
import org.xml.sax.InputSource;
|
||||
import org.xml.sax.SAXException;
|
||||
import org.xml.sax.XMLReader;
|
||||
import org.xml.sax.helpers.DefaultHandler;
|
||||
import org.xml.sax.helpers.XMLReaderFactory;
|
||||
|
||||
import java.io.StringReader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Common utilities for easily parsing XML without duplicating logic.
|
||||
*
|
||||
* @author Scott Battaglia
|
||||
* @version $Revision: 11729 $ $Date: 2007-09-26 14:22:30 -0400 (Tue, 26 Sep 2007) $
|
||||
* @since 3.0
|
||||
*/
|
||||
public final class XmlUtils {
|
||||
|
||||
/**
|
||||
* Static instance of Commons Logging.
|
||||
*/
|
||||
private final static Log LOG = LogFactory.getLog(XmlUtils.class);
|
||||
|
||||
/**
|
||||
* Get an instance of an XML reader from the XMLReaderFactory.
|
||||
*
|
||||
* @return the XMLReader.
|
||||
*/
|
||||
public static XMLReader getXmlReader() {
|
||||
try {
|
||||
return XMLReaderFactory.createXMLReader();
|
||||
} catch (final SAXException e) {
|
||||
throw new RuntimeException("Unable to create XMLReader", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the text for a group of elements. Each text element is an entry
|
||||
* in a list.
|
||||
* <p>This method is currently optimized for the use case of two elements in a list.
|
||||
*
|
||||
* @param xmlAsString the xml response
|
||||
* @param element the element to look for
|
||||
* @return the list of text from the elements.
|
||||
*/
|
||||
public static List getTextForElements(final String xmlAsString,
|
||||
final String element) {
|
||||
final List elements = new ArrayList(2);
|
||||
final XMLReader reader = getXmlReader();
|
||||
|
||||
final DefaultHandler handler = new DefaultHandler() {
|
||||
|
||||
private boolean foundElement = false;
|
||||
|
||||
private StringBuffer buffer = new StringBuffer();
|
||||
|
||||
public void startElement(final String uri, final String localName,
|
||||
final String qName, final Attributes attributes)
|
||||
throws SAXException {
|
||||
if (localName.equals(element)) {
|
||||
this.foundElement = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void endElement(final String uri, final String localName,
|
||||
final String qName) throws SAXException {
|
||||
if (localName.equals(element)) {
|
||||
this.foundElement = false;
|
||||
elements.add(this.buffer.toString());
|
||||
this.buffer = new StringBuffer();
|
||||
}
|
||||
}
|
||||
|
||||
public void characters(char[] ch, int start, int length)
|
||||
throws SAXException {
|
||||
if (this.foundElement) {
|
||||
this.buffer.append(ch, start, length);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
reader.setContentHandler(handler);
|
||||
reader.setErrorHandler(handler);
|
||||
|
||||
try {
|
||||
reader.parse(new InputSource(new StringReader(xmlAsString)));
|
||||
} catch (final Exception e) {
|
||||
LOG.error(e, e);
|
||||
return null;
|
||||
}
|
||||
|
||||
return elements;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the text for a specific element (when we know there is only
|
||||
* one).
|
||||
*
|
||||
* @param xmlAsString the xml response
|
||||
* @param element the element to look for
|
||||
* @return the text value of the element.
|
||||
*/
|
||||
public static String getTextForElement(final String xmlAsString,
|
||||
final String element) {
|
||||
final XMLReader reader = getXmlReader();
|
||||
final StringBuffer buffer = new StringBuffer();
|
||||
|
||||
final DefaultHandler handler = new DefaultHandler() {
|
||||
|
||||
private boolean foundElement = false;
|
||||
|
||||
public void startElement(final String uri, final String localName,
|
||||
final String qName, final Attributes attributes)
|
||||
throws SAXException {
|
||||
if (localName.equals(element)) {
|
||||
this.foundElement = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void endElement(final String uri, final String localName,
|
||||
final String qName) throws SAXException {
|
||||
if (localName.equals(element)) {
|
||||
this.foundElement = false;
|
||||
}
|
||||
}
|
||||
|
||||
public void characters(char[] ch, int start, int length)
|
||||
throws SAXException {
|
||||
if (this.foundElement) {
|
||||
buffer.append(ch, start, length);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
reader.setContentHandler(handler);
|
||||
reader.setErrorHandler(handler);
|
||||
|
||||
try {
|
||||
reader.parse(new InputSource(new StringReader(xmlAsString)));
|
||||
} catch (final Exception e) {
|
||||
LOG.error(e, e);
|
||||
return null;
|
||||
}
|
||||
|
||||
return buffer.toString();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
<html>
|
||||
<body>
|
||||
<p>The validation package includes interfaces for validating Tickets, as well as the common implementations.</p>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* Copyright 2007 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.validation;
|
||||
|
||||
import java.net.URL;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Abstract class that knows the protocol for validating a CAS ticket.
|
||||
*
|
||||
* @author Scott Battaglia
|
||||
* @version $Revision$ $Date$
|
||||
* @since 3.1
|
||||
*/
|
||||
public abstract class AbstractCasProtocolUrlBasedTicketValidator extends AbstractUrlBasedTicketValidator {
|
||||
|
||||
protected AbstractCasProtocolUrlBasedTicketValidator(final String casServerUrlPrefix) {
|
||||
super(casServerUrlPrefix);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the response from the server by opening a connection and merely reading the response.
|
||||
*/
|
||||
protected final String retrieveResponseFromServer(final URL validationUrl, final String ticket) {
|
||||
HttpURLConnection connection = null;
|
||||
|
||||
try {
|
||||
connection = (HttpURLConnection) validationUrl.openConnection();
|
||||
final BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
|
||||
|
||||
String line;
|
||||
final StringBuffer stringBuffer = new StringBuffer(255);
|
||||
|
||||
synchronized (stringBuffer) {
|
||||
while ((line = in.readLine()) != null) {
|
||||
stringBuffer.append(line);
|
||||
stringBuffer.append("\n");
|
||||
}
|
||||
return stringBuffer.toString();
|
||||
}
|
||||
|
||||
} catch (final IOException e) {
|
||||
log.error(e,e);
|
||||
return null;
|
||||
} finally {
|
||||
if (connection != null) {
|
||||
connection.disconnect();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,182 @@
|
|||
/*
|
||||
* Copyright 2007 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.validation;
|
||||
|
||||
import org.jasig.cas.client.util.AbstractCasFilter;
|
||||
import org.jasig.cas.client.util.CommonUtils;
|
||||
|
||||
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 java.io.IOException;
|
||||
|
||||
/**
|
||||
* The filter that handles all the work of validating ticket requests.
|
||||
* <p>
|
||||
* This filter can be configured with the following values:
|
||||
* <ul>
|
||||
* <li><code>redirectAfterValidation</code> - redirect the CAS client to the same URL without the ticket.</li>
|
||||
* <li><code>exceptionOnValidationFailure</code> - throw an exception if the validation fails. Otherwise, continue
|
||||
* processing.</li>
|
||||
* <li><code>useSession</code> - store any of the useful information in a session attribute.</li>
|
||||
* </ul>
|
||||
*
|
||||
* @author Scott Battaglia
|
||||
* @version $Revision$ $Date$
|
||||
* @since 3.1
|
||||
*/
|
||||
public abstract class AbstractTicketValidationFilter extends AbstractCasFilter {
|
||||
|
||||
/** The TicketValidator we will use to validate tickets. */
|
||||
private TicketValidator ticketValidator;
|
||||
|
||||
/**
|
||||
* Specify whether the filter should redirect the user agent after a
|
||||
* successful validation to remove the ticket parameter from the query
|
||||
* string.
|
||||
*/
|
||||
private boolean redirectAfterValidation = false;
|
||||
|
||||
/** Determines whether an exception is thrown when there is a ticket validation failure. */
|
||||
private boolean exceptionOnValidationFailure = true;
|
||||
|
||||
private boolean useSession = true;
|
||||
|
||||
/**
|
||||
* Template method to return the appropriate validator.
|
||||
*
|
||||
* @param filterConfig the FilterConfiguration that may be needed to construct a validator.
|
||||
* @return the ticket validator.
|
||||
*/
|
||||
protected TicketValidator getTicketValidator(FilterConfig filterConfig) {
|
||||
return this.ticketValidator;
|
||||
}
|
||||
|
||||
protected void initInternal(final FilterConfig filterConfig) throws ServletException {
|
||||
super.initInternal(filterConfig);
|
||||
setExceptionOnValidationFailure(Boolean.parseBoolean(getPropertyFromInitParams(filterConfig, "exceptionOnValidationFailure", "true")));
|
||||
setRedirectAfterValidation(Boolean.parseBoolean(getPropertyFromInitParams(filterConfig, "redirectAfterValidation", "false")));
|
||||
setUseSession(Boolean.parseBoolean(getPropertyFromInitParams(filterConfig, "useSession", "true")));
|
||||
setTicketValidator(getTicketValidator(filterConfig));
|
||||
}
|
||||
|
||||
public void init() {
|
||||
super.init();
|
||||
CommonUtils.assertNotNull(this.ticketValidator, "ticketValidator cannot be null.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Pre-process the request before the normal filter process starts. This could be useful for pre-empting code.
|
||||
*
|
||||
* @param servletRequest The servlet request.
|
||||
* @param servletResponse The servlet response.
|
||||
* @param filterChain the filter chain.
|
||||
* @return true if processing should continue, false otherwise.
|
||||
* @throws IOException if there is an I/O problem
|
||||
* @throws ServletException if there is a servlet problem.
|
||||
*/
|
||||
protected boolean preFilter(final ServletRequest servletRequest, final ServletResponse servletResponse, final FilterChain filterChain) throws IOException, ServletException {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Template method that gets executed if ticket validation succeeds. Override if you want additional behavior to occur
|
||||
* if ticket validation succeeds. This method is called after all ValidationFilter processing required for a successful authentication
|
||||
* occurs.
|
||||
*
|
||||
* @param request the HttpServletRequest.
|
||||
* @param response the HttpServletResponse.
|
||||
* @param assertion the successful Assertion from the server.
|
||||
*/
|
||||
protected void onSuccessfulValidation(final HttpServletRequest request, final HttpServletResponse response, final Assertion assertion) {
|
||||
// nothing to do here.
|
||||
}
|
||||
|
||||
/**
|
||||
* Template method that gets executed if validation fails. This method is called right after the exception is caught from the ticket validator
|
||||
* but before any of the processing of the exception occurs.
|
||||
*
|
||||
* @param request the HttpServletRequest.
|
||||
* @param response the HttpServletResponse.
|
||||
*/
|
||||
protected void onFailedValidation(final HttpServletRequest request, final HttpServletResponse response) {
|
||||
// nothing to do here.
|
||||
}
|
||||
|
||||
public final void doFilter(final ServletRequest servletRequest, final ServletResponse servletResponse, final FilterChain filterChain) throws IOException, ServletException {
|
||||
|
||||
if (!preFilter(servletRequest, servletResponse, filterChain)) {
|
||||
return;
|
||||
}
|
||||
|
||||
final HttpServletRequest request = (HttpServletRequest) servletRequest;
|
||||
final HttpServletResponse response = (HttpServletResponse) servletResponse;
|
||||
final String ticket = request.getParameter(getArtifactParameterName());
|
||||
|
||||
if (CommonUtils.isNotBlank(ticket)) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Attempting to validate ticket: " + ticket);
|
||||
}
|
||||
|
||||
try {
|
||||
final Assertion assertion = this.ticketValidator.validate(
|
||||
ticket, constructServiceUrl(request,
|
||||
response));
|
||||
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Successfully authenticated user: "
|
||||
+ assertion.getPrincipal().getName());
|
||||
}
|
||||
|
||||
request.setAttribute(CONST_CAS_ASSERTION, assertion);
|
||||
|
||||
if (this.useSession) {
|
||||
request.getSession().setAttribute(CONST_CAS_ASSERTION,
|
||||
assertion);
|
||||
}
|
||||
onSuccessfulValidation(request, response, assertion);
|
||||
} catch (final TicketValidationException e) {
|
||||
response.setStatus(HttpServletResponse.SC_FORBIDDEN);
|
||||
log.warn(e, e);
|
||||
|
||||
onFailedValidation(request, response);
|
||||
|
||||
if (this.exceptionOnValidationFailure) {
|
||||
throw new ServletException(e);
|
||||
}
|
||||
}
|
||||
|
||||
if (this.redirectAfterValidation) {
|
||||
response.sendRedirect(response
|
||||
.encodeRedirectURL(constructServiceUrl(request, response)));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
filterChain.doFilter(request, response);
|
||||
|
||||
}
|
||||
|
||||
public final void setTicketValidator(final TicketValidator ticketValidator) {
|
||||
this.ticketValidator = ticketValidator;
|
||||
}
|
||||
|
||||
public final void setRedirectAfterValidation(final boolean redirectAfterValidation) {
|
||||
this.redirectAfterValidation = redirectAfterValidation;
|
||||
}
|
||||
|
||||
public final void setExceptionOnValidationFailure(final boolean exceptionOnValidationFailure) {
|
||||
this.exceptionOnValidationFailure = exceptionOnValidationFailure;
|
||||
}
|
||||
|
||||
public final void setUseSession(final boolean useSession) {
|
||||
this.useSession = useSession;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,174 @@
|
|||
/*
|
||||
* Copyright 2007 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.validation;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.jasig.cas.client.util.CommonUtils;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Abstract validator implementation for tickets that must be validated against a server.
|
||||
*
|
||||
* @author Scott Battaglia
|
||||
* @version $Revision$ $Date$
|
||||
* @since 3.1
|
||||
*/
|
||||
public abstract class AbstractUrlBasedTicketValidator implements TicketValidator {
|
||||
|
||||
/**
|
||||
* Commons Logging instance.
|
||||
*/
|
||||
protected final Log log = LogFactory.getLog(getClass());
|
||||
|
||||
/**
|
||||
* Prefix for the CAS server. Should be everything up to the url endpoint, including the /.
|
||||
*
|
||||
* i.e. https://cas.rutgers.edu/
|
||||
*/
|
||||
private final String casServerUrlPrefix;
|
||||
|
||||
/**
|
||||
* Whether the request include a renew or not.
|
||||
*/
|
||||
private boolean renew;
|
||||
|
||||
/**
|
||||
* Constructs a new TicketValidator with the casServerUrlPrefix.
|
||||
*
|
||||
* @param casServerUrlPrefix the location of the CAS server.
|
||||
*/
|
||||
protected AbstractUrlBasedTicketValidator(final String casServerUrlPrefix) {
|
||||
this.casServerUrlPrefix = casServerUrlPrefix;
|
||||
CommonUtils.assertNotNull(this.casServerUrlPrefix, "casServerUrlPrefix cannot be null.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Template method for ticket validators that need to provide additional parameters to the validation url.
|
||||
*
|
||||
* @param urlParameters the map containing the parameters.
|
||||
*/
|
||||
protected void populateUrlAttributeMap(final Map urlParameters) {
|
||||
// nothing to do
|
||||
}
|
||||
|
||||
/**
|
||||
* The endpoint of the validation URL. Should be relative (i.e. not start with a "/"). I.e. validate or serviceValidate.
|
||||
* @return the endpoint of the validation URL.
|
||||
*/
|
||||
protected abstract String getUrlSuffix();
|
||||
|
||||
/**
|
||||
* Constructs the URL to send the validation request to.
|
||||
*
|
||||
* @param ticket the ticket to be validated.
|
||||
* @param serviceUrl the service identifier.
|
||||
* @return the fully constructed URL.
|
||||
*/
|
||||
protected final String constructValidationUrl(final String ticket, final String serviceUrl) {
|
||||
final Map urlParameters = new HashMap();
|
||||
|
||||
urlParameters.put("ticket", ticket);
|
||||
urlParameters.put("service", encodeUrl(serviceUrl));
|
||||
|
||||
if (this.renew) {
|
||||
urlParameters.put("renew", "true");
|
||||
}
|
||||
|
||||
populateUrlAttributeMap(urlParameters);
|
||||
|
||||
final String suffix = getUrlSuffix();
|
||||
final StringBuffer buffer = new StringBuffer(urlParameters.size()*10 + this.casServerUrlPrefix.length() + suffix.length() +1);
|
||||
|
||||
int i = 0;
|
||||
synchronized (buffer) {
|
||||
buffer.append(this.casServerUrlPrefix);
|
||||
buffer.append("/");
|
||||
buffer.append(suffix);
|
||||
|
||||
for (final Iterator iter = urlParameters.entrySet().iterator(); iter.hasNext();) {
|
||||
buffer.append(i++ == 0 ? "?" : "&");
|
||||
final Map.Entry entry = (Map.Entry) iter.next();
|
||||
final String key = (String) entry.getKey();
|
||||
final String value = (String) entry.getValue();
|
||||
|
||||
if (value != null) {
|
||||
buffer.append(key);
|
||||
buffer.append("=");
|
||||
buffer.append(value);
|
||||
}
|
||||
}
|
||||
|
||||
return buffer.toString();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes a URL using the URLEncoder format.
|
||||
*
|
||||
* @param url the url to encode.
|
||||
* @return the encoded url, or the original url if "UTF-8" character encoding could not be found.
|
||||
*/
|
||||
protected final String encodeUrl(final String url) {
|
||||
if (url == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
return URLEncoder.encode(url, "UTF-8");
|
||||
} catch (final UnsupportedEncodingException e) {
|
||||
return url;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the response from the server into a CAS Assertion.
|
||||
*
|
||||
* @param response the response from the server, in any format.
|
||||
* @return the CAS assertion if one could be parsed from the response.
|
||||
* @throws TicketValidationException if an Assertion could not be created.
|
||||
*
|
||||
*/
|
||||
protected abstract Assertion parseResponseFromServer(final String response) throws TicketValidationException;
|
||||
|
||||
/**
|
||||
* Contacts the CAS Server to retrieve the response for the ticket validation.
|
||||
*
|
||||
* @param validationUrl the url to send the validation request to.
|
||||
* @param ticket the ticket to validate.
|
||||
* @return the response from the CAS server.
|
||||
*/
|
||||
|
||||
protected abstract String retrieveResponseFromServer(URL validationUrl, String ticket);
|
||||
|
||||
public Assertion validate(final String ticket, final String service) throws TicketValidationException {
|
||||
|
||||
final String validationUrl = constructValidationUrl(ticket, service);
|
||||
|
||||
try {
|
||||
final String serverResponse = retrieveResponseFromServer(new URL(validationUrl), ticket);
|
||||
|
||||
if (serverResponse == null) {
|
||||
throw new TicketValidationException("The CAS server returned no response.");
|
||||
}
|
||||
|
||||
return parseResponseFromServer(serverResponse);
|
||||
} catch (final MalformedURLException e) {
|
||||
throw new TicketValidationException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public void setRenew(final boolean renew) {
|
||||
this.renew = renew;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* Copyright 2007 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.validation;
|
||||
|
||||
import org.jasig.cas.client.authentication.AttributePrincipal;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Represents a response to a validation request.
|
||||
*
|
||||
* @author Scott Battaglia
|
||||
* @version $Revision$ $Date$
|
||||
* @since 3.1
|
||||
*/
|
||||
public interface Assertion extends Serializable {
|
||||
|
||||
/**
|
||||
* The date from which the assertion is valid from.
|
||||
*
|
||||
* @return the valid from date.
|
||||
*/
|
||||
Date getValidFromDate();
|
||||
|
||||
/**
|
||||
* The date which the assertion is valid until.
|
||||
*
|
||||
* @return the valid until date.
|
||||
*/
|
||||
Date getValidUntilDate();
|
||||
|
||||
/**
|
||||
* The key/value pairs associated with this assertion.
|
||||
*
|
||||
* @return the map of attributes.
|
||||
*/
|
||||
Map getAttributes();
|
||||
|
||||
/**
|
||||
* The principal for which this assertion is valid.
|
||||
*
|
||||
* @return the principal.
|
||||
*/
|
||||
AttributePrincipal getPrincipal();
|
||||
}
|
||||
|
|
@ -0,0 +1,102 @@
|
|||
/*
|
||||
* Copyright 2007 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.validation;
|
||||
|
||||
import org.jasig.cas.client.authentication.AttributePrincipal;
|
||||
import org.jasig.cas.client.authentication.AttributePrincipalImpl;
|
||||
import org.jasig.cas.client.util.CommonUtils;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Concrete Implementation of the {@link Assertion}.
|
||||
*
|
||||
* @author Scott Battaglia
|
||||
* @version $Revision$ $Date$
|
||||
* @since 3.1
|
||||
*
|
||||
*/
|
||||
public final class AssertionImpl implements Assertion {
|
||||
|
||||
/** Unique Id for serialization. */
|
||||
private static final long serialVersionUID = -7767943925833639221L;
|
||||
|
||||
/** The date from which the assertion is valid. */
|
||||
private final Date validFromDate;
|
||||
|
||||
/** The date the assertion is valid until. */
|
||||
private final Date validUntilDate;
|
||||
|
||||
/** Map of key/value pairs associated with this assertion. I.e. authentication type. */
|
||||
private final Map attributes;
|
||||
|
||||
/** The principal for which this assertion is valid for. */
|
||||
private final AttributePrincipal principal;
|
||||
|
||||
/**
|
||||
* Constructs a new Assertion with a Principal of the supplied name, a valid from date of now, no valid until date, and no attributes.
|
||||
*
|
||||
* @param name the name of the principal for which this assertion is valid.
|
||||
*/
|
||||
public AssertionImpl(final String name) {
|
||||
this(new AttributePrincipalImpl(name));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new Assrtion with the supplied Principal.
|
||||
*
|
||||
* @param principal the Principal to associate with the Assertion.
|
||||
*/
|
||||
public AssertionImpl(final AttributePrincipal principal) {
|
||||
this(principal, Collections.EMPTY_MAP);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new Assertion with the supplied principal and Assertion attributes.
|
||||
*
|
||||
* @param principal the Principal to associate with the Assertion.
|
||||
* @param attributes the key/value pairs for this attribute.
|
||||
*/
|
||||
public AssertionImpl(final AttributePrincipal principal, final Map attributes) {
|
||||
this(principal, new Date(), null, attributes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creats a new Assertion with the supplied principal, Assertion attributes, and start and valid until dates.
|
||||
*
|
||||
* @param principal the Principal to associate with the Assertion.
|
||||
* @param validFromDate when the assertion is valid from.
|
||||
* @param validUntilDate when the assertion is valid to.
|
||||
* @param attributes the key/value pairs for this attribute.
|
||||
*/
|
||||
public AssertionImpl(final AttributePrincipal principal, final Date validFromDate, final Date validUntilDate, final Map attributes) {
|
||||
this.principal = principal;
|
||||
this.validFromDate = validFromDate;
|
||||
this.validUntilDate = validUntilDate;
|
||||
this.attributes = attributes;
|
||||
|
||||
CommonUtils.assertNotNull(this.principal, "principal cannot be null.");
|
||||
CommonUtils.assertNotNull(this.validFromDate, "validFromDate cannot be null.");
|
||||
CommonUtils.assertNotNull(this.attributes, "attributes cannot be null.");
|
||||
}
|
||||
public Date getValidFromDate() {
|
||||
return this.validFromDate;
|
||||
}
|
||||
|
||||
public Date getValidUntilDate() {
|
||||
return this.validUntilDate;
|
||||
}
|
||||
|
||||
public Map getAttributes() {
|
||||
return this.attributes;
|
||||
}
|
||||
|
||||
public AttributePrincipal getPrincipal() {
|
||||
return this.principal;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* Copyright 2007 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.validation;
|
||||
|
||||
import javax.servlet.FilterConfig;
|
||||
|
||||
/**
|
||||
* Implementation of AbstractTicketValidatorFilter that instanciates a Cas10TicketValidator.
|
||||
* <p>Deployers can provide the "casServerPrefix" and the "renew" attributes via the standard context or filter init
|
||||
* parameters.
|
||||
*
|
||||
* @author Scott Battaglia
|
||||
* @version $Revision$ $Date$
|
||||
* @since 3.1
|
||||
*/
|
||||
public class Cas10TicketValidationFilter extends AbstractTicketValidationFilter {
|
||||
|
||||
protected final TicketValidator getTicketValidator(final FilterConfig filterConfig) {
|
||||
final String casUrlServerPrefix = getPropertyFromInitParams(filterConfig, "casUrlServerPrefix", null);
|
||||
final Cas10TicketValidator validator = new Cas10TicketValidator(casUrlServerPrefix);
|
||||
validator.setRenew(Boolean.parseBoolean(getPropertyFromInitParams(filterConfig, "renew", "false")));
|
||||
|
||||
return validator;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* Copyright 2007 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.validation;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.StringReader;
|
||||
|
||||
/**
|
||||
* Implementation of a Ticket Validator that can validate tickets conforming to the CAS 1.0 specification.
|
||||
*
|
||||
* @author Scott Battaglia
|
||||
* @version $Revision$ $Date$
|
||||
* @since 3.1
|
||||
*/
|
||||
public final class Cas10TicketValidator extends AbstractCasProtocolUrlBasedTicketValidator {
|
||||
|
||||
public Cas10TicketValidator(final String casServerUrlPrefix) {
|
||||
super(casServerUrlPrefix);
|
||||
}
|
||||
|
||||
protected String getUrlSuffix() {
|
||||
return "validate";
|
||||
}
|
||||
|
||||
protected Assertion parseResponseFromServer(final String response) throws TicketValidationException {
|
||||
if (!response.startsWith("yes")) {
|
||||
throw new TicketValidationException("CAS Server could not validate ticket.");
|
||||
}
|
||||
|
||||
try {
|
||||
final BufferedReader reader = new BufferedReader(new StringReader(
|
||||
response));
|
||||
reader.readLine();
|
||||
final String name = reader.readLine();
|
||||
|
||||
return new AssertionImpl(name);
|
||||
} catch (final IOException e) {
|
||||
throw new TicketValidationException("Unable to parse response.", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,150 @@
|
|||
/*
|
||||
* Copyright 2007 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.validation;
|
||||
|
||||
import org.jasig.cas.client.proxy.Cas20ProxyRetriever;
|
||||
import org.jasig.cas.client.proxy.ProxyGrantingTicketStorage;
|
||||
import org.jasig.cas.client.proxy.ProxyGrantingTicketStorageImpl;
|
||||
import org.jasig.cas.client.util.CommonUtils;
|
||||
|
||||
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 java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Creates either a CAS20ProxyTicketValidator or a CAS20ServiceTicketValidator depending on whether any of the
|
||||
* proxy parameters are set.
|
||||
*
|
||||
* @author Scott Battaglia
|
||||
* @version $Revision$ $Date$
|
||||
* @since 3.1
|
||||
*
|
||||
*/
|
||||
public class Cas20ProxyReceivingTicketValidationFilter extends AbstractTicketValidationFilter {
|
||||
|
||||
/**
|
||||
* Constant representing the ProxyGrantingTicket IOU Request Parameter.
|
||||
*/
|
||||
private static final String PARAM_PROXY_GRANTING_TICKET_IOU = "pgtIou";
|
||||
|
||||
/**
|
||||
* Constant representing the ProxyGrantingTicket Request Parameter.
|
||||
*/
|
||||
private static final String PARAM_PROXY_GRANTING_TICKET = "pgtId";
|
||||
|
||||
/**
|
||||
* The URL to send to the CAS server as the URL that will process proxying requests on the CAS client.
|
||||
*/
|
||||
private String proxyReceptorUrl;
|
||||
|
||||
/**
|
||||
* Storage location of ProxyGrantingTickets and Proxy Ticket IOUs.
|
||||
*/
|
||||
private ProxyGrantingTicketStorage proxyGrantingTicketStorage = new ProxyGrantingTicketStorageImpl();
|
||||
|
||||
protected void initInternal(final FilterConfig filterConfig) throws ServletException {
|
||||
super.initInternal(filterConfig);
|
||||
setProxyReceptorUrl(getPropertyFromInitParams(filterConfig, "proxyReceptorUrl", null));
|
||||
}
|
||||
|
||||
public void init() {
|
||||
super.init();
|
||||
CommonUtils.assertNotNull(this.proxyGrantingTicketStorage, "proxyGrantingTicketStorage cannot be null.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Cas20ServiceTicketValidator or a Cas20ProxyTicketValidator based on supplied parameters.
|
||||
*
|
||||
* @param filterConfig the Filter Configuration object.
|
||||
* @return a fully constructed TicketValidator.
|
||||
*/
|
||||
protected final TicketValidator getTicketValidator(final FilterConfig filterConfig) {
|
||||
final String allowAnyProxy = getPropertyFromInitParams(filterConfig, "acceptAnyProxy", null);
|
||||
final String allowedProxyChains = getPropertyFromInitParams(filterConfig, "allowedProxyChains", null);
|
||||
final String casServerUrlPrefix = getPropertyFromInitParams(filterConfig, "casServerUrlPrefix", null);
|
||||
final Cas20ServiceTicketValidator validator;
|
||||
|
||||
if (CommonUtils.isNotBlank(allowAnyProxy) || CommonUtils.isNotBlank(allowedProxyChains)) {
|
||||
final Cas20ProxyTicketValidator v = new Cas20ProxyTicketValidator(casServerUrlPrefix);
|
||||
v.setAcceptAnyProxy(Boolean.parseBoolean(allowAnyProxy));
|
||||
v.setAllowedProxyChains(constructListOfProxies(allowedProxyChains));
|
||||
validator = v;
|
||||
} else {
|
||||
validator = new Cas20ServiceTicketValidator(casServerUrlPrefix);
|
||||
}
|
||||
validator.setProxyCallbackUrl(getPropertyFromInitParams(filterConfig, "proxyCallbackUrl", null));
|
||||
validator.setProxyGrantingTicketStorage(this.proxyGrantingTicketStorage);
|
||||
validator.setProxyRetriever(new Cas20ProxyRetriever(casServerUrlPrefix));
|
||||
validator.setRenew(Boolean.parseBoolean(getPropertyFromInitParams(filterConfig, "renew", "false")));
|
||||
return validator;
|
||||
}
|
||||
|
||||
protected final List constructListOfProxies(final String proxies) {
|
||||
if (CommonUtils.isBlank(proxies)) {
|
||||
return new ArrayList();
|
||||
}
|
||||
|
||||
final String[] splitProxies = proxies.split("\n");
|
||||
final List items = Arrays.asList(splitProxies);
|
||||
final ProxyListPropertyEditor editor = new ProxyListPropertyEditor();
|
||||
editor.setValue(items);
|
||||
return (List) editor.getValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* This processes the ProxyReceptor request before the ticket validation code executes.
|
||||
*/
|
||||
protected final boolean preFilter(final ServletRequest servletRequest, final ServletResponse servletResponse, final FilterChain filterChain) throws IOException, ServletException {
|
||||
final HttpServletRequest request = (HttpServletRequest) servletRequest;
|
||||
final HttpServletResponse response = (HttpServletResponse) servletResponse;
|
||||
final String requestUri = request.getRequestURI();
|
||||
|
||||
if (CommonUtils.isEmpty(this.proxyReceptorUrl) || !requestUri.endsWith(this.proxyReceptorUrl)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
final String proxyGrantingTicketIou = request
|
||||
.getParameter(PARAM_PROXY_GRANTING_TICKET_IOU);
|
||||
|
||||
final String proxyGrantingTicket = request
|
||||
.getParameter(PARAM_PROXY_GRANTING_TICKET);
|
||||
|
||||
if (CommonUtils.isBlank(proxyGrantingTicket)
|
||||
|| CommonUtils.isBlank(proxyGrantingTicketIou)) {
|
||||
response.getWriter().write("");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Received proxyGrantingTicketId ["
|
||||
+ proxyGrantingTicket + "] for proxyGrantingTicketIou ["
|
||||
+ proxyGrantingTicketIou + "]");
|
||||
}
|
||||
|
||||
this.proxyGrantingTicketStorage.save(proxyGrantingTicketIou,
|
||||
proxyGrantingTicket);
|
||||
|
||||
response.getWriter().write("<?xml version=\"1.0\"?>");
|
||||
response.getWriter().write("<casClient:proxySuccess xmlns:casClient=\"http://www.yale.edu/tp/casClient\" />");
|
||||
return false;
|
||||
}
|
||||
|
||||
public final void setProxyReceptorUrl(final String proxyReceptorUrl) {
|
||||
this.proxyReceptorUrl = proxyReceptorUrl;
|
||||
}
|
||||
|
||||
public final void setProxyGrantingTicketStorage(final ProxyGrantingTicketStorage proxyGrantingTicketStorage) {
|
||||
this.proxyGrantingTicketStorage = proxyGrantingTicketStorage;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* Copyright 2007 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.validation;
|
||||
|
||||
import org.jasig.cas.client.util.XmlUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Extension to the traditional Service Ticket validation that will validate service tickets and proxy tickets.
|
||||
*
|
||||
* @author Scott Battaglia
|
||||
* @version $Revision$ $Date$
|
||||
* @since 3.1
|
||||
*/
|
||||
public final class Cas20ProxyTicketValidator extends Cas20ServiceTicketValidator {
|
||||
|
||||
private boolean acceptAnyProxy;
|
||||
|
||||
/** This should be a list of an array of Strings */
|
||||
private List allowedProxyChains = new ArrayList();
|
||||
|
||||
public Cas20ProxyTicketValidator(final String casServerUrlPrefix) {
|
||||
super(casServerUrlPrefix);
|
||||
}
|
||||
|
||||
protected String getUrlSuffix() {
|
||||
return "proxyValidate";
|
||||
}
|
||||
|
||||
protected void customParseResponse(final String response, final Assertion assertion) throws TicketValidationException {
|
||||
final List proxies = XmlUtils.getTextForElements(response, "proxy");
|
||||
final String[] proxiedList = (String[]) proxies.toArray(new String[proxies.size()]);
|
||||
|
||||
// this means there was nothing in the proxy chain, which is okay
|
||||
if (proxies == null || proxies.isEmpty() || this.acceptAnyProxy) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (Iterator iter = this.allowedProxyChains.iterator(); iter.hasNext();) {
|
||||
if (Arrays.equals(proxiedList, (String[]) iter.next())) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
throw new InvalidProxyChainTicketValidationException("Invalid proxy chain: " + proxies.toString());
|
||||
}
|
||||
|
||||
public void setAcceptAnyProxy(final boolean acceptAnyProxy) {
|
||||
this.acceptAnyProxy = acceptAnyProxy;
|
||||
}
|
||||
|
||||
public void setAllowedProxyChains(final List allowedProxyChains) {
|
||||
this.allowedProxyChains = allowedProxyChains;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* Copyright 2007 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.validation;
|
||||
|
||||
import java.beans.IntrospectionException;
|
||||
import java.beans.PropertyDescriptor;
|
||||
import java.beans.PropertyEditor;
|
||||
import java.beans.SimpleBeanInfo;
|
||||
|
||||
import org.springframework.beans.propertyeditors.CustomBooleanEditor;
|
||||
|
||||
/**
|
||||
* BeanInfo support for using this class with Spring. Configures a ProxyListPropertyEditor to be used with the
|
||||
* Cas20ProxyTicketValidator when Spring is used to configure the CAS client.
|
||||
*
|
||||
* @author Scott Battaglia
|
||||
* @version $Revision$ $Date$
|
||||
* @since 3.1
|
||||
*/
|
||||
public final class Cas20ProxyTicketValidatorBeanInfo extends SimpleBeanInfo {
|
||||
|
||||
public PropertyDescriptor[] getPropertyDescriptors() {
|
||||
try {
|
||||
final PropertyDescriptor descriptor = new PropertyDescriptor("allowedProxyChains", Cas20ProxyTicketValidator.class, null, "setAllowedProxyChains") {
|
||||
public PropertyEditor createPropertyEditor(final Object bean) {
|
||||
return new ProxyListPropertyEditor();
|
||||
}
|
||||
};
|
||||
|
||||
final PropertyDescriptor acceptAnyProxy = new PropertyDescriptor("acceptAnyProxy", Cas20ProxyTicketValidator.class, null, "setAcceptAnyProxy") {
|
||||
public PropertyEditor createPropertyEditor(final Object bean) {
|
||||
return new CustomBooleanEditor(true);
|
||||
}
|
||||
};
|
||||
|
||||
return new PropertyDescriptor[] {descriptor, acceptAnyProxy};
|
||||
} catch (final IntrospectionException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,112 @@
|
|||
/*
|
||||
* Copyright 2007 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.validation;
|
||||
|
||||
import org.jasig.cas.client.authentication.AttributePrincipal;
|
||||
import org.jasig.cas.client.authentication.AttributePrincipalImpl;
|
||||
import org.jasig.cas.client.proxy.Cas20ProxyRetriever;
|
||||
import org.jasig.cas.client.proxy.ProxyGrantingTicketStorage;
|
||||
import org.jasig.cas.client.proxy.ProxyRetriever;
|
||||
import org.jasig.cas.client.util.CommonUtils;
|
||||
import org.jasig.cas.client.util.XmlUtils;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Implementation of the TicketValidator that will validate Service Tickets in compliance with the CAS 2.
|
||||
*
|
||||
* @author Scott Battaglia
|
||||
* @version $Revision$ $Date$
|
||||
* @since 3.1
|
||||
*/
|
||||
public class Cas20ServiceTicketValidator extends AbstractCasProtocolUrlBasedTicketValidator {
|
||||
|
||||
/** The CAS 2.0 protocol proxy callback url. */
|
||||
private String proxyCallbackUrl;
|
||||
|
||||
/** The storage location of the proxy granting tickets. */
|
||||
private ProxyGrantingTicketStorage proxyGrantingTicketStorage;
|
||||
|
||||
/** Implementation of the proxy retriever. */
|
||||
private ProxyRetriever proxyRetriever;
|
||||
|
||||
/**
|
||||
* Constructs an instance of the CAS 2.0 Service Ticket Validator with the supplied
|
||||
* CAS server url prefix.
|
||||
*
|
||||
* @param casServerUrlPrefix the CAS Server URL prefix.
|
||||
*/
|
||||
public Cas20ServiceTicketValidator(final String casServerUrlPrefix) {
|
||||
super(casServerUrlPrefix);
|
||||
this.proxyRetriever = new Cas20ProxyRetriever(casServerUrlPrefix);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the pgtUrl to the list of parameters to pass to the CAS server.
|
||||
*
|
||||
* @param urlParameters the Map containing the existing parameters to send to the server.
|
||||
*/
|
||||
protected final void populateUrlAttributeMap(final Map urlParameters) {
|
||||
urlParameters.put("pgtUrl", encodeUrl(this.proxyCallbackUrl));
|
||||
}
|
||||
|
||||
protected String getUrlSuffix() {
|
||||
return "serviceValidate";
|
||||
}
|
||||
|
||||
protected final Assertion parseResponseFromServer(final String response) throws TicketValidationException {
|
||||
final String error = XmlUtils.getTextForElement(response,
|
||||
"authenticationFailure");
|
||||
|
||||
if (CommonUtils.isNotBlank(error)) {
|
||||
throw new TicketValidationException(error);
|
||||
}
|
||||
|
||||
final String principal = XmlUtils.getTextForElement(response, "user");
|
||||
final String proxyGrantingTicketIou = XmlUtils.getTextForElement(
|
||||
response, "proxyGrantingTicket");
|
||||
final String proxyGrantingTicket = this.proxyGrantingTicketStorage != null ? this.proxyGrantingTicketStorage.retrieve(proxyGrantingTicketIou) : null;
|
||||
|
||||
if (CommonUtils.isEmpty(principal)) {
|
||||
throw new TicketValidationException("No principal was found in the response from the CAS server.");
|
||||
}
|
||||
|
||||
final Assertion assertion;
|
||||
if (CommonUtils.isNotBlank(proxyGrantingTicket)) {
|
||||
final AttributePrincipal attributePrincipal = new AttributePrincipalImpl(principal, proxyGrantingTicket, this.proxyRetriever);
|
||||
assertion = new AssertionImpl(attributePrincipal);
|
||||
} else {
|
||||
assertion = new AssertionImpl(principal);
|
||||
}
|
||||
|
||||
customParseResponse(response, assertion);
|
||||
|
||||
return assertion;
|
||||
}
|
||||
|
||||
/**
|
||||
* Template method if additional custom parsing (such as Proxying) needs to be done.
|
||||
*
|
||||
* @param response the original response from the CAS server.
|
||||
* @param assertion the partially constructed assertion.
|
||||
* @throws TicketValidationException if there is a problem constructing the Assertion.
|
||||
*/
|
||||
protected void customParseResponse(final String response, final Assertion assertion) throws TicketValidationException {
|
||||
// nothing to do
|
||||
}
|
||||
|
||||
public final void setProxyCallbackUrl(final String proxyCallbackUrl) {
|
||||
this.proxyCallbackUrl = proxyCallbackUrl;
|
||||
}
|
||||
|
||||
public final void setProxyGrantingTicketStorage(final ProxyGrantingTicketStorage proxyGrantingTicketStorage) {
|
||||
this.proxyGrantingTicketStorage = proxyGrantingTicketStorage;
|
||||
}
|
||||
|
||||
public final void setProxyRetriever(final ProxyRetriever proxyRetriever) {
|
||||
this.proxyRetriever = proxyRetriever;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* Copyright 2007 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.validation;
|
||||
|
||||
/**
|
||||
* Exception denotes that an invalid proxy chain was sent from the CAS server to the local application.
|
||||
*
|
||||
* @author Scott Battaglia
|
||||
* @version $Revision$ $Date$
|
||||
* @since 3.1
|
||||
*/
|
||||
public final class InvalidProxyChainTicketValidationException extends TicketValidationException {
|
||||
|
||||
/**
|
||||
* Unique Id for Serialization
|
||||
*/
|
||||
private static final long serialVersionUID = -7736653266370691534L;
|
||||
|
||||
/**
|
||||
* Constructs an exception with the supplied message.
|
||||
* @param string the supplied message.
|
||||
*/
|
||||
|
||||
public InvalidProxyChainTicketValidationException(final String string) {
|
||||
super(string);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an exception with the supplied message and chained throwable.
|
||||
* @param string the message.
|
||||
* @param throwable the root exception.
|
||||
*/
|
||||
public InvalidProxyChainTicketValidationException(final String string, final Throwable throwable) {
|
||||
super(string, throwable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an exception with the chained throwable.
|
||||
* @param throwable the root exception.
|
||||
*/
|
||||
public InvalidProxyChainTicketValidationException(final Throwable throwable) {
|
||||
super(throwable);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* Copyright 2007 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.validation;
|
||||
|
||||
import java.beans.PropertyEditorSupport;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.StringReader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.jasig.cas.client.util.CommonUtils;
|
||||
|
||||
/**
|
||||
* Convert a String-formatted list of acceptable proxies to an array.
|
||||
*
|
||||
* @author Scott Battaglia
|
||||
* @version $Revision$ $Date$
|
||||
* @since 3.1
|
||||
*
|
||||
*/
|
||||
public final class ProxyListPropertyEditor extends PropertyEditorSupport {
|
||||
|
||||
public void setAsText(final String text) throws IllegalArgumentException {
|
||||
final BufferedReader reader = new BufferedReader(new StringReader(text));
|
||||
final List proxyChains = new ArrayList();
|
||||
|
||||
try {
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
if (CommonUtils.isNotBlank(line)) {
|
||||
proxyChains.add(line.trim().split(" "));
|
||||
}
|
||||
}
|
||||
} catch (final IOException e) {
|
||||
// ignore this
|
||||
} finally {
|
||||
try {
|
||||
reader.close();
|
||||
} catch (final IOException e) {
|
||||
// nothing to do
|
||||
}
|
||||
}
|
||||
|
||||
setValue(proxyChains);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* Copyright 2007 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.validation;
|
||||
|
||||
import javax.servlet.FilterConfig;
|
||||
|
||||
/**
|
||||
* Implementation of TicketValidationFilter that can instanciate a SAML 1.1 Ticket Validator.
|
||||
* <p>
|
||||
* Deployers can provide the "casServerUrlPrefix" and "tolerance" properties of the Saml11TicketValidator via the
|
||||
* context or filter init parameters.
|
||||
*
|
||||
* @author Scott Battaglia
|
||||
* @version $Revision$ $Date$
|
||||
* @since 3.1
|
||||
*/
|
||||
public class Saml11TicketValidationFilter extends AbstractTicketValidationFilter {
|
||||
|
||||
public Saml11TicketValidationFilter() {
|
||||
setArtifactParameterName("SAMLart");
|
||||
setServiceParameterName("TARGET");
|
||||
}
|
||||
|
||||
protected final TicketValidator getTicketValidator(final FilterConfig filterConfig) {
|
||||
final Saml11TicketValidator validator = new Saml11TicketValidator(getPropertyFromInitParams(filterConfig, "casServerUrlPrefix", null));
|
||||
final String tolerance = getPropertyFromInitParams(filterConfig, "tolerance", "1000");
|
||||
validator.setTolerance(Long.parseLong(tolerance));
|
||||
return validator;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,204 @@
|
|||
/*
|
||||
* Copyright 2007 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.validation;
|
||||
|
||||
import org.jasig.cas.client.authentication.AttributePrincipal;
|
||||
import org.jasig.cas.client.authentication.AttributePrincipalImpl;
|
||||
import org.opensaml.*;
|
||||
|
||||
import java.io.*;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* TicketValidator that can understand validating a SAML artifact. This includes the SOAP request/response.
|
||||
*
|
||||
* @author Scott Battaglia
|
||||
* @version $Revision$ $Date$
|
||||
* @since 3.1
|
||||
*/
|
||||
public final class Saml11TicketValidator extends AbstractUrlBasedTicketValidator {
|
||||
|
||||
/** Time tolerance to allow for time drifting. */
|
||||
private long tolerance = 1000L;
|
||||
|
||||
public Saml11TicketValidator(final String casServerUrlPrefix) {
|
||||
super(casServerUrlPrefix);
|
||||
}
|
||||
|
||||
protected String getUrlSuffix() {
|
||||
return "samlValidate";
|
||||
}
|
||||
|
||||
protected void populateUrlAttributeMap(final Map urlParameters) {
|
||||
final String service = (String) urlParameters.get("service");
|
||||
urlParameters.remove("service");
|
||||
urlParameters.remove("ticket");
|
||||
urlParameters.put("TARGET", service);
|
||||
}
|
||||
|
||||
protected Assertion parseResponseFromServer(final String response) throws TicketValidationException {
|
||||
try {
|
||||
final SAMLResponse samlResponse = new SAMLResponse(new ByteArrayInputStream(response.getBytes()));
|
||||
|
||||
if (!samlResponse.getAssertions().hasNext()) {
|
||||
throw new TicketValidationException("No assertions found.");
|
||||
}
|
||||
|
||||
for (final Iterator iter = samlResponse.getAssertions(); iter.hasNext();) {
|
||||
final SAMLAssertion assertion = (SAMLAssertion) iter.next();
|
||||
|
||||
if (!isValidAssertion(assertion)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
final SAMLAuthenticationStatement authenticationStatement = getSAMLAuthenticationStatement(assertion);
|
||||
|
||||
if (authenticationStatement == null) {
|
||||
throw new TicketValidationException("No AuthentiationStatement found in SAML Assertion.");
|
||||
}
|
||||
final SAMLSubject subject = authenticationStatement.getSubject();
|
||||
|
||||
if (subject == null) {
|
||||
throw new TicketValidationException("No Subject found in SAML Assertion.");
|
||||
}
|
||||
|
||||
final SAMLAttribute[] attributes = getAttributesFor(assertion, subject);
|
||||
|
||||
final Map personAttributes = new HashMap();
|
||||
|
||||
for (int i = 0; i < attributes.length; i++) {
|
||||
final SAMLAttribute samlAttribute = attributes[i];
|
||||
final List values = getValuesFrom(samlAttribute);
|
||||
|
||||
personAttributes.put(samlAttribute.getName(), values.size() == 1 ? values.get(0) : values);
|
||||
}
|
||||
|
||||
final AttributePrincipal principal = new AttributePrincipalImpl(subject.getNameIdentifier().getName(), personAttributes);
|
||||
|
||||
|
||||
final Map authenticationAttributes = new HashMap();
|
||||
authenticationAttributes.put("samlAuthenticationStatement::authMethod", authenticationStatement.getAuthMethod());
|
||||
|
||||
final Assertion casAssertion = new AssertionImpl(principal, authenticationAttributes);
|
||||
return casAssertion;
|
||||
}
|
||||
} catch (final SAMLException e) {
|
||||
throw new TicketValidationException(e);
|
||||
}
|
||||
|
||||
throw new TicketValidationException("No valid assertions from the SAML response found.");
|
||||
}
|
||||
|
||||
private boolean isValidAssertion(final SAMLAssertion assertion) {
|
||||
final Date notBefore = assertion.getNotBefore();
|
||||
final Date notOnOrAfter = assertion.getNotOnOrAfter();
|
||||
|
||||
if (assertion.getNotBefore() == null || assertion.getNotOnOrAfter() == null) {
|
||||
log.debug("Assertion has no bounding dates. Will not process.");
|
||||
return false;
|
||||
}
|
||||
|
||||
final long currentTime = new Date().getTime();
|
||||
|
||||
if (currentTime + tolerance < notBefore.getTime()) {
|
||||
log.debug("skipping assertion that's not yet valid...");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (notOnOrAfter.getTime() <= currentTime - tolerance) {
|
||||
log.debug("skipping expired assertion...");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private SAMLAuthenticationStatement getSAMLAuthenticationStatement(final SAMLAssertion assertion) {
|
||||
for (final Iterator iter = assertion.getStatements(); iter.hasNext();) {
|
||||
final SAMLStatement statement = (SAMLStatement) iter.next();
|
||||
|
||||
if (statement instanceof SAMLAuthenticationStatement) {
|
||||
return (SAMLAuthenticationStatement) statement;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private SAMLAttribute[] getAttributesFor(final SAMLAssertion assertion, final SAMLSubject subject) {
|
||||
final List attributes = new ArrayList();
|
||||
for (final Iterator iter = assertion.getStatements(); iter.hasNext();) {
|
||||
final SAMLStatement statement = (SAMLStatement) iter.next();
|
||||
|
||||
if (statement instanceof SAMLAttributeStatement) {
|
||||
final SAMLAttributeStatement attributeStatement = (SAMLAttributeStatement) statement;
|
||||
// used because SAMLSubject does not implement equals
|
||||
if (subject.getNameIdentifier().getName().equals(attributeStatement.getSubject().getNameIdentifier().getName())) {
|
||||
for (final Iterator iter2 = attributeStatement.getAttributes(); iter2.hasNext();)
|
||||
attributes.add(iter2.next());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (SAMLAttribute[]) attributes.toArray(new SAMLAttribute[attributes.size()]);
|
||||
}
|
||||
|
||||
private List getValuesFrom(final SAMLAttribute attribute) {
|
||||
final List list = new ArrayList();
|
||||
for (final Iterator iter = attribute.getValues(); iter.hasNext();) {
|
||||
list.add(iter.next());
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
protected String retrieveResponseFromServer(final URL validationUrl, final String ticket) {
|
||||
final String MESSAGE_TO_SEND = "<SOAP-ENV:Envelope xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\"><SOAP-ENV:Header/><SOAP-ENV:Body><samlp:Request xmlns:samlp=\"urn:oasis:names:tc:SAML:1.0:protocol\" MajorVersion=\"1\" MinorVersion=\"1\" RequestID=\"_192.168.16.51.1024506224022\" IssueInstant=\"2002-06-19T17:03:44.022Z\">"
|
||||
+ "<samlp:AssertionArtifact>" + ticket
|
||||
+ "</samlp:AssertionArtifact></samlp:Request></SOAP-ENV:Body></SOAP-ENV:Envelope>";
|
||||
|
||||
HttpURLConnection conn = null;
|
||||
|
||||
try {
|
||||
conn = (HttpURLConnection) validationUrl.openConnection();
|
||||
conn.setRequestMethod("POST");
|
||||
conn.setRequestProperty("Content-Length", Integer.toString(MESSAGE_TO_SEND.length()));
|
||||
conn.setRequestProperty("SOAPAction", "http://www.oasis-open.org/committees/security");
|
||||
conn.setUseCaches(false);
|
||||
conn.setDoInput(true);
|
||||
conn.setDoOutput(true);
|
||||
|
||||
final DataOutputStream out = new DataOutputStream(conn.getOutputStream());
|
||||
out.writeBytes(MESSAGE_TO_SEND);
|
||||
out.flush();
|
||||
out.close();
|
||||
|
||||
final BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
|
||||
final StringBuffer buffer = new StringBuffer(256);
|
||||
|
||||
synchronized (buffer) {
|
||||
String line;
|
||||
|
||||
while ((line = in.readLine()) != null) {
|
||||
buffer.append(line);
|
||||
}
|
||||
return buffer.toString();
|
||||
}
|
||||
} catch (final IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
} finally {
|
||||
if (conn != null) {
|
||||
conn.disconnect();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setTolerance(final long tolerance) {
|
||||
this.tolerance = tolerance;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* Copyright 2007 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.validation;
|
||||
|
||||
/**
|
||||
* Generic exception to be thrown when ticket validation fails.
|
||||
*
|
||||
* @author Scott Battaglia
|
||||
* @version $Revision$ $Date$
|
||||
* @since 3.1
|
||||
*/
|
||||
public class TicketValidationException extends Exception {
|
||||
|
||||
/**
|
||||
* Unique Id for Serialization
|
||||
*/
|
||||
private static final long serialVersionUID = -7036248720402711806L;
|
||||
|
||||
/**
|
||||
* Constructs an exception with the supplied message.
|
||||
*
|
||||
* @param string the message
|
||||
*/
|
||||
public TicketValidationException(final String string) {
|
||||
super(string);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an exception with the supplied message and chained throwable.
|
||||
*
|
||||
* @param string the message
|
||||
* @param throwable the original exception
|
||||
*/
|
||||
public TicketValidationException(final String string, final Throwable throwable) {
|
||||
super(string, throwable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an exception with the chained throwable.
|
||||
* @param throwable the original exception.
|
||||
*/
|
||||
public TicketValidationException(final Throwable throwable) {
|
||||
super(throwable);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* Copyright 2007 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.validation;
|
||||
|
||||
/**
|
||||
* Contract for a validator that will confirm the validity of a supplied ticket.
|
||||
* <p>
|
||||
* Validator makes no statement about how to validate the ticket or the format of the ticket (other than that it must be a String).
|
||||
*
|
||||
* @author Scott Battaglia
|
||||
* @version $Revision$ $Date$
|
||||
* @since 3.1
|
||||
*/
|
||||
public interface TicketValidator {
|
||||
|
||||
/**
|
||||
* Attempts to validate a ticket for the provided service.
|
||||
*
|
||||
* @param ticket the ticket to attempt to validate.
|
||||
* @param service the service this ticket is valid for.
|
||||
* @return an assertion from the ticket.
|
||||
* @throws TicketValidationException if the ticket cannot be validated.
|
||||
*
|
||||
*/
|
||||
Assertion validate(String ticket, String service) throws TicketValidationException;
|
||||
}
|
||||
|
|
@ -0,0 +1,106 @@
|
|||
package org.jasig.cas.client;
|
||||
|
||||
|
||||
import java.io.*;
|
||||
import java.net.ServerSocket;
|
||||
import java.net.Socket;
|
||||
|
||||
/**
|
||||
* @author Scott Battaglia
|
||||
* @version $Revision: 11721 $ $Date: 2007-08-09 15:17:44 -0400 (Wed, 09 Aug 2007) $
|
||||
* @since 3.0
|
||||
*/
|
||||
public final class PublicTestHttpServer extends Thread {
|
||||
|
||||
private static PublicTestHttpServer httpServer;
|
||||
|
||||
public byte[] content;
|
||||
|
||||
private byte[] header;
|
||||
|
||||
private int port = 80;
|
||||
|
||||
public String encoding;
|
||||
|
||||
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 {
|
||||
|
||||
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";
|
||||
this.header = header.getBytes("ASCII");
|
||||
|
||||
}
|
||||
|
||||
public static synchronized PublicTestHttpServer instance() {
|
||||
if (httpServer == null) {
|
||||
try {
|
||||
httpServer = new PublicTestHttpServer("test", "ASCII",
|
||||
"text/plain", 8085);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
httpServer.start();
|
||||
Thread.yield();
|
||||
}
|
||||
|
||||
return httpServer;
|
||||
}
|
||||
|
||||
public void run() {
|
||||
|
||||
try {
|
||||
ServerSocket server = new ServerSocket(this.port);
|
||||
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());
|
||||
// read the first line only; that's all we need
|
||||
StringBuffer request = new StringBuffer(80);
|
||||
while (true) {
|
||||
int c = in.read();
|
||||
if (c == '\r' || c == '\n' || c == -1)
|
||||
break;
|
||||
request.append((char) c);
|
||||
}
|
||||
|
||||
if (request.toString().startsWith("STOP")) {
|
||||
connection.close();
|
||||
break;
|
||||
}
|
||||
if (request.toString().indexOf("HTTP/") != -1) {
|
||||
out.write(this.header);
|
||||
}
|
||||
out.write(this.content);
|
||||
out.flush();
|
||||
} // end try
|
||||
catch (IOException e) {
|
||||
// nothing to do with this IOException
|
||||
} finally {
|
||||
if (connection != null)
|
||||
connection.close();
|
||||
}
|
||||
|
||||
} // end while
|
||||
} // end try
|
||||
catch (IOException e) {
|
||||
System.err.println("Could not start server. Port Occupied");
|
||||
}
|
||||
|
||||
} // end run
|
||||
}
|
||||
|
|
@ -0,0 +1,167 @@
|
|||
/*
|
||||
* Copyright 2007 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 junit.framework.TestCase;
|
||||
import org.jasig.cas.client.util.AbstractCasFilter;
|
||||
import org.jasig.cas.client.validation.AssertionImpl;
|
||||
import org.springframework.mock.web.MockFilterConfig;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.mock.web.MockHttpServletResponse;
|
||||
import org.springframework.mock.web.MockHttpSession;
|
||||
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.net.URLEncoder;
|
||||
|
||||
/**
|
||||
* Tests for the AuthenticationFilter.
|
||||
*
|
||||
* @author Scott Battaglia
|
||||
* @version $Revision: 11753 $ $Date: 2007-01-03 13:37:26 -0500 (Wed, 03 Jan 2007) $
|
||||
* @since 3.0
|
||||
*/
|
||||
public final class AuthenticationFilterTests extends TestCase {
|
||||
|
||||
private static final String CAS_SERVICE_URL = "https://localhost:8443/service";
|
||||
|
||||
private static final String CAS_LOGIN_URL = "https://localhost:8443/cas/login";
|
||||
|
||||
private AuthenticationFilter filter;
|
||||
|
||||
protected void setUp() throws Exception {
|
||||
// TODO CAS_SERVICE_URL, false, CAS_LOGIN_URL
|
||||
this.filter = new AuthenticationFilter();
|
||||
final MockFilterConfig config = new MockFilterConfig();
|
||||
config.addInitParameter("casServerLoginUrl", CAS_LOGIN_URL);
|
||||
config.addInitParameter("service", "https://localhost:8443/service");
|
||||
this.filter.init(config);
|
||||
}
|
||||
|
||||
protected void tearDown() throws Exception {
|
||||
this.filter.destroy();
|
||||
}
|
||||
|
||||
public void testRedirect() throws Exception {
|
||||
final MockHttpSession session = new MockHttpSession();
|
||||
final MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
final MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
final FilterChain filterChain = new FilterChain() {
|
||||
|
||||
public void doFilter(ServletRequest arg0, ServletResponse arg1)
|
||||
throws IOException, ServletException {
|
||||
// nothing to do
|
||||
}
|
||||
};
|
||||
|
||||
request.setSession(session);
|
||||
this.filter.doFilter(request, response, filterChain);
|
||||
|
||||
assertEquals(CAS_LOGIN_URL + "?service="
|
||||
+ URLEncoder.encode(CAS_SERVICE_URL, "UTF-8"), response
|
||||
.getRedirectedUrl());
|
||||
}
|
||||
|
||||
public void testRedirectWithQueryString() throws Exception {
|
||||
final MockHttpSession session = new MockHttpSession();
|
||||
final MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
final MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
request.setQueryString("test=12456");
|
||||
request.setRequestURI("/test");
|
||||
request.setSecure(true);
|
||||
final FilterChain filterChain = new FilterChain() {
|
||||
|
||||
public void doFilter(ServletRequest arg0, ServletResponse arg1)
|
||||
throws IOException, ServletException {
|
||||
// nothing to do
|
||||
}
|
||||
};
|
||||
|
||||
request.setSession(session);
|
||||
this.filter = new AuthenticationFilter();
|
||||
|
||||
final MockFilterConfig config = new MockFilterConfig();
|
||||
config.addInitParameter("casServerLoginUrl", CAS_LOGIN_URL);
|
||||
config.addInitParameter("serverName", "localhost:8443");
|
||||
this.filter.init(config);
|
||||
|
||||
this.filter.doFilter(request, response, filterChain);
|
||||
|
||||
assertEquals(CAS_LOGIN_URL
|
||||
+ "?service="
|
||||
+ URLEncoder.encode("https://localhost:8443"
|
||||
+ request.getRequestURI() + "?" + request.getQueryString(),
|
||||
"UTF-8"), response.getRedirectedUrl());
|
||||
}
|
||||
|
||||
public void testAssertion() throws Exception {
|
||||
final MockHttpSession session = new MockHttpSession();
|
||||
final MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
final MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
final FilterChain filterChain = new FilterChain() {
|
||||
|
||||
public void doFilter(ServletRequest arg0, ServletResponse arg1)
|
||||
throws IOException, ServletException {
|
||||
// nothing to do
|
||||
}
|
||||
};
|
||||
|
||||
request.setSession(session);
|
||||
session.setAttribute(AbstractCasFilter.CONST_CAS_ASSERTION,
|
||||
new AssertionImpl("test"));
|
||||
this.filter.doFilter(request, response, filterChain);
|
||||
|
||||
assertNull(response.getRedirectedUrl());
|
||||
}
|
||||
|
||||
public void testRenew() throws Exception {
|
||||
final MockHttpSession session = new MockHttpSession();
|
||||
final MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
final MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
final FilterChain filterChain = new FilterChain() {
|
||||
|
||||
public void doFilter(ServletRequest arg0, ServletResponse arg1)
|
||||
throws IOException, ServletException {
|
||||
// nothing to do
|
||||
}
|
||||
};
|
||||
|
||||
this.filter.setRenew(true);
|
||||
request.setSession(session);
|
||||
this.filter.doFilter(request, response, filterChain);
|
||||
|
||||
assertNotNull(response.getRedirectedUrl());
|
||||
assertTrue(response.getRedirectedUrl().indexOf("renew=true") != -1);
|
||||
}
|
||||
|
||||
public void testGateway() throws Exception {
|
||||
final MockHttpSession session = new MockHttpSession();
|
||||
final MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
final MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
final FilterChain filterChain = new FilterChain() {
|
||||
|
||||
public void doFilter(ServletRequest arg0, ServletResponse arg1)
|
||||
throws IOException, ServletException {
|
||||
// nothing to do
|
||||
}
|
||||
};
|
||||
|
||||
request.setSession(session);
|
||||
this.filter.setRenew(true);
|
||||
this.filter.setGateway(true);
|
||||
this.filter.doFilter(request, response, filterChain);
|
||||
assertNotNull(session.getAttribute(AuthenticationFilter.CONST_CAS_GATEWAY));
|
||||
assertNotNull(response.getRedirectedUrl());
|
||||
|
||||
final MockHttpServletResponse response2 = new MockHttpServletResponse();
|
||||
this.filter.doFilter(request, response2, filterChain);
|
||||
assertNull(session.getAttribute(AuthenticationFilter.CONST_CAS_GATEWAY));
|
||||
assertNull(response2.getRedirectedUrl());
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,91 @@
|
|||
/*
|
||||
* Copyright 2007 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;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* Tests for the CommonUtils.
|
||||
*
|
||||
* @author Scott Battaglia
|
||||
* @version $Revision: 11731 $ $Date: 2007-09-27 11:27:21 -0400 (Wed, 27 Sep 2007) $
|
||||
* @since 3.0
|
||||
*/
|
||||
public final class CommonUtilsTests extends TestCase {
|
||||
|
||||
public void testAssertNotNull() {
|
||||
final String CONST_MESSAGE = "test";
|
||||
CommonUtils.assertNotNull(new Object(), CONST_MESSAGE);
|
||||
try {
|
||||
CommonUtils.assertNotNull(null, CONST_MESSAGE);
|
||||
} catch (IllegalArgumentException e) {
|
||||
assertEquals(CONST_MESSAGE, e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public void testAssertNotEmpty() {
|
||||
final String CONST_MESSAGE = "test";
|
||||
final Collection c = new ArrayList();
|
||||
c.add(new Object());
|
||||
CommonUtils.assertNotEmpty(c, CONST_MESSAGE);
|
||||
try {
|
||||
CommonUtils.assertNotEmpty(new ArrayList(), CONST_MESSAGE);
|
||||
} catch (IllegalArgumentException e) {
|
||||
assertEquals(CONST_MESSAGE, e.getMessage());
|
||||
}
|
||||
|
||||
try {
|
||||
CommonUtils.assertNotEmpty(null, CONST_MESSAGE);
|
||||
} catch (IllegalArgumentException e) {
|
||||
assertEquals(CONST_MESSAGE, e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public void testAssertTrue() {
|
||||
final String CONST_MESSAGE = "test";
|
||||
CommonUtils.assertTrue(true, CONST_MESSAGE);
|
||||
try {
|
||||
CommonUtils.assertTrue(false, CONST_MESSAGE);
|
||||
} catch (IllegalArgumentException e) {
|
||||
assertEquals(CONST_MESSAGE, e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public void testIsEmpty() {
|
||||
assertFalse(CommonUtils.isEmpty("test"));
|
||||
assertFalse(CommonUtils.isEmpty(" test"));
|
||||
assertTrue(CommonUtils.isEmpty(""));
|
||||
assertTrue(CommonUtils.isEmpty(null));
|
||||
assertFalse(CommonUtils.isEmpty(" "));
|
||||
}
|
||||
|
||||
public void testIsNotEmpty() {
|
||||
assertTrue(CommonUtils.isNotEmpty("test"));
|
||||
assertTrue(CommonUtils.isNotEmpty(" test"));
|
||||
assertFalse(CommonUtils.isNotEmpty(""));
|
||||
assertFalse(CommonUtils.isNotEmpty(null));
|
||||
assertTrue(CommonUtils.isNotEmpty(" "));
|
||||
}
|
||||
|
||||
public void testIsBlank() {
|
||||
assertFalse(CommonUtils.isBlank("test"));
|
||||
assertFalse(CommonUtils.isBlank(" test"));
|
||||
assertTrue(CommonUtils.isBlank(""));
|
||||
assertTrue(CommonUtils.isBlank(null));
|
||||
assertTrue(CommonUtils.isBlank(" "));
|
||||
}
|
||||
|
||||
public void testIsNotBlank() {
|
||||
assertTrue(CommonUtils.isNotBlank("test"));
|
||||
assertTrue(CommonUtils.isNotBlank(" test"));
|
||||
assertFalse(CommonUtils.isNotBlank(""));
|
||||
assertFalse(CommonUtils.isNotBlank(null));
|
||||
assertFalse(CommonUtils.isNotBlank(" "));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* Copyright 2007 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;
|
||||
import org.jasig.cas.client.validation.AssertionImpl;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.mock.web.MockHttpServletResponse;
|
||||
import org.springframework.mock.web.MockHttpSession;
|
||||
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Tests for the HttpServletRequestWrapperFilter.
|
||||
*
|
||||
* @author Scott Battaglia
|
||||
* @version $Revision: 11742 $ $Date: 2007-10-05 14:03:58 -0400 (Thu, 05 Oct 2007) $
|
||||
* @since 3.0
|
||||
*/
|
||||
|
||||
public final class HttpServletRequestWrapperFilterTests extends TestCase {
|
||||
|
||||
private HttpServletRequestWrapperFilter filter = new HttpServletRequestWrapperFilter();
|
||||
|
||||
protected HttpServletRequest mockRequest;
|
||||
|
||||
protected void setUp() throws Exception {
|
||||
this.filter.init(null);
|
||||
this.filter.destroy();
|
||||
}
|
||||
|
||||
public void testWrappedRequest() throws Exception {
|
||||
final MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
final MockHttpSession session = new MockHttpSession();
|
||||
final FilterChain filterChain = new FilterChain() {
|
||||
|
||||
public void doFilter(ServletRequest request,
|
||||
ServletResponse response) throws IOException, ServletException {
|
||||
HttpServletRequestWrapperFilterTests.this.mockRequest = (HttpServletRequest) request;
|
||||
}
|
||||
|
||||
};
|
||||
session.setAttribute(AbstractCasFilter.CONST_CAS_ASSERTION,
|
||||
new AssertionImpl("test"));
|
||||
|
||||
request.setSession(session);
|
||||
|
||||
this.filter.doFilter(request, new MockHttpServletResponse(),
|
||||
filterChain);
|
||||
assertEquals("test", this.mockRequest.getRemoteUser());
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
* Copyright 2007 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.validation;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
/**
|
||||
* Base class for all TicketValidator tests to inherit from.
|
||||
*
|
||||
* @author Scott Battaglia
|
||||
* @version $Revision: 11731 $ $Date: 2007-09-27 11:27:21 -0400 (Wed, 27 Sep 2007) $
|
||||
* @since 3.0
|
||||
*/
|
||||
public abstract class AbstractTicketValidatorTests extends TestCase {
|
||||
|
||||
protected static final String CONST_CAS_SERVER_URL = "http://localhost:8085/";
|
||||
|
||||
protected static final String CONST_USERNAME = "username";
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* Copyright 2007 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.validation;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
import org.jasig.cas.client.authentication.AttributePrincipal;
|
||||
import org.jasig.cas.client.authentication.AttributePrincipalImpl;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Test cases for the {@link AssertionImpl}.
|
||||
*
|
||||
* @author Scott Battaglia
|
||||
* @version $Revision: 11737 $ $Date: 2007-10-03 09:14:02 -0400 (Tue, 03 Oct 2007) $
|
||||
* @since 3.0
|
||||
*/
|
||||
public final class AssertionImplTests extends TestCase {
|
||||
|
||||
private static final AttributePrincipal CONST_PRINCIPAL = new AttributePrincipalImpl("test");
|
||||
|
||||
private static final Map CONST_ATTRIBUTES = new HashMap();
|
||||
|
||||
static {
|
||||
CONST_ATTRIBUTES.put("test", "test");
|
||||
}
|
||||
|
||||
public void testPrincipalConstructor() {
|
||||
final Assertion assertion = new AssertionImpl(CONST_PRINCIPAL);
|
||||
|
||||
assertEquals(CONST_PRINCIPAL, assertion.getPrincipal());
|
||||
assertTrue(assertion.getAttributes().isEmpty());
|
||||
assertNull(assertion.getPrincipal().getProxyTicketFor("test"));
|
||||
}
|
||||
|
||||
public void testCompleteConstructor() {
|
||||
final Assertion assertion = new AssertionImpl(CONST_PRINCIPAL,
|
||||
CONST_ATTRIBUTES);
|
||||
|
||||
assertEquals(CONST_PRINCIPAL, assertion.getPrincipal());
|
||||
assertEquals(CONST_ATTRIBUTES, assertion.getAttributes());
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* Copyright 2007 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.validation;
|
||||
|
||||
|
||||
import org.jasig.cas.client.PublicTestHttpServer;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
|
||||
/**
|
||||
* Test cases for the {@link Cas10TicketValidator}.
|
||||
*
|
||||
* @author Scott Battaglia
|
||||
* @version $Revision: 11731 $ $Date: 2007-09-27 11:27:21 -0400 (Wed, 27 Sep 2007) $
|
||||
* @since 3.0
|
||||
*/
|
||||
public final class Cas10TicketValidatorTests extends AbstractTicketValidatorTests {
|
||||
|
||||
private Cas10TicketValidator ticketValidator;
|
||||
|
||||
public Cas10TicketValidatorTests() {
|
||||
super();
|
||||
}
|
||||
|
||||
protected void setUp() throws Exception {
|
||||
this.ticketValidator = new Cas10TicketValidator(CONST_CAS_SERVER_URL);
|
||||
}
|
||||
|
||||
public void testNoResponse() throws Exception {
|
||||
PublicTestHttpServer.instance().content = "no\n\n"
|
||||
.getBytes(PublicTestHttpServer.instance().encoding);
|
||||
try {
|
||||
this.ticketValidator.validate("testTicket",
|
||||
"myService");
|
||||
fail("ValidationException expected.");
|
||||
} catch (final TicketValidationException e) {
|
||||
// expected
|
||||
}
|
||||
}
|
||||
|
||||
public void testYesResponse() throws TicketValidationException,
|
||||
UnsupportedEncodingException {
|
||||
PublicTestHttpServer.instance().content = "yes\nusername\n\n"
|
||||
.getBytes(PublicTestHttpServer.instance().encoding);
|
||||
final Assertion assertion = this.ticketValidator.validate("testTicket",
|
||||
"myService");
|
||||
assertEquals(CONST_USERNAME, assertion.getPrincipal().getName());
|
||||
}
|
||||
|
||||
public void testBadResponse() throws UnsupportedEncodingException {
|
||||
PublicTestHttpServer.instance().content = "falalala\n\n"
|
||||
.getBytes(PublicTestHttpServer.instance().encoding);
|
||||
try {
|
||||
this.ticketValidator.validate("testTicket",
|
||||
"myService");
|
||||
fail("ValidationException expected.");
|
||||
} catch (final TicketValidationException e) {
|
||||
// expected
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,106 @@
|
|||
/*
|
||||
* Copyright 2007 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.validation;
|
||||
|
||||
import org.jasig.cas.client.PublicTestHttpServer;
|
||||
import org.jasig.cas.client.proxy.ProxyGrantingTicketStorage;
|
||||
import org.jasig.cas.client.proxy.ProxyGrantingTicketStorageImpl;
|
||||
import org.jasig.cas.client.proxy.ProxyRetriever;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.support.ClassPathXmlApplicationContext;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Test cases for the {@link Cas20ProxyTicketValidator}.
|
||||
*
|
||||
* @author Scott Battaglia
|
||||
* @version $Revision: 11737 $ $Date: 2007-10-03 09:14:02 -0400 (Tue, 03 Oct 2007) $
|
||||
* @since 3.0
|
||||
*/
|
||||
public final class Cas20ProxyTicketValidatorTests extends
|
||||
AbstractTicketValidatorTests {
|
||||
|
||||
private Cas20ProxyTicketValidator ticketValidator;
|
||||
|
||||
public Cas20ProxyTicketValidatorTests() {
|
||||
super();
|
||||
}
|
||||
|
||||
protected void setUp() throws Exception {
|
||||
final List list = new ArrayList();
|
||||
list.add(new String[] {"proxy1", "proxy2", "proxy3"});
|
||||
|
||||
this.ticketValidator = new Cas20ProxyTicketValidator(CONST_CAS_SERVER_URL);
|
||||
this.ticketValidator.setRenew(true);
|
||||
this.ticketValidator.setProxyCallbackUrl("test");
|
||||
this.ticketValidator.setProxyGrantingTicketStorage(getProxyGrantingTicketStorage());
|
||||
this.ticketValidator.setProxyRetriever(getProxyRetriever());
|
||||
this.ticketValidator.setAllowedProxyChains(list);
|
||||
}
|
||||
|
||||
private ProxyGrantingTicketStorage getProxyGrantingTicketStorage() {
|
||||
final ProxyGrantingTicketStorageImpl proxyGrantingTicketStorageImpl = new ProxyGrantingTicketStorageImpl();
|
||||
|
||||
return proxyGrantingTicketStorageImpl;
|
||||
}
|
||||
|
||||
private ProxyRetriever getProxyRetriever() {
|
||||
final ProxyRetriever proxyRetriever = new ProxyRetriever() {
|
||||
|
||||
public String getProxyTicketIdFor(String proxyGrantingTicketId, String targetService) {
|
||||
return "test";
|
||||
}
|
||||
};
|
||||
|
||||
return proxyRetriever;
|
||||
}
|
||||
|
||||
public void testProxyChainWithValidProxy() throws TicketValidationException,
|
||||
UnsupportedEncodingException {
|
||||
final String USERNAME = "username";
|
||||
final String RESPONSE = "<cas:serviceResponse xmlns:cas='http://www.yale.edu/tp/cas'><cas:authenticationSuccess><cas:user>username</cas:user><cas:proxyGrantingTicket>PGTIOU-84678-8a9d...</cas:proxyGrantingTicket><cas:proxies><cas:proxy>proxy1</cas:proxy><cas:proxy>proxy2</cas:proxy><cas:proxy>proxy3</cas:proxy></cas:proxies></cas:authenticationSuccess></cas:serviceResponse>";
|
||||
PublicTestHttpServer.instance().content = RESPONSE
|
||||
.getBytes(PublicTestHttpServer.instance().encoding);
|
||||
|
||||
final Assertion assertion = this.ticketValidator.validate("test",
|
||||
"test");
|
||||
assertEquals(USERNAME, assertion.getPrincipal().getName());
|
||||
}
|
||||
|
||||
public void testProxyChainWithInvalidProxy() throws TicketValidationException,
|
||||
UnsupportedEncodingException {
|
||||
final String RESPONSE = "<cas:serviceResponse xmlns:cas='http://www.yale.edu/tp/cas'><cas:authenticationSuccess><cas:user>username</cas:user><cas:proxyGrantingTicket>PGTIOU-84678-8a9d...</cas:proxyGrantingTicket><cas:proxies><cas:proxy>proxy7</cas:proxy><cas:proxy>proxy2</cas:proxy><cas:proxy>proxy3</cas:proxy></cas:proxies></cas:authenticationSuccess></cas:serviceResponse>";
|
||||
PublicTestHttpServer.instance().content = RESPONSE
|
||||
.getBytes(PublicTestHttpServer.instance().encoding);
|
||||
|
||||
try {
|
||||
this.ticketValidator.validate("test", "test");
|
||||
fail("Invalid proxy chain");
|
||||
} catch (InvalidProxyChainTicketValidationException e) {
|
||||
// expected
|
||||
}
|
||||
}
|
||||
|
||||
public void testConstructionFromSpringBean() throws TicketValidationException,
|
||||
UnsupportedEncodingException {
|
||||
final ApplicationContext context = new ClassPathXmlApplicationContext("classpath:cas20ProxyTicketValidator.xml");
|
||||
final Cas20ProxyTicketValidator v = (Cas20ProxyTicketValidator) context.getBean("proxyTicketValidator");
|
||||
final Cas20ProxyTicketValidator v2 = (Cas20ProxyTicketValidator) context.getBean("proxyTicketValidatorWithAllowAnyProxy");
|
||||
|
||||
final String USERNAME = "username";
|
||||
final String RESPONSE = "<cas:serviceResponse xmlns:cas='http://www.yale.edu/tp/cas'><cas:authenticationSuccess><cas:user>username</cas:user><cas:proxyGrantingTicket>PGTIOU-84678-8a9d...</cas:proxyGrantingTicket><cas:proxies><cas:proxy>proxy1</cas:proxy><cas:proxy>proxy2</cas:proxy><cas:proxy>proxy3</cas:proxy></cas:proxies></cas:authenticationSuccess></cas:serviceResponse>";
|
||||
PublicTestHttpServer.instance().content = RESPONSE
|
||||
.getBytes(PublicTestHttpServer.instance().encoding);
|
||||
|
||||
final Assertion assertion = v.validate("test",
|
||||
"test");
|
||||
assertEquals(USERNAME, assertion.getPrincipal().getName());
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,123 @@
|
|||
/*
|
||||
* Copyright 2007 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.validation;
|
||||
|
||||
|
||||
import org.jasig.cas.client.PublicTestHttpServer;
|
||||
import org.jasig.cas.client.proxy.ProxyGrantingTicketStorage;
|
||||
import org.jasig.cas.client.proxy.ProxyGrantingTicketStorageImpl;
|
||||
import org.jasig.cas.client.proxy.ProxyRetriever;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
|
||||
/**
|
||||
* Test cases for the {@link Cas20ServiceTicketValidator}.
|
||||
*
|
||||
* @author Scott Battaglia
|
||||
* @version $Revision: 11737 $ $Date: 2007-10-03 09:14:02 -0400 (Tue, 03 Oct 2007) $
|
||||
* @since 3.0
|
||||
*/
|
||||
public final class Cas20ServiceTicketValidatorTests extends
|
||||
AbstractTicketValidatorTests {
|
||||
|
||||
private Cas20ServiceTicketValidator ticketValidator;
|
||||
|
||||
private ProxyGrantingTicketStorage proxyGrantingTicketStorage;
|
||||
|
||||
public Cas20ServiceTicketValidatorTests() {
|
||||
super();
|
||||
}
|
||||
|
||||
public Cas20ServiceTicketValidatorTests(Cas20ServiceTicketValidator ticketValidator) {
|
||||
this.ticketValidator = ticketValidator;
|
||||
}
|
||||
|
||||
protected void setUp() throws Exception {
|
||||
this.proxyGrantingTicketStorage = getProxyGrantingTicketStorage();
|
||||
this.ticketValidator = new Cas20ServiceTicketValidator(CONST_CAS_SERVER_URL);
|
||||
this.ticketValidator.setProxyCallbackUrl("test");
|
||||
this.ticketValidator.setProxyGrantingTicketStorage(getProxyGrantingTicketStorage());
|
||||
this.ticketValidator.setProxyRetriever(getProxyRetriever());
|
||||
this.ticketValidator.setRenew(true);
|
||||
}
|
||||
|
||||
private ProxyGrantingTicketStorage getProxyGrantingTicketStorage() {
|
||||
final ProxyGrantingTicketStorageImpl proxyGrantingTicketStorageImpl = new ProxyGrantingTicketStorageImpl();
|
||||
|
||||
return proxyGrantingTicketStorageImpl;
|
||||
}
|
||||
|
||||
private ProxyRetriever getProxyRetriever() {
|
||||
final ProxyRetriever proxyRetriever = new ProxyRetriever() {
|
||||
|
||||
public String getProxyTicketIdFor(String proxyGrantingTicketId, String targetService) {
|
||||
return "test";
|
||||
}
|
||||
};
|
||||
|
||||
return proxyRetriever;
|
||||
}
|
||||
|
||||
public void testNoResponse() throws UnsupportedEncodingException {
|
||||
final String RESPONSE = "<cas:serviceResponse xmlns:cas='http://www.yale.edu/tp/cas'><cas:authenticationFailure code=\"INVALID_TICKET\">Ticket ST-1856339-aA5Yuvrxzpv8Tau1cYQ7 not recognized</cas:authenticationFailure></cas:serviceResponse>";
|
||||
PublicTestHttpServer.instance().content = RESPONSE
|
||||
.getBytes(PublicTestHttpServer.instance().encoding);
|
||||
try {
|
||||
this.ticketValidator.validate("test", "test");
|
||||
fail("ValidationException expected due to 'no' response");
|
||||
} catch (final TicketValidationException e) {
|
||||
// expected
|
||||
}
|
||||
}
|
||||
|
||||
public void testYesResponseButNoPgt() throws TicketValidationException,
|
||||
UnsupportedEncodingException {
|
||||
final String USERNAME = "username";
|
||||
final String RESPONSE = "<cas:serviceResponse xmlns:cas='http://www.yale.edu/tp/cas'><cas:authenticationSuccess><cas:user>"
|
||||
+ USERNAME
|
||||
+ "</cas:user></cas:authenticationSuccess></cas:serviceResponse>";
|
||||
PublicTestHttpServer.instance().content = RESPONSE
|
||||
.getBytes(PublicTestHttpServer.instance().encoding);
|
||||
|
||||
final Assertion assertion = this.ticketValidator.validate("test",
|
||||
"test");
|
||||
assertEquals(USERNAME, assertion.getPrincipal().getName());
|
||||
}
|
||||
|
||||
public void testYesResponseWithPgt() throws TicketValidationException,
|
||||
UnsupportedEncodingException {
|
||||
final String USERNAME = "username";
|
||||
final String PGTIOU = "testPgtIou";
|
||||
final String PGT = "test";
|
||||
final String RESPONSE = "<cas:serviceResponse xmlns:cas='http://www.yale.edu/tp/cas'><cas:authenticationSuccess><cas:user>"
|
||||
+ USERNAME
|
||||
+ "</cas:user><cas:proxyGrantingTicket>"
|
||||
+ PGTIOU
|
||||
+ "</cas:proxyGrantingTicket></cas:authenticationSuccess></cas:serviceResponse>";
|
||||
|
||||
PublicTestHttpServer.instance().content = RESPONSE
|
||||
.getBytes(PublicTestHttpServer.instance().encoding);
|
||||
|
||||
this.proxyGrantingTicketStorage.save(PGTIOU, PGT);
|
||||
|
||||
final Assertion assertion = this.ticketValidator.validate("test",
|
||||
"test");
|
||||
assertEquals(USERNAME, assertion.getPrincipal().getName());
|
||||
// assertEquals(PGT, assertion.getProxyGrantingTicketId());
|
||||
}
|
||||
|
||||
public void testInvalidResponse() throws Exception {
|
||||
final String RESPONSE = "<root />";
|
||||
PublicTestHttpServer.instance().content = RESPONSE
|
||||
.getBytes(PublicTestHttpServer.instance().encoding);
|
||||
try {
|
||||
this.ticketValidator.validate("test", "test");
|
||||
fail("ValidationException expected due to invalid response.");
|
||||
} catch (final TicketValidationException e) {
|
||||
// expected
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:p="http://www.springframework.org/schema/p"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
|
||||
|
||||
<bean id="proxyTicketValidator"
|
||||
class="org.jasig.cas.client.validation.Cas20ProxyTicketValidator">
|
||||
<constructor-arg index="0" value="http://localhost:8085/" />
|
||||
<property name="allowedProxyChains">
|
||||
<value>
|
||||
test test2 test3 test4 test5
|
||||
mytest mytest1 mytest2 mytest3
|
||||
proxy1 proxy2 proxy3
|
||||
</value>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<bean id="proxyTicketValidatorWithAllowAnyProxy"
|
||||
class="org.jasig.cas.client.validation.Cas20ProxyTicketValidator"
|
||||
p:acceptAnyProxy="true">
|
||||
<constructor-arg index="0" value="http://localhost:8085/" />
|
||||
</bean>
|
||||
</beans>
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
License for Use
|
||||
|
||||
Copyright (c) 2007, JA-SIG, Inc.
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the name of the JA-SIG, Inc. nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
|
@ -0,0 +1,126 @@
|
|||
<project>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.jasig.cas</groupId>
|
||||
<version>3.1-RC3</version>
|
||||
<artifactId>cas-client</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
<name>JA-SIG CAS Client for Java</name>
|
||||
<description>JA-SIG CAS Client for Java is the integration point for applications that want to speak with a CAS
|
||||
server, either via the CAS 1.0 or CAS 2.0 protocol.
|
||||
</description>
|
||||
<url>http://www.ja-sig.org/products/cas/</url>
|
||||
<issueManagement>
|
||||
<system>JIRA</system>
|
||||
<url>http://www.ja-sig.org/issues</url>
|
||||
</issueManagement>
|
||||
<inceptionYear>2006</inceptionYear>
|
||||
<mailingLists>
|
||||
<mailingList>
|
||||
<name>CAS Community Discussion List</name>
|
||||
<subscribe>http://tp.its.yale.edu/mailman/listinfo/cas</subscribe>
|
||||
<unsubscribe>http://tp.its.yale.edu/mailman/listinfo/cas</unsubscribe>
|
||||
<post>cas@tp.its.yale.edu</post>
|
||||
<archive>http://tp.its.yale.edu/pipermail/cas/</archive>
|
||||
<otherArchives>
|
||||
<otherArchive>http://news.gmane.org/gmane.comp.java.jasig.cas.user</otherArchive>
|
||||
</otherArchives>
|
||||
</mailingList>
|
||||
<mailingList>
|
||||
<name>CAS Developers Discussion List</name>
|
||||
<subscribe>http://tp.its.yale.edu/mailman/listinfo/cas-dev</subscribe>
|
||||
<unsubscribe>http://tp.its.yale.edu/mailman/listinfo/cas-dev</unsubscribe>
|
||||
<post>cas-dev@tp.its.yale.edu</post>
|
||||
<archive>http://tp.its.yale.edu/pipermail/cas-dev/</archive>
|
||||
<otherArchives>
|
||||
<otherArchive>http://news.gmane.org/gmane.comp.java.jasig.cas.devel</otherArchive>
|
||||
</otherArchives>
|
||||
</mailingList>
|
||||
</mailingLists>
|
||||
<developers>
|
||||
<developer>
|
||||
<id>battags</id>
|
||||
<name>Scott Battaglia</name>
|
||||
<email>scott_battaglia@rutgers.edu</email>
|
||||
<url>http://www.scottbattaglia.com</url>
|
||||
<organization>Rutgers, the State University of New Jersey</organization>
|
||||
<organizationUrl>http://www.rutgers.edu</organizationUrl>
|
||||
<roles>
|
||||
<role>Project Admin</role>
|
||||
<role>Developer</role>
|
||||
</roles>
|
||||
<timezone>-5</timezone>
|
||||
</developer>
|
||||
</developers>
|
||||
<licenses>
|
||||
<license>
|
||||
<name>JA-SIG License for Use</name>
|
||||
<url>http://www.ja-sig.org/products/cas/overview/license/</url>
|
||||
<distribution>repo</distribution>
|
||||
</license>
|
||||
</licenses>
|
||||
<organization>
|
||||
<name>JA-SIG</name>
|
||||
<url>http://www.ja-sig.org</url>
|
||||
</organization>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-assembly-plugin</artifactId>
|
||||
<version>2.2-beta-1</version>
|
||||
<configuration>
|
||||
<descriptors>
|
||||
<descriptor>${basedir}/assembly.xml</descriptor>
|
||||
</descriptors>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>3.8.1</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-logging</groupId>
|
||||
<artifactId>commons-logging</artifactId>
|
||||
<version>1.1</version>
|
||||
<scope>compile</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>log4j</groupId>
|
||||
<artifactId>log4j</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>logkit</groupId>
|
||||
<artifactId>logkit</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>avalon-framework</groupId>
|
||||
<artifactId>avalon-framework</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.servlet</groupId>
|
||||
<artifactId>servlet-api</artifactId>
|
||||
<version>2.4</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>jasig</id>
|
||||
<name>JA-SIG Maven Repository</name>
|
||||
<url>http://developer.ja-sig.org/maven2/</url>
|
||||
<layout>default</layout>
|
||||
</repository>
|
||||
</repositories>
|
||||
<modules>
|
||||
<module>cas-client-core</module>
|
||||
</modules>
|
||||
</project>
|
||||
Loading…
Reference in New Issue