diff --git a/.classpath b/.classpath
new file mode 100644
index 0000000..7ab140e
--- /dev/null
+++ b/.classpath
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/.project b/.project
new file mode 100644
index 0000000..f5db6d1
--- /dev/null
+++ b/.project
@@ -0,0 +1,17 @@
+
+
+ java-client
+
+
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+
+
+
+ org.eclipse.jdt.core.javanature
+
+
diff --git a/assembly.xml b/assembly.xml
new file mode 100644
index 0000000..d668de7
--- /dev/null
+++ b/assembly.xml
@@ -0,0 +1,39 @@
+
+ dist
+ false
+
+ tar.gz
+ zip
+
+
+
+
+ org.jasig.cas:cas-client-core
+ org.jasig.cas:cas-client-uportal
+
+
+
+ ${artifactId}/src
+
+ src
+ README*
+ LICENSE*
+ NOTICE*
+ pom.xml
+
+
+
+ bin
+ true
+ false
+
+ target/*.jar
+
+
+ *uportal*.jar
+ *spring-mock*.jar
+
+
+
+
+
\ No newline at end of file
diff --git a/build.bat b/build.bat
new file mode 100644
index 0000000..e2663e0
--- /dev/null
+++ b/build.bat
@@ -0,0 +1 @@
+@mvn clean package assembly:assembly -Ddescriptor=assembly.xml
\ No newline at end of file
diff --git a/cas-client-core/.classpath b/cas-client-core/.classpath
new file mode 100644
index 0000000..6bc534a
--- /dev/null
+++ b/cas-client-core/.classpath
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/cas-client-core/.cvsignore b/cas-client-core/.cvsignore
new file mode 100644
index 0000000..eb5a316
--- /dev/null
+++ b/cas-client-core/.cvsignore
@@ -0,0 +1 @@
+target
diff --git a/cas-client-core/.project b/cas-client-core/.project
new file mode 100644
index 0000000..6581b2e
--- /dev/null
+++ b/cas-client-core/.project
@@ -0,0 +1,15 @@
+
+ cas-client-core
+ 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.
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+
+
+ org.eclipse.jdt.core.javanature
+
+
\ No newline at end of file
diff --git a/cas-client-core/.settings/org.eclipse.jdt.core.prefs b/cas-client-core/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000..57e31ff
--- /dev/null
+++ b/cas-client-core/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,5 @@
+#Mon Aug 07 13:41:21 EDT 2006
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.4
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.source=1.4
+org.eclipse.jdt.core.compiler.compliance=1.4
diff --git a/cas-client-core/LICENSE.txt b/cas-client-core/LICENSE.txt
new file mode 100644
index 0000000..30c8573
--- /dev/null
+++ b/cas-client-core/LICENSE.txt
@@ -0,0 +1,29 @@
+License for Use
+
+Copyright (c) 2000 The JA-SIG Collaborative. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. 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.
+
+ 3. Redistributions of any form whatsoever must retain the following
+ acknowledgment:
+ "This product includes software developed by the JA-SIG Collaborative
+ (http://www.ja-sig.org/)."
+
+This software is provided by the JA-SIG collaborative "as is" and any expressed
+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 JA-SIG collaborative or its 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.
\ No newline at end of file
diff --git a/cas-client-core/README.txt b/cas-client-core/README.txt
new file mode 100644
index 0000000..f5cd476
--- /dev/null
+++ b/cas-client-core/README.txt
@@ -0,0 +1,28 @@
+CENTRAL AUTHENTICATION SERVICE (CAS)
+--------------------------------------------------------------------
+http://www.ja-sig.org/products/cas/
+
+1. INTRODUCTION
+
+The Central Authentication Service (CAS) is the standard mechanism by which web
+applications should authenticate users. Any custom applications written benefit
+from using CAS.
+
+Note that CAS provides authentication; that is, it determines that your users
+are who they say they are. CAS should not be viewed as an access-control system;
+in particular, providers of applications that grant access to anyone who
+possesses a NetID should understand that loose affiliates of an organization may
+be granted NetIDs.
+
+The JA-SIG CAS Client for Java is a support library for Java applications to communicate
+with the CAS server.
+
+2. RELEASE INFO
+
+CAS requires J2SE 1.4 and J2EE1.3.
+
+Release conents:
+* "src/main/java" contains the Java source files for the framework
+* "src/test/java" contains the Java source files for CAS's test suite
+
+
diff --git a/cas-client-core/cas-client-core.iml b/cas-client-core/cas-client-core.iml
new file mode 100644
index 0000000..fc4fe0c
--- /dev/null
+++ b/cas-client-core/cas-client-core.iml
@@ -0,0 +1,155 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/cas-client-core/pom.xml b/cas-client-core/pom.xml
new file mode 100644
index 0000000..47eac6d
--- /dev/null
+++ b/cas-client-core/pom.xml
@@ -0,0 +1,132 @@
+
+
+ org.jasig.cas
+ 3.0-SNAPSHOT
+ cas-client
+
+ 4.0.0
+ org.jasig.cas
+ cas-client-core
+ jar
+ JA-SIG CAS Client for Java - Core
+ 3.0-SNAPSHOT
+
+
+ src/main/java
+ src/test/java
+
+
+ src/test/resources
+ false
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+ 1.4
+ 1.4
+
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+
+
+ **/*Tests*
+
+
+
+
+ org.apache.maven.plugins
+ maven-clover-plugin
+
+ ${basedir}/src/test/clover/clover.license
+
+
+
+ pre-site
+
+ instrument
+
+
+
+
+
+
+
+
+
+ commons-httpclient
+ commons-httpclient
+ 3.0.1
+ compile
+
+
+
+ commons-httpclient
+ commons-httpclient-contrib
+ 3.0
+ compile
+
+
+
+ org.springframework
+ spring-web
+ 2.0-rc2
+ compile
+
+
+
+ org.springframework
+ spring-context
+ 2.0-rc2
+ compile
+
+
+
+ org.springframework
+ spring-mock
+ 2.0-rc2
+ compile
+
+
+
+ false
+
+
+ org.apache.maven.plugins
+ maven-clover-plugin
+
+ ${basedir}/src/test/clover/clover.license
+
+
+
+ org.apache.maven.plugins
+ maven-checkstyle-plugin
+
+
+ org.apache.maven.plugins
+ maven-javadoc-plugin
+
+ 128m
+ 512m
+
+
+
+ org.apache.maven.plugins
+ maven-jxr-plugin
+
+
+ org.apache.maven.plugins
+ maven-surefire-report-plugin
+
+
+ org.codehaus.mojo
+ jdepend-maven-plugin
+
+
+
+
diff --git a/cas-client-core/settings.xml b/cas-client-core/settings.xml
new file mode 100644
index 0000000..e3e8e4a
--- /dev/null
+++ b/cas-client-core/settings.xml
@@ -0,0 +1,8 @@
+
+
+ central
+ JA-SIG Maven Repository
+ http://developer.ja-sig.org/maven/
+ jasig
+
+
\ No newline at end of file
diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/authorization/AuthorizationException.java b/cas-client-core/src/main/java/org/jasig/cas/client/authorization/AuthorizationException.java
new file mode 100644
index 0000000..5adc35e
--- /dev/null
+++ b/cas-client-core/src/main/java/org/jasig/cas/client/authorization/AuthorizationException.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2006 The JA-SIG Collaborative. All rights reserved. See license
+ * distributed with this file and available online at
+ * http://www.uportal.org/license.html
+ */
+package org.jasig.cas.client.authorization;
+
+/**
+ * Exception to be thrown if the user is not authorized to use the system.
+ *
+ * @author Scott Battaglia
+ * @version $Revision$ $Date$
+ * @since 3.0
+ */
+public class AuthorizationException extends RuntimeException {
+
+ /**
+ * Unique ID for serialization.
+ */
+ private static final long serialVersionUID = 5912038088650643442L;
+
+ public AuthorizationException() {
+ super();
+ }
+
+ public AuthorizationException(String arg0, Throwable arg1) {
+ super(arg0, arg1);
+ }
+
+ public AuthorizationException(String arg0) {
+ super(arg0);
+ }
+
+ public AuthorizationException(Throwable arg0) {
+ super(arg0);
+ }
+}
diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/authorization/CasAuthorizedDecider.java b/cas-client-core/src/main/java/org/jasig/cas/client/authorization/CasAuthorizedDecider.java
new file mode 100644
index 0000000..1c944fe
--- /dev/null
+++ b/cas-client-core/src/main/java/org/jasig/cas/client/authorization/CasAuthorizedDecider.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2006 The JA-SIG Collaborative. All rights reserved. See license
+ * distributed with this file and available online at
+ * http://www.uportal.org/license.html
+ */
+package org.jasig.cas.client.authorization;
+
+import org.jasig.cas.authentication.principal.Principal;
+
+/**
+ * Simple interface for determining whether a Principal is authorized to use the
+ * application or not.
+ *
+ * @author Scott Battaglia
+ * @version $Revision$ $Date$
+ * @since 3.0
+ */
+public interface CasAuthorizedDecider {
+
+ /**
+ * Determines whether someone can use the system or not.
+ *
+ * @param principal the person we are checking
+ * @return true if authorized, false otherwise.
+ */
+ boolean isAuthorizedToUseApplication(final Principal principal);
+}
diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/authorization/DefaultCasAuthorizedDeciderImpl.java b/cas-client-core/src/main/java/org/jasig/cas/client/authorization/DefaultCasAuthorizedDeciderImpl.java
new file mode 100644
index 0000000..fd20073
--- /dev/null
+++ b/cas-client-core/src/main/java/org/jasig/cas/client/authorization/DefaultCasAuthorizedDeciderImpl.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2006 The JA-SIG Collaborative. All rights reserved. See license
+ * distributed with this file and available online at
+ * http://www.uportal.org/license.html
+ */
+package org.jasig.cas.client.authorization;
+
+import org.jasig.cas.authentication.principal.Principal;
+import org.jasig.cas.client.util.CommonUtils;
+
+import java.util.List;
+
+/**
+ * Default implementation of the CasAuthorizedDecider that delegates to a list
+ * to check if someone is authorized.
+ *
+ * @author Scott Battaglia
+ * @version $Revision$ $Date$
+ * @since 3.0
+ */
+public final class DefaultCasAuthorizedDeciderImpl implements
+ CasAuthorizedDecider {
+
+ /** The list of users authorized to use the system. */
+ private List users;
+
+ public boolean isAuthorizedToUseApplication(final Principal principal) {
+ return this.users.contains(principal.getId());
+ }
+
+ public void init() {
+ CommonUtils.assertNotEmpty(this.users, "users cannot be empty.");
+ }
+
+ public void setUsers(final List users) {
+ this.users = users;
+ }
+}
diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/authorization/package.html b/cas-client-core/src/main/java/org/jasig/cas/client/authorization/package.html
new file mode 100644
index 0000000..b8c3d55
--- /dev/null
+++ b/cas-client-core/src/main/java/org/jasig/cas/client/authorization/package.html
@@ -0,0 +1,7 @@
+
+
+
The authorization package contains the interface for a simple
+abstraction for authorizing users to use an application. It is not a
+complete role-based or access control authorization system.
+
+
diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/proxy/AbstractProxyReceptorServlet.java b/cas-client-core/src/main/java/org/jasig/cas/client/proxy/AbstractProxyReceptorServlet.java
new file mode 100644
index 0000000..ee84926
--- /dev/null
+++ b/cas-client-core/src/main/java/org/jasig/cas/client/proxy/AbstractProxyReceptorServlet.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2006 The JA-SIG Collaborative. All rights reserved. See license
+ * distributed with this file and available online at
+ * http://www.uportal.org/license.html
+ */
+package org.jasig.cas.client.proxy;
+
+import java.io.IOException;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.jasig.cas.client.util.CommonUtils;
+
+/**
+ * Implementation of an HttpServlet that accepts ProxyGrantingTicketIous and
+ * ProxyGrantingTickets and stores them in an implementation of
+ * {@link ProxyGrantingTicketStorage}.
+ *
+ * @author Scott Battaglia
+ * @version $Revision$ $Date$
+ * @since 3.0
+ */
+public abstract class AbstractProxyReceptorServlet extends HttpServlet {
+
+ /**
+ * The name we expect the instance of ProxyGrantingTicketStorage to be
+ * instanciated under in the applicationContext.
+ */
+ public static final String CONST_PROXY_GRANTING_TICKET_STORAGE_BEAN_NAME = "proxyGrantingTicketStorage";
+
+ /** 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";
+
+ /** Instance of ProxyGrantingTicketStorage to store ProxyGrantingTickets. */
+ private ProxyGrantingTicketStorage proxyGrantingTicketStorage;
+
+ protected final Log logger = LogFactory.getLog(this.getClass());
+
+ /** Unique Id for Serialization. */
+ private static final long serialVersionUID = 8766956323018042995L;
+
+ protected final void doGet(final HttpServletRequest request,
+ final HttpServletResponse response) throws ServletException,
+ IOException {
+ 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;
+ }
+
+ if (logger.isDebugEnabled()) {
+ logger.debug("Received proxyGrantingTicketId ["
+ + proxyGrantingTicket + "] for proxyGrantingTicketIou ["
+ + proxyGrantingTicketIou + "]");
+ }
+
+ this.proxyGrantingTicketStorage.save(proxyGrantingTicketIou,
+ proxyGrantingTicket);
+
+ response.getWriter().write("");
+ response
+ .getWriter()
+ .write(
+ "");
+ }
+
+ public final void setProxyGrantingTicketStorage(
+ final ProxyGrantingTicketStorage proxyGrantingTicketStorage) {
+ this.proxyGrantingTicketStorage = proxyGrantingTicketStorage;
+ }
+}
diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/proxy/Cas20ProxyRetriever.java b/cas-client-core/src/main/java/org/jasig/cas/client/proxy/Cas20ProxyRetriever.java
new file mode 100644
index 0000000..caa4daa
--- /dev/null
+++ b/cas-client-core/src/main/java/org/jasig/cas/client/proxy/Cas20ProxyRetriever.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright 2006 The JA-SIG Collaborative. All rights reserved. See license
+ * distributed with this file and available online at
+ * http://www.uportal.org/license.html
+ */
+package org.jasig.cas.client.proxy;
+
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.net.URLEncoder;
+
+import org.apache.commons.httpclient.HttpClient;
+import org.apache.commons.httpclient.methods.GetMethod;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.jasig.cas.authentication.principal.Service;
+import org.jasig.cas.client.util.CommonUtils;
+import org.jasig.cas.client.util.XmlUtils;
+
+/**
+ * Implementation of a ProxyRetriever that follows the CAS 2.0 specification.
+ * For more information on the CAS 2.0 specification, please see the specification
+ * document.
+ *
+ * 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$ $Date$
+ * @since 3.0
+ */
+public final class Cas20ProxyRetriever implements ProxyRetriever {
+
+ /** Instance of Commons Logging. */
+ protected Log log = LogFactory.getLog(this.getClass());
+
+ /** Url to CAS server. */
+ private String casServerUrl;
+
+ /** Instance of HttpClient for connecting to server. */
+ private HttpClient httpClient;
+
+ public String getProxyTicketIdFor(final String proxyGrantingTicketId,
+ final Service targetService) {
+
+ final String url = constructUrl(proxyGrantingTicketId, targetService
+ .getId());
+
+ final GetMethod method = new GetMethod(url);
+ try {
+ this.httpClient.executeMethod(method);
+ final String response = method.getResponseBodyAsString();
+
+ final String error = XmlUtils.getTextForElement(response,
+ "proxyFailure");
+
+ if (CommonUtils.isNotEmpty(error)) {
+ log.debug(error);
+ return null;
+ }
+
+ return XmlUtils.getTextForElement(response, "proxyTicket");
+
+ } catch (IOException e) {
+ log.error(e, e);
+ return null;
+ } finally {
+ method.releaseConnection();
+ }
+ }
+
+ 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);
+ }
+ }
+
+ public void setCasServerUrl(final String casServerUrl) {
+ this.casServerUrl = casServerUrl;
+ }
+
+ public void setHttpClient(final HttpClient httpClient) {
+ this.httpClient = httpClient;
+ }
+
+ public void init() {
+ CommonUtils.assertNotNull(this.casServerUrl,
+ "casServerUrl cannot be null.");
+ CommonUtils
+ .assertNotNull(this.httpClient, "httpClient cannot be null.");
+ }
+}
diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/proxy/ProxyGrantingTicketStorage.java b/cas-client-core/src/main/java/org/jasig/cas/client/proxy/ProxyGrantingTicketStorage.java
new file mode 100644
index 0000000..dd6785a
--- /dev/null
+++ b/cas-client-core/src/main/java/org/jasig/cas/client/proxy/ProxyGrantingTicketStorage.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2006 The JA-SIG Collaborative. All rights reserved. See license
+ * distributed with this file and available online at
+ * http://www.uportal.org/license.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$ $Date$
+ * @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);
+}
diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/proxy/ProxyGrantingTicketStorageImpl.java b/cas-client-core/src/main/java/org/jasig/cas/client/proxy/ProxyGrantingTicketStorageImpl.java
new file mode 100644
index 0000000..11e4b05
--- /dev/null
+++ b/cas-client-core/src/main/java/org/jasig/cas/client/proxy/ProxyGrantingTicketStorageImpl.java
@@ -0,0 +1,141 @@
+/*
+ * Copyright 2006 The JA-SIG Collaborative. All rights reserved. See license
+ * distributed with this file and available online at
+ * http://www.uportal.org/license.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.
+ *
+ * A cleanup thread is run periodically to clean out the HashMap.
+ *
+ * @author Scott Battaglia
+ * @version $Revision$ $Date$
+ * @since 3.0
+ */
+public final class ProxyGrantingTicketStorageImpl implements
+ ProxyGrantingTicketStorage {
+
+ /**
+ * Default timeout in milliseconds.
+ */
+ private static final long DEFAULT_TIMEOUT = 60000;
+
+ private Map cache = new HashMap();
+
+ private long timeout = DEFAULT_TIMEOUT;
+
+ /**
+ * 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);
+ }
+
+ public void init() throws Exception {
+ final Thread thread = new ProxyGrantingTicketCleanupThread(
+ this.timeout, this.cache);
+ thread.setDaemon(true);
+ thread.start();
+ }
+
+ /**
+ * 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 void setTimeout(final long timeout) {
+ this.timeout = timeout;
+ }
+
+ private 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 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());
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/proxy/ProxyRetriever.java b/cas-client-core/src/main/java/org/jasig/cas/client/proxy/ProxyRetriever.java
new file mode 100644
index 0000000..08228e1
--- /dev/null
+++ b/cas-client-core/src/main/java/org/jasig/cas/client/proxy/ProxyRetriever.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2006 The JA-SIG Collaborative. All rights reserved. See license
+ * distributed with this file and available online at
+ * http://www.uportal.org/license.html
+ */
+package org.jasig.cas.client.proxy;
+
+import org.jasig.cas.authentication.principal.Service;
+
+/**
+ * Interface to abstract the retrieval of a proxy ticket to make the
+ * implementation a black box to the client.
+ *
+ * @author Scott Battaglia
+ * @version $Revision$ $Date$
+ * @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,
+ Service targetService);
+}
diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/proxy/SpringConfiguredProxyReceptorServlet.java b/cas-client-core/src/main/java/org/jasig/cas/client/proxy/SpringConfiguredProxyReceptorServlet.java
new file mode 100644
index 0000000..8baad5e
--- /dev/null
+++ b/cas-client-core/src/main/java/org/jasig/cas/client/proxy/SpringConfiguredProxyReceptorServlet.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2006 The JA-SIG Collaborative. All rights reserved. See license
+ * distributed with this file and available online at
+ * http://www.uportal.org/license.html
+ */
+package org.jasig.cas.client.proxy;
+
+import java.util.Map;
+
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletException;
+
+import org.springframework.web.context.WebApplicationContext;
+import org.springframework.web.context.support.WebApplicationContextUtils;
+
+/**
+ * Implementation of an HttpServlet that accepts ProxyGrantingTicketIous and
+ * ProxyGrantingTickets and stores them in an implementation of
+ * {@link ProxyGrantingTicketStorage}.
+ *
+ * Note that ProxyReceptorServlet attempts to load a
+ * {@link ProxyGrantingTicketStorage} from the ApplicationContext either via the
+ * name "proxyGrantingTicketStorage" or by type. One of these two must exist
+ * within the applicationContext or the initialization of the
+ * ProxyReceptorServlet will fail.
+ *
+ * @author Scott Battaglia
+ * @version $Revision$ $Date$
+ * @since 3.0
+ */
+public final class SpringConfiguredProxyReceptorServlet extends
+ AbstractProxyReceptorServlet {
+
+ /** Unique Id for serialization */
+ private static final long serialVersionUID = -5642050740265266568L;
+
+ public void init(final ServletConfig servletConfig) throws ServletException {
+ final WebApplicationContext context = WebApplicationContextUtils
+ .getRequiredWebApplicationContext(servletConfig.getServletContext());
+
+ if (context.containsBean(CONST_PROXY_GRANTING_TICKET_STORAGE_BEAN_NAME)) {
+ this
+ .setProxyGrantingTicketStorage((ProxyGrantingTicketStorage) context
+ .getBean(CONST_PROXY_GRANTING_TICKET_STORAGE_BEAN_NAME,
+ ProxyGrantingTicketStorage.class));
+ return;
+ }
+
+ final Map map = context
+ .getBeansOfType(ProxyGrantingTicketStorage.class);
+
+ if (map.isEmpty()) {
+ throw new ServletException("No ProxyGrantingTicketStorage found!");
+ }
+
+ if (map.size() > 1) {
+ throw new ServletException(
+ "Expecting one ProxyGrantingTicketStorage and found multiple instances.");
+ }
+
+ setProxyGrantingTicketStorage((ProxyGrantingTicketStorage) map.get(map
+ .keySet().iterator().next()));
+ }
+
+}
diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/proxy/package.html b/cas-client-core/src/main/java/org/jasig/cas/client/proxy/package.html
new file mode 100644
index 0000000..8e28951
--- /dev/null
+++ b/cas-client-core/src/main/java/org/jasig/cas/client/proxy/package.html
@@ -0,0 +1,7 @@
+
+
+
The proxy package includes a servlet to act as a proxy receptor,
+an interface for ProxyGrantingTicketStorage and an abstraction for
+retrieving proxy tickets.
+
+
\ No newline at end of file
diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/util/CommonUtils.java b/cas-client-core/src/main/java/org/jasig/cas/client/util/CommonUtils.java
new file mode 100644
index 0000000..0b3dcd2
--- /dev/null
+++ b/cas-client-core/src/main/java/org/jasig/cas/client/util/CommonUtils.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2006 The JA-SIG Collaborative. All rights reserved. See license
+ * distributed with this file and available online at
+ * http://www.uportal.org/license.html
+ */
+package org.jasig.cas.client.util;
+
+import java.util.Collection;
+
+/**
+ * Common utilities so that we don't need to include Commons Lang.
+ *
+ * @author Scott Battaglia
+ * @version $Revision$ $Date$
+ * @since 3.0
+ */
+public final class CommonUtils {
+
+ 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);
+ }
+
+}
diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/util/DelegatingFilter.java b/cas-client-core/src/main/java/org/jasig/cas/client/util/DelegatingFilter.java
new file mode 100644
index 0000000..c4768bc
--- /dev/null
+++ b/cas-client-core/src/main/java/org/jasig/cas/client/util/DelegatingFilter.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright 2006 The JA-SIG Collaborative. All rights reserved. See license
+ * distributed with this file and available online at
+ * http://www.uportal.org/license.html
+ */
+package org.jasig.cas.client.util;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import javax.servlet.*;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+/**
+ * A Delegating Filter looks up a parameter in the request object and matches
+ * (either exact or using Regular Expressions) the value. If there is a match,
+ * the associated filter is executed. Otherwise, the normal chain is executed.
+ *
+ * @author Scott Battaglia
+ * @version $Revision$ $Date$
+ * @since 3.0
+ */
+public final class DelegatingFilter implements Filter {
+
+ /** Instance of Commons Logging. */
+ private Log log = LogFactory.getLog(this.getClass());
+
+ /** The request parameter to look for in the Request object. */
+ private String requestParameterName;
+
+ /** The map of filters to delegate to and the criteria (as key). */
+ private Map delegators = new HashMap();
+
+ /** The default filter to use if there is no match. */
+ private Filter defaultFilter;
+
+ /**
+ * Whether the key in the delegators map is an exact match or a regular
+ * expression.
+ */
+ private boolean exactMatch = false;
+
+ public void destroy() {
+ // nothing to do here
+ }
+
+ public void doFilter(final ServletRequest request,
+ final ServletResponse response, final FilterChain filterChain)
+ throws IOException, ServletException {
+
+ final String parameter = request
+ .getParameter(this.requestParameterName);
+
+ if (CommonUtils.isNotEmpty(parameter)) {
+ for (final Iterator iter = this.delegators.keySet().iterator(); iter
+ .hasNext();) {
+ final String key = (String) iter.next();
+
+ if ((parameter.equals(key) && this.exactMatch)
+ || (parameter.matches(key) && !this.exactMatch)) {
+ final Filter filter = (Filter) this.delegators.get(key);
+ if (log.isDebugEnabled()) {
+ log.debug("Match found for parameter ["
+ + this.requestParameterName + "] with value ["
+ + parameter + "]. Delegating to filter ["
+ + filter.getClass().getName() + "]");
+ }
+ filter.doFilter(request, response, filterChain);
+ return;
+ }
+ }
+ }
+
+ log.debug("No match found for parameter [" + this.requestParameterName
+ + "] with value [" + parameter + "]");
+
+ if (this.defaultFilter != null) {
+ this.defaultFilter.doFilter(request, response, filterChain);
+ } else {
+ filterChain.doFilter(request, response);
+ }
+ }
+
+ public void init(final FilterConfig filterConfig) throws ServletException {
+ // nothing to do here.
+ }
+
+ public void init() {
+ CommonUtils.assertNotNull(this.requestParameterName,
+ "requestParameterName cannot be null.");
+ CommonUtils.assertTrue(!this.delegators.isEmpty(),
+ "delegators cannot be empty.");
+
+ for (final Iterator iter = this.delegators.keySet().iterator(); iter
+ .hasNext();) {
+ final Object object = this.delegators.get(iter.next());
+
+ if (!Filter.class.isAssignableFrom(object.getClass())) {
+ throw new IllegalArgumentException(
+ "All value objects in the delegators map must be filters.");
+ }
+ }
+ }
+
+ /**
+ * Sets the map of delegating filters.
+ *
+ * @param delegators the map of delegators to set.
+ */
+ public void setDelegators(final Map delegators) {
+ this.delegators = delegators;
+ }
+
+ /**
+ * Marks whether the value of the parameter needs to match exactly or not.
+ *
+ * @param exactMatch the value of whether we need to match exactly or not.
+ */
+ public void setExactMatch(final boolean exactMatch) {
+ this.exactMatch = exactMatch;
+ }
+
+ /**
+ * Sets the name of the request parameter to monitor.
+ *
+ * @param requestParameterName the name of the request parameter.
+ */
+ public void setRequestParameterName(final String requestParameterName) {
+ this.requestParameterName = requestParameterName;
+ }
+
+ /**
+ * Sets the default filter to use if there are no matches. This is optional
+ * as the filter will just continue on the chain if there is no default.
+ *
+ * @param defaultFilter the filter to use by default.
+ */
+ protected void setDefaultFilter(final Filter defaultFilter) {
+ this.defaultFilter = defaultFilter;
+ }
+
+}
diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/util/FilterToBeanProxy.java b/cas-client-core/src/main/java/org/jasig/cas/client/util/FilterToBeanProxy.java
new file mode 100644
index 0000000..7d1ed1d
--- /dev/null
+++ b/cas-client-core/src/main/java/org/jasig/cas/client/util/FilterToBeanProxy.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2006 The JA-SIG Collaborative. All rights reserved. See license
+ * distributed with this file and available online at
+ * http://www.uportal.org/license.html
+ */
+package org.jasig.cas.client.util;
+
+import org.springframework.context.ApplicationContext;
+import org.springframework.web.context.support.WebApplicationContextUtils;
+
+import javax.servlet.*;
+import java.io.IOException;
+
+/**
+ * Utility class to retrieve a Filter from a Spring-managed configuration file.
+ * Based on the FilterToBeanProxy class in Acegi Security (but simplified)
+ *
+ * @author Scott Battaglia
+ * @version $Revision$ $Date$
+ * @since 3.0
+ */
+public class FilterToBeanProxy implements Filter {
+
+ /** The filter we are proxying. */
+ private Filter filter;
+
+ public void destroy() {
+ // nothing to do
+ }
+
+ public final void doFilter(final ServletRequest request,
+ final ServletResponse response, final FilterChain chain)
+ throws IOException, ServletException {
+ this.filter.doFilter(request, response, chain);
+ }
+
+ public final void init(final FilterConfig filterConfig)
+ throws ServletException {
+ doInit(filterConfig);
+ }
+
+ protected ApplicationContext getContext(FilterConfig filterConfig) {
+ return WebApplicationContextUtils
+ .getRequiredWebApplicationContext(filterConfig.getServletContext());
+ }
+
+ public final void doInit(final FilterConfig filterConfig)
+ throws ServletException {
+ final String targetBean = filterConfig.getInitParameter("targetBean");
+
+ if (CommonUtils.isBlank(targetBean)) {
+ throw new ServletException(
+ "init-parameter missing: targetBean is required.");
+ }
+
+ final ApplicationContext ctx = this.getContext(filterConfig);
+
+ if (!ctx.containsBean(targetBean)) {
+ throw new ServletException("targetBean '" + targetBean
+ + "' not found in context");
+ }
+
+ this.filter = (Filter) ctx.getBean(targetBean, Filter.class);
+ }
+}
diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/util/XmlUtils.java b/cas-client-core/src/main/java/org/jasig/cas/client/util/XmlUtils.java
new file mode 100644
index 0000000..cbfdfb5
--- /dev/null
+++ b/cas-client-core/src/main/java/org/jasig/cas/client/util/XmlUtils.java
@@ -0,0 +1,155 @@
+/*
+ * Copyright 2006 The JA-SIG Collaborative. All rights reserved. See license
+ * distributed with this file and available online at
+ * http://www.uportal.org/license.html
+ */
+package org.jasig.cas.client.util;
+
+import java.io.StringReader;
+import java.util.ArrayList;
+import java.util.List;
+
+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;
+
+/**
+ * Common utilities for easily parsing XML without duplicating logic.
+ *
+ * @author Scott Battaglia
+ * @version $Revision$ $Date$
+ * @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.
+ *
+ * @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();
+ 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();
+ }
+}
diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/util/package.html b/cas-client-core/src/main/java/org/jasig/cas/client/util/package.html
new file mode 100644
index 0000000..d6d6b49
--- /dev/null
+++ b/cas-client-core/src/main/java/org/jasig/cas/client/util/package.html
@@ -0,0 +1,5 @@
+
+
+
The validation package includes interfaces for validating Tickets, as well as the common implementations.
+
+
diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/validation/AbstractUrlBasedTicketValidator.java b/cas-client-core/src/main/java/org/jasig/cas/client/validation/AbstractUrlBasedTicketValidator.java
new file mode 100644
index 0000000..4b01983
--- /dev/null
+++ b/cas-client-core/src/main/java/org/jasig/cas/client/validation/AbstractUrlBasedTicketValidator.java
@@ -0,0 +1,117 @@
+package org.jasig.cas.client.validation;
+
+import org.apache.commons.httpclient.HttpClient;
+import org.apache.commons.httpclient.methods.GetMethod;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.jasig.cas.authentication.principal.Service;
+import org.jasig.cas.client.util.CommonUtils;
+
+import java.net.URLEncoder;
+
+/**
+ * Abstract class for validating tickets that defines a workflow that all ticket
+ * validation should follow.
+ *
+ * @author Scott Battaglia
+ * @version $Revision$ $Date$
+ * @since 3.0
+ */
+public abstract class AbstractUrlBasedTicketValidator implements
+ TicketValidator {
+
+ /** Instance of Commons Logging. */
+ protected Log log = LogFactory.getLog(this.getClass());
+
+ /** Url to CAS server. */
+ private String casServerUrl;
+
+ /** Whether this client is looking for an authentication from renew. */
+ private boolean renew;
+
+ /** Instance of HttpClient for connecting to server. */
+ private HttpClient httpClient;
+
+ public final Assertion validate(final String ticketId, final Service service)
+ throws ValidationException {
+ final String url = constructURL(ticketId, service);
+ final String response = getResponseFromURL(url);
+
+ return parseResponse(response);
+ }
+
+ protected abstract String constructURL(final String ticketId,
+ final Service service);
+
+ protected abstract Assertion parseResponse(final String response)
+ throws ValidationException;
+
+ private String getResponseFromURL(final String url)
+ throws ValidationException {
+ final GetMethod method = new GetMethod(url);
+
+ try {
+ this.httpClient.executeMethod(method);
+ return method.getResponseBodyAsString();
+ } catch (Exception e) {
+ log.error(e, e);
+ throw new ValidationException(
+ "Unable to retrieve response from CAS Server.", e);
+ } finally {
+ method.releaseConnection();
+ }
+ }
+
+ public final void init() {
+ CommonUtils.assertNotNull(this.casServerUrl,
+ "the validationUrl cannot be null");
+ CommonUtils
+ .assertNotNull(this.httpClient, "httpClient cannot be null.");
+
+ afterPropertiesSetInternal();
+ }
+
+ /**
+ * Helper method to encode the service url.
+ *
+ * @param service the service url to encode.
+ * @return the encoded service url.
+ */
+ protected final String getEncodedService(final Service service) {
+ try {
+ return URLEncoder.encode(service.getId(), "UTF-8");
+ } catch (final Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ protected final String getCasServerUrl() {
+ return this.casServerUrl;
+ }
+
+ protected final boolean isRenew() {
+ return this.renew;
+ }
+
+ public final void setCasServerUrl(final String casServerUrl) {
+ this.casServerUrl = casServerUrl;
+ }
+
+ public final void setHttpClient(final HttpClient httpClient) {
+ this.httpClient = httpClient;
+ }
+
+ public final void setRenew(final boolean renew) {
+ this.renew = renew;
+ }
+
+ /**
+ * Template method for afterProperties() for subclasses to call.
+ *
+ * @throws Exception
+ */
+ protected void afterPropertiesSetInternal() {
+ // template method
+ }
+
+}
diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/validation/Assertion.java b/cas-client-core/src/main/java/org/jasig/cas/client/validation/Assertion.java
new file mode 100644
index 0000000..3bfd34e
--- /dev/null
+++ b/cas-client-core/src/main/java/org/jasig/cas/client/validation/Assertion.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2006 The JA-SIG Collaborative. All rights reserved. See license
+ * distributed with this file and available online at
+ * http://www.uportal.org/license.html
+ */
+package org.jasig.cas.client.validation;
+
+import java.io.Serializable;
+import java.util.Map;
+
+import org.jasig.cas.authentication.principal.Principal;
+
+/**
+ * Interface to represent a successful response from the CAS Server.
+ *
+ * @author Scott Battaglia
+ * @version $Revision$ $Date$
+ * @since 3.0
+ */
+public interface Assertion extends Serializable {
+
+ /**
+ * Method to retrieve the principal.
+ *
+ * @return the principal.
+ */
+ Principal getPrincipal();
+
+ /**
+ * Map of attributes returned by the CAS server. A client must know what
+ * attributes he is looking for as CAS makes no claims about what attributes
+ * are returned.
+ *
+ * @return the map of attributes.
+ */
+ Map getAttributes();
+
+ /**
+ * Method to retrieve the proxyGrantingTicket Id.
+ *
+ * @return the ProxyGrantingTicket Id if one exists, otherwise null.
+ */
+ String getProxyGrantingTicketId();
+}
diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/validation/AssertionImpl.java b/cas-client-core/src/main/java/org/jasig/cas/client/validation/AssertionImpl.java
new file mode 100644
index 0000000..2e444db
--- /dev/null
+++ b/cas-client-core/src/main/java/org/jasig/cas/client/validation/AssertionImpl.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2006 The JA-SIG Collaborative. All rights reserved. See license
+ * distributed with this file and available online at
+ * http://www.uportal.org/license.html
+ */
+package org.jasig.cas.client.validation;
+
+import org.jasig.cas.authentication.principal.Principal;
+import org.jasig.cas.client.util.CommonUtils;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Concrete implementation of an Assertion.
+ *
+ * @author Scott Battaglia
+ * @version $Revision$ $Date$
+ * @since 3.0
+ */
+public class AssertionImpl implements Assertion {
+
+ /** Unique id for serialization. */
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Map of the attributes returned by the CAS server. This is optional as the
+ * CAS server spec makes no mention of attributes.
+ */
+ private final Map attributes;
+
+ /** The principal who was authenticated. */
+ private final Principal principal;
+
+ /** The Proxy Granting Ticket Id returned by the server. */
+ private final String proxyGrantingTicketId;
+
+ public AssertionImpl(final Principal principal) {
+ this(principal, null, null);
+ }
+
+ public AssertionImpl(final Principal principal, final Map attributes,
+ final String proxyGrantingTicketId) {
+ CommonUtils.assertNotNull(principal, "principal cannot be null");
+
+ this.principal = principal;
+ this.attributes = attributes == null ? new HashMap() : attributes;
+ this.proxyGrantingTicketId = CommonUtils
+ .isNotEmpty(proxyGrantingTicketId) ? proxyGrantingTicketId : null;
+ }
+
+ public Map getAttributes() {
+ return this.attributes;
+ }
+
+ public Principal getPrincipal() {
+ return this.principal;
+ }
+
+ public String getProxyGrantingTicketId() {
+ return this.proxyGrantingTicketId;
+ }
+}
diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/validation/Cas10TicketValidator.java b/cas-client-core/src/main/java/org/jasig/cas/client/validation/Cas10TicketValidator.java
new file mode 100644
index 0000000..e45c0fa
--- /dev/null
+++ b/cas-client-core/src/main/java/org/jasig/cas/client/validation/Cas10TicketValidator.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2006 The JA-SIG Collaborative. All rights reserved. See license
+ * distributed with this file and available online at
+ * http://www.uportal.org/license.html
+ */
+package org.jasig.cas.client.validation;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.StringReader;
+
+import org.jasig.cas.authentication.principal.Principal;
+import org.jasig.cas.authentication.principal.Service;
+import org.jasig.cas.authentication.principal.SimplePrincipal;
+
+/**
+ * Implementation of TicketValidator that follows the CAS 1.0 protocol.
+ *
+ * @author Scott Battaglia
+ * @version $Revision$ $Date$
+ * @since 3.0
+ */
+public class Cas10TicketValidator extends AbstractUrlBasedTicketValidator {
+
+ protected String constructURL(final String ticketId, final Service service) {
+ return getCasServerUrl() + "validate?ticket=" + ticketId
+ + (isRenew() ? "&renew=true" : "") + "&service="
+ + getEncodedService(service);
+ }
+
+ protected final Assertion parseResponse(final String response)
+ throws ValidationException {
+ if (response == null || "no\n\n".equals(response)
+ || !response.startsWith("yes")) {
+ throw new ValidationException(
+ "'No' response returned from server for validation request.");
+ }
+
+ try {
+ final BufferedReader reader = new BufferedReader(new StringReader(
+ response));
+ reader.readLine();
+
+ final Principal principal = new SimplePrincipal(reader.readLine());
+ return new AssertionImpl(principal);
+ } catch (final IOException e) {
+ throw new ValidationException("Unable to parse response.", e);
+ }
+ }
+}
diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/validation/Cas20ProxyTicketValidator.java b/cas-client-core/src/main/java/org/jasig/cas/client/validation/Cas20ProxyTicketValidator.java
new file mode 100644
index 0000000..07f27fe
--- /dev/null
+++ b/cas-client-core/src/main/java/org/jasig/cas/client/validation/Cas20ProxyTicketValidator.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright 2006 The JA-SIG Collaborative. All rights reserved. See license
+ * distributed with this file and available online at
+ * http://www.uportal.org/license.html
+ */
+package org.jasig.cas.client.validation;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+
+import org.jasig.cas.authentication.principal.Service;
+import org.jasig.cas.authentication.principal.SimpleService;
+import org.jasig.cas.client.util.CommonUtils;
+import org.jasig.cas.client.util.XmlUtils;
+
+/**
+ * Implementation of the TicketValidator interface that knows how to handle
+ * proxy tickets.
+ *
+ * @author Scott Battaglia
+ * @version $Revision$ $Date$
+ * @since 3.0
+ */
+public class Cas20ProxyTicketValidator extends Cas20ServiceTicketValidator {
+
+ /* List of proxy chains that we accept. */
+ private List proxyChains;
+
+ /** Boolean whether we accept any proxy request or not. */
+ private boolean acceptAnyProxy;
+
+ protected String getValidationUrlName() {
+ return "proxyValidate";
+ }
+
+ protected Assertion getValidAssertionInternal(final String response,
+ final Assertion assertion) throws ValidationException {
+ final List proxies = XmlUtils.getTextForElements(response, "proxy");
+ final Service[] principals = new Service[proxies.size()];
+
+ // this means there was nothing in the proxy chain, which is okay
+ if (principals.length == 0 || this.acceptAnyProxy) {
+ return assertion;
+ }
+
+ int i = 0;
+ for (final Iterator iter = proxies.iterator(); iter.hasNext();) {
+ principals[i++] = new SimpleService((String) iter.next());
+ }
+
+ boolean found = false;
+ for (Iterator iter = this.proxyChains.iterator(); iter.hasNext();) {
+ if (Arrays.equals(principals, (Object[]) iter.next())) {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found) {
+ throw new InvalidProxyChainValidationException();
+ }
+
+ return new AssertionImpl(assertion.getPrincipal(), assertion
+ .getAttributes(), assertion.getProxyGrantingTicketId());
+ }
+
+ /**
+ * In your XML configuration file, proxy chains should be defined as
+ * follows: <list> <value> proxy1 proxy2 proxy3</value>
+ * <value> proxy2 proxy4 proxy5</value> <value> proxy4
+ * proxy5 proxy6</value> </list>
+ *
+ * @param proxyChains
+ */
+ public final void setProxyChains(final List proxyChains) {
+ this.proxyChains = proxyChains;
+ }
+
+ /**
+ * Set this flag to true if you don't care where the proxied request came
+ * from.
+ *
+ * @param acceptAnyProxy flag on whether we accept any proxy or not.
+ */
+ public void setAcceptAnyProxy(final boolean acceptAnyProxy) {
+ this.acceptAnyProxy = acceptAnyProxy;
+ }
+
+ protected void afterPropertiesSetInternal() {
+ super.afterPropertiesSetInternal();
+
+ CommonUtils.assertTrue(this.proxyChains != null || this.acceptAnyProxy,
+ "proxyChains cannot be null or acceptAnyProxy must be true.");
+ CommonUtils.assertTrue((this.proxyChains != null && !this.proxyChains
+ .isEmpty())
+ || this.acceptAnyProxy,
+ "proxyChains cannot be empty or acceptAnyProxy must be true.");
+
+ final List tempProxyChains = new ArrayList();
+ for (final Iterator iter = this.proxyChains.iterator(); iter.hasNext();) {
+ final String[] values = ((String) iter.next()).split(" ");
+ final Service[] principals = new Service[values.length];
+
+ for (int i = 0; i < principals.length; i++) {
+ principals[i] = new SimpleService(values[i]);
+ }
+
+ tempProxyChains.add(principals);
+ }
+
+ this.proxyChains = tempProxyChains;
+ }
+}
diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/validation/Cas20ServiceTicketValidator.java b/cas-client-core/src/main/java/org/jasig/cas/client/validation/Cas20ServiceTicketValidator.java
new file mode 100644
index 0000000..a05c9b7
--- /dev/null
+++ b/cas-client-core/src/main/java/org/jasig/cas/client/validation/Cas20ServiceTicketValidator.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright 2006 The JA-SIG Collaborative. All rights reserved. See license
+ * distributed with this file and available online at
+ * http://www.uportal.org/license.html
+ */
+package org.jasig.cas.client.validation;
+
+import org.jasig.cas.authentication.principal.Service;
+import org.jasig.cas.authentication.principal.SimplePrincipal;
+import org.jasig.cas.authentication.principal.SimpleService;
+import org.jasig.cas.client.proxy.ProxyGrantingTicketStorage;
+import org.jasig.cas.client.util.CommonUtils;
+import org.jasig.cas.client.util.XmlUtils;
+
+/**
+ * Implementation of TicketValidator that follows the CAS 2.0 protocol (without
+ * proxying).
+ *
+ * @author Scott Battaglia
+ * @version $Revision$ $Date$
+ * @since 3.0
+ */
+public class Cas20ServiceTicketValidator extends
+ AbstractUrlBasedTicketValidator {
+
+ /** Proxy callback url to send to the CAS server. */
+ private Service proxyCallbackUrl;
+
+ /** The storage mechanism for the ProxyGrantingTickets. */
+ private ProxyGrantingTicketStorage proxyGrantingTicketStorage;
+
+ protected String constructURL(final String ticketId,
+ final Service service) {
+ return getCasServerUrl()
+ + getValidationUrlName()
+ + "?ticket="
+ + ticketId
+ + (isRenew() ? "&renew=true" : "")
+ + "&service="
+ + getEncodedService(service)
+ + (this.proxyCallbackUrl != null ? "&pgtUrl="
+ + getEncodedService(this.proxyCallbackUrl) : "");
+ }
+
+ protected final Assertion parseResponse(String response)
+ throws ValidationException {
+ final String error = XmlUtils.getTextForElement(response,
+ "authenticationFailure");
+
+ if (CommonUtils.isNotBlank(error)) {
+ log.debug("Validation of ticket failed: " + error);
+ throw new ValidationException(error);
+ }
+
+ final String principal = XmlUtils.getTextForElement(response, "user");
+ final String proxyGrantingTicketIou = XmlUtils.getTextForElement(
+ response, "proxyGrantingTicket");
+
+ if (CommonUtils.isEmpty(principal)) {
+ throw new ValidationException("No principal found.");
+ }
+
+ if (CommonUtils.isNotBlank(proxyGrantingTicketIou)) {
+ return getValidAssertionInternal(response, new AssertionImpl(
+ new SimplePrincipal(principal), null,
+ this.proxyGrantingTicketStorage
+ .retrieve(proxyGrantingTicketIou)));
+ }
+
+ return getValidAssertionInternal(response, new AssertionImpl(
+ new SimplePrincipal(principal)));
+ }
+
+ protected String getValidationUrlName() {
+ return "serviceValidate";
+ }
+
+ protected Assertion getValidAssertionInternal(final String response,
+ final Assertion assertion) throws ValidationException {
+ return assertion;
+ }
+
+ /**
+ * Sets the proxy callback url
+ *
+ * @param proxyCallbackUrl the proxycallback url specified for this
+ * application.
+ */
+ public final void setProxyCallbackUrl(final String proxyCallbackUrl) {
+ this.proxyCallbackUrl = new SimpleService(proxyCallbackUrl);
+ }
+
+ /**
+ * Sets the ProxyGrantingTicketStorage
+ *
+ * @param proxyGrantingTicketStorage the storage mechanism to use.
+ */
+ public final void setProxyGrantingTicketStorage(
+ final ProxyGrantingTicketStorage proxyGrantingTicketStorage) {
+ this.proxyGrantingTicketStorage = proxyGrantingTicketStorage;
+ }
+
+ protected void afterPropertiesSetInternal() {
+ CommonUtils.assertNotNull(this.proxyGrantingTicketStorage,
+ "proxyGrantingTicketStorage cannot be null");
+ }
+}
diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/validation/InvalidProxyChainValidationException.java b/cas-client-core/src/main/java/org/jasig/cas/client/validation/InvalidProxyChainValidationException.java
new file mode 100644
index 0000000..4ce7bd2
--- /dev/null
+++ b/cas-client-core/src/main/java/org/jasig/cas/client/validation/InvalidProxyChainValidationException.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2006 The JA-SIG Collaborative. All rights reserved. See license
+ * distributed with this file and available online at
+ * http://www.uportal.org/license.html
+ */
+package org.jasig.cas.client.validation;
+
+/**
+ * Specific instance of a ValidationException that is thrown when the proxy
+ * chain does not match what is returned.
+ *
+ * @author Scott Battaglia
+ * @version $Revision$ $Date$
+ * @since 3.0
+ */
+public final class InvalidProxyChainValidationException extends ValidationException {
+
+ /** Unique id for serialization. */
+ private static final long serialVersionUID = 1L;
+
+ public InvalidProxyChainValidationException() {
+ super();
+ }
+
+ public InvalidProxyChainValidationException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ public InvalidProxyChainValidationException(String message) {
+ super(message);
+ }
+
+ public InvalidProxyChainValidationException(Throwable cause) {
+ super(cause);
+ }
+}
diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/validation/TicketValidator.java b/cas-client-core/src/main/java/org/jasig/cas/client/validation/TicketValidator.java
new file mode 100644
index 0000000..5eadddc
--- /dev/null
+++ b/cas-client-core/src/main/java/org/jasig/cas/client/validation/TicketValidator.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2006 The JA-SIG Collaborative. All rights reserved. See license
+ * distributed with this file and available online at
+ * http://www.uportal.org/license.html
+ */
+package org.jasig.cas.client.validation;
+
+import org.jasig.cas.authentication.principal.Service;
+
+/**
+ * Interface to encapsulate the validation of a ticket. The inteface is
+ * specification neutral. Any implementation can be provided, including
+ * something that parses CAS1 or CAS2 responses.
+ *
+ * @author Scott Battaglia
+ * @version $Revision$ $Date$
+ * @since 3.0
+ */
+public interface TicketValidator {
+
+ /**
+ * Method to validate a ticket for a give Service.
+ *
+ * @param ticketId the ticket to validate
+ * @param service the service to validate the ticket for
+ * @return the Assertion about the ticket (never null)
+ * @throws ValidationException if there is a problem validating the ticket.
+ */
+ Assertion validate(String ticketId, Service service)
+ throws ValidationException;
+}
diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/validation/ValidationException.java b/cas-client-core/src/main/java/org/jasig/cas/client/validation/ValidationException.java
new file mode 100644
index 0000000..ae17505
--- /dev/null
+++ b/cas-client-core/src/main/java/org/jasig/cas/client/validation/ValidationException.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2006 The JA-SIG Collaborative. All rights reserved. See license
+ * distributed with this file and available online at
+ * http://www.uportal.org/license.html
+ */
+package org.jasig.cas.client.validation;
+
+/**
+ * Implementation of Exception to be thrown when there is an error validating
+ * the Ticket returned from the CAS server.
+ *
+ * @author Scott Battaglia
+ * @version $Revision$ $Date$
+ * @since 3.0
+ */
+public class ValidationException extends Exception {
+
+ /** Unique Id for serialization. */
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Default constructor.
+ */
+ public ValidationException() {
+ super();
+ }
+
+ /**
+ * Constructor that accepts a message and a chained exception.
+ * @param message the error message.
+ * @param cause the exception we are chaining with.
+ */
+ public ValidationException(final String message, final Throwable cause) {
+ super(message, cause);
+ }
+
+ /**
+ * Constructor that accepts a message.
+ * @param message the error message.
+ */
+ public ValidationException(final String message) {
+ super(message);
+ }
+
+ /**
+ * Constructor that accepts a chained exception.
+ * @param cause the exception we are chaining with.
+ */
+ public ValidationException(final Throwable cause) {
+ super(cause);
+ }
+}
diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/validation/package.html b/cas-client-core/src/main/java/org/jasig/cas/client/validation/package.html
new file mode 100644
index 0000000..e272813
--- /dev/null
+++ b/cas-client-core/src/main/java/org/jasig/cas/client/validation/package.html
@@ -0,0 +1,5 @@
+
+
+
This package contains common utilities used within the CAS client classes.
+
+
diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/web/filter/AbstractCasFilter.java b/cas-client-core/src/main/java/org/jasig/cas/client/web/filter/AbstractCasFilter.java
new file mode 100644
index 0000000..e3eeae4
--- /dev/null
+++ b/cas-client-core/src/main/java/org/jasig/cas/client/web/filter/AbstractCasFilter.java
@@ -0,0 +1,181 @@
+/*
+ * Copyright 2006 The JA-SIG Collaborative. All rights reserved. See license
+ * distributed with this file and available online at
+ * http://www.uportal.org/license.html
+ */
+package org.jasig.cas.client.web.filter;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.jasig.cas.client.util.CommonUtils;
+
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+
+/**
+ * Abstract class that contains common functionality amongst CAS filters.
+ *
+ * You must specify the serverName or the serviceUrl. If you specify both, the
+ * serviceUrl is used over the serverName.
+ *
+ * @author Scott Battaglia
+ * @version $Revision$ $Date$
+ * @since 3.0
+ */
+public abstract class AbstractCasFilter implements Filter {
+
+ /** Constant string representing the ticket parameter. */
+ public static final String PARAM_TICKET = "ticket";
+
+ /**
+ * Constant representing where we store the Assertion in the
+ * session.
+ */
+ public static final String CONST_ASSERTION = "_cas_assertion_";
+
+ /** Constant representing where we flag a gatewayed request in the session. */
+ public static final String CONST_GATEWAY = "_cas_gateway_";
+
+ /** Constant representing where we flag a principal. */
+ public static final String CONST_PRINCIPAL = "_cas_principal_";
+
+ /** Instance of Commons Logging. */
+ protected final Log log = LogFactory.getLog(this.getClass());
+
+ /**
+ * The name of the server in the following format: : where
+ * port is optional if its a standard port.
+ */
+ private String serverName;
+
+ /** The exact service url to match to. */
+ private String serviceUrl;
+
+ /** Whether to store the entry in session or not. Defaults to true. */
+ private boolean useSession = true;
+
+ public final void destroy() {
+ // nothing to do
+ }
+
+ public final void doFilter(final ServletRequest servletRequest,
+ final ServletResponse servletResponse, final FilterChain filterChain)
+ throws IOException, ServletException {
+ doFilterInternal((HttpServletRequest) servletRequest,
+ (HttpServletResponse) servletResponse, filterChain);
+ }
+
+ protected abstract void doFilterInternal(HttpServletRequest request,
+ HttpServletResponse response, FilterChain filterChain)
+ throws IOException, ServletException;
+
+ public void init(final FilterConfig filterConfig) throws ServletException {
+ // nothing to do here
+ }
+
+ /**
+ * 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.
+ */
+ protected final String constructServiceUrl(final HttpServletRequest request,
+ final HttpServletResponse response) {
+ if (CommonUtils.isNotBlank(this.serviceUrl)) {
+ return response.encodeURL(this.serviceUrl);
+ }
+
+ final StringBuffer buffer = new StringBuffer();
+
+ synchronized (buffer) {
+ buffer.append(request.isSecure() ? "https://" : "http://");
+ buffer.append(this.serverName);
+ buffer.append(request.getRequestURI());
+
+ if (CommonUtils.isNotBlank(request.getQueryString())) {
+ final int location = request.getQueryString().indexOf(
+ PARAM_TICKET + "=");
+
+ 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("&" + PARAM_TICKET + "=");
+
+ 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;
+ }
+
+ protected final boolean isUseSession() {
+ return this.useSession;
+ }
+
+ protected final void setUseSession(final boolean useSession) {
+ this.useSession = useSession;
+ }
+
+ /**
+ * Sets the serverName which should be of the format :
+ * where port is optional if its a standard port. Either the serverName or
+ * the serviceUrl must be set.
+ *
+ * @param serverName the : combination.
+ */
+ public final void setServerName(final String serverName) {
+ this.serverName = serverName;
+ }
+
+ public final void setServiceUrl(final String serviceUrl) {
+ this.serviceUrl = serviceUrl;
+ }
+
+ public final void init() {
+ CommonUtils.assertTrue(CommonUtils.isNotBlank(this.serverName)
+ || CommonUtils.isNotBlank(this.serviceUrl),
+ "either serverName or serviceUrl must be set");
+ afterPropertiesSetInternal();
+ }
+
+ /**
+ * Template method for additional checks at initialization.
+ *
+ * @throws Exception any exceptions thrown upon initialization.
+ */
+ protected void afterPropertiesSetInternal() {
+ // template method
+ }
+}
diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/web/filter/CasAuthenticationFilter.java b/cas-client-core/src/main/java/org/jasig/cas/client/web/filter/CasAuthenticationFilter.java
new file mode 100644
index 0000000..2180008
--- /dev/null
+++ b/cas-client-core/src/main/java/org/jasig/cas/client/web/filter/CasAuthenticationFilter.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2006 The JA-SIG Collaborative. All rights reserved. See license
+ * distributed with this file and available online at
+ * http://www.uportal.org/license.html
+ */
+package org.jasig.cas.client.web.filter;
+
+import java.io.IOException;
+import java.net.URLEncoder;
+
+import javax.servlet.FilterChain;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+
+import org.jasig.cas.client.util.CommonUtils;
+import org.jasig.cas.client.validation.Assertion;
+
+/**
+ * Filter implementation to intercept all requests and attempt to authenticate
+ * the user by redirecting them to CAS (unless the user has a ticket).
+ *
+ * @author Scott Battaglia
+ * @version $Revision$ $Date$
+ * @since 3.0
+ */
+public final class CasAuthenticationFilter extends AbstractCasFilter {
+
+ /** The URL to the CAS Server login. */
+ private String casServerLoginUrl;
+
+ /** Whether to send the renew request or not. */
+ private boolean renew;
+
+ /** Whether to send the gateway request or not. */
+ private boolean gateway;
+
+ protected void doFilterInternal(final HttpServletRequest request,
+ final HttpServletResponse response, final FilterChain filterChain)
+ throws IOException, ServletException {
+ final HttpSession session = request.getSession(isUseSession());
+ final String ticket = request.getParameter(PARAM_TICKET);
+ final Assertion assertion = session != null ? (Assertion) session
+ .getAttribute(CONST_ASSERTION) : null;
+ final boolean wasGatewayed = session != null
+ && session.getAttribute(CONST_GATEWAY) != null;
+
+ if (CommonUtils.isBlank(ticket) && assertion == null && !wasGatewayed) {
+ if (this.gateway && session != null) {
+ session.setAttribute(CONST_GATEWAY, "yes");
+ }
+
+ final String serviceUrl = constructServiceUrl(request, response);
+ final String urlToRedirectTo = this.casServerLoginUrl + "?service="
+ + URLEncoder.encode(serviceUrl, "UTF-8")
+ + (this.renew ? "&renew=true" : "")
+ + (this.gateway ? "&gateway=true" : "");
+ response.sendRedirect(urlToRedirectTo);
+ return;
+ }
+
+ if (session != null) {
+ session.setAttribute(CONST_GATEWAY, null);
+ }
+
+ filterChain.doFilter(request, response);
+ }
+
+ public void setCasServerLoginUrl(final String casServerLoginUrl) {
+ this.casServerLoginUrl = casServerLoginUrl;
+ }
+
+ public void setGateway(final boolean gateway) {
+ this.gateway = gateway;
+ }
+
+ public void setRenew(final boolean renew) {
+ this.renew = renew;
+ }
+
+ protected void afterPropertiesSetInternal() {
+ CommonUtils.assertNotNull(this.casServerLoginUrl,
+ "the CAS Server Login URL cannot be null.");
+ }
+}
diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/web/filter/CasAuthorizationFilter.java b/cas-client-core/src/main/java/org/jasig/cas/client/web/filter/CasAuthorizationFilter.java
new file mode 100644
index 0000000..3ed2737
--- /dev/null
+++ b/cas-client-core/src/main/java/org/jasig/cas/client/web/filter/CasAuthorizationFilter.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2006 The JA-SIG Collaborative. All rights reserved. See license
+ * distributed with this file and available online at
+ * http://www.uportal.org/license.html
+ */
+package org.jasig.cas.client.web.filter;
+
+import org.jasig.cas.authentication.principal.Principal;
+import org.jasig.cas.client.authorization.AuthorizationException;
+import org.jasig.cas.client.authorization.CasAuthorizedDecider;
+import org.jasig.cas.client.util.CommonUtils;
+import org.jasig.cas.client.validation.Assertion;
+
+import javax.servlet.*;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+
+/**
+ * Simple filter that attempts to determine if someone is authorized to use the
+ * system. Assumes that you are protecting the application with the
+ * AuthenticationFilter such that the Assertion is set in the session.
+ *
+ * If a user is not authorized to use the application, the response code of 403
+ * will be sent to the browser.
+ *
+ * This filter needs to be configured after both the authentication filter and
+ * the validation filter.
+ *
+ * @author Scott Battaglia
+ * @version $Revision$ $Date$
+ * @since 3.0
+ * @see CasAuthorizedDecider
+ */
+public final class CasAuthorizationFilter implements Filter {
+
+ /**
+ * Decider that determines whether a specified principal has access to the
+ * resource or not.
+ */
+ private CasAuthorizedDecider decider;
+
+ public void destroy() {
+ // 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 HttpServletResponse response = (HttpServletResponse) servletResponse;
+ final Assertion assertion = (Assertion) request.getSession()
+ .getAttribute(AbstractCasFilter.CONST_ASSERTION);
+
+ if (assertion == null) {
+ throw new ServletException(
+ "assertion session attribute expected but not found.");
+ }
+
+ final Principal principal = assertion.getPrincipal();
+
+ final boolean authorized = this.decider
+ .isAuthorizedToUseApplication(principal);
+
+ if (!authorized) {
+ response.setStatus(HttpServletResponse.SC_FORBIDDEN);
+ throw new AuthorizationException(principal.getId()
+ + " is not authorized to use this application.");
+ }
+
+ filterChain.doFilter(servletRequest, servletResponse);
+ }
+
+ public void init(final FilterConfig filterConfig) throws ServletException {
+ // nothing to do here
+
+ }
+
+ public void setDecider(final CasAuthorizedDecider decider) {
+ this.decider = decider;
+ }
+
+ public void init() {
+ CommonUtils.assertNotNull(this.decider,
+ "the casAuthorizedDecider cannot be null.");
+ }
+}
diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/web/filter/CasValidationFilter.java b/cas-client-core/src/main/java/org/jasig/cas/client/web/filter/CasValidationFilter.java
new file mode 100644
index 0000000..799ddb5
--- /dev/null
+++ b/cas-client-core/src/main/java/org/jasig/cas/client/web/filter/CasValidationFilter.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright 2006 The JA-SIG Collaborative. All rights reserved. See license
+ * distributed with this file and available online at
+ * http://www.uportal.org/license.html
+ */
+package org.jasig.cas.client.web.filter;
+
+import org.jasig.cas.authentication.principal.SimpleService;
+import org.jasig.cas.client.util.CommonUtils;
+import org.jasig.cas.client.validation.Assertion;
+import org.jasig.cas.client.validation.TicketValidator;
+import org.jasig.cas.client.validation.ValidationException;
+
+import javax.servlet.FilterChain;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+
+/**
+ * Implementation of a Filter that checks for a "ticket" and if one is found,
+ * will attempt to validate the ticket. On a successful validation, it sets the
+ * Assertion object into the session. On an unsuccessful validation attempt, it
+ * sets the response code to 403.
+ *
+ * This filter needs to be configured after the authentication filter (if that
+ * filter exists in the chain).
+ *
+ * @author Scott Battaglia
+ * @version $Revision$ $Date$
+ * @since 3.0
+ * @see TicketValidator
+ */
+public final class CasValidationFilter extends AbstractCasFilter {
+
+ /** Instance of the ticket validator. */
+ 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;
+
+ public void doFilterInternal(final HttpServletRequest request,
+ final HttpServletResponse response, final FilterChain filterChain)
+ throws IOException, ServletException {
+ final String ticket = request.getParameter(PARAM_TICKET);
+
+ if (CommonUtils.isNotBlank(ticket)) {
+ if (log.isDebugEnabled()) {
+ log.debug("Attempting to validate ticket: " + ticket);
+ }
+
+ try {
+ final Assertion assertion = this.ticketValidator.validate(
+ ticket, new SimpleService(constructServiceUrl(request,
+ response)));
+
+ if (log.isDebugEnabled()) {
+ log.debug("Successfully authenticated user: "
+ + assertion.getPrincipal().getId());
+ }
+
+ request.setAttribute(CONST_PRINCIPAL, assertion.getPrincipal());
+
+ if (isUseSession()) {
+ request.getSession().setAttribute(CONST_ASSERTION,
+ assertion);
+ }
+ } catch (final ValidationException e) {
+ response.setStatus(HttpServletResponse.SC_FORBIDDEN);
+ log.warn(e, e);
+ throw new ServletException(e);
+ }
+ }
+
+ if (this.redirectAfterValidation) {
+ response.sendRedirect(response
+ .encodeRedirectURL(constructServiceUrl(request, response)));
+ return;
+ }
+
+ filterChain.doFilter(request, response);
+ }
+
+ /**
+ * Sets the ticket validator for validating tickets.
+ *
+ * @param ticketValidator the ticket validator instance we want to use.
+ */
+ public void setTicketValidator(final TicketValidator ticketValidator) {
+ this.ticketValidator = ticketValidator;
+ }
+
+ /**
+ * Sets the flag that tells the filter to redirect after the successful
+ * validation.
+ *
+ * @param redirectAfterValidation true if we want to redirect, false
+ * otherwise.
+ */
+ public void setRedirectAfterValidation(boolean redirectAfterValidation) {
+ this.redirectAfterValidation = redirectAfterValidation;
+ }
+
+ protected void afterPropertiesSetInternal() {
+ CommonUtils.assertNotNull(this.ticketValidator,
+ "ticketValidator cannot be null.");
+ }
+}
diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/web/filter/HttpServletRequestWrapperFilter.java b/cas-client-core/src/main/java/org/jasig/cas/client/web/filter/HttpServletRequestWrapperFilter.java
new file mode 100644
index 0000000..3ff3408
--- /dev/null
+++ b/cas-client-core/src/main/java/org/jasig/cas/client/web/filter/HttpServletRequestWrapperFilter.java
@@ -0,0 +1,298 @@
+/*
+ * Copyright 2006 The JA-SIG Collaborative. All rights reserved. See license
+ * distributed with this file and available online at
+ * http://www.uportal.org/license.html
+ */
+package org.jasig.cas.client.web.filter;
+
+import org.jasig.cas.client.validation.Assertion;
+import org.springframework.web.util.WebUtils;
+
+import javax.servlet.*;
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpSession;
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.security.Principal;
+import java.util.Enumeration;
+import java.util.Locale;
+import java.util.Map;
+
+/**
+ * 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.
+ *
+ * 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$ $Date$
+ * @since 3.0
+ */
+public final class HttpServletRequestWrapperFilter implements Filter {
+
+ public void destroy() {
+ // nothing to do
+ }
+
+ /**
+ * Wraps the HttpServletRequest in a wrapper class that delegates
+ * request.getRemoteUser 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 {
+ filterChain.doFilter(new CasHttpServletRequestWrapper(
+ (HttpServletRequest) servletRequest), servletResponse);
+ }
+
+ public void init(final FilterConfig filterConfig) throws ServletException {
+ // nothing to do
+ }
+
+ protected final class CasHttpServletRequestWrapper implements
+ HttpServletRequest {
+
+ private final HttpServletRequest request;
+
+ protected CasHttpServletRequestWrapper(final HttpServletRequest request) {
+ this.request = request;
+ }
+
+ public String getAuthType() {
+ return this.request.getAuthType();
+ }
+
+ public Cookie[] getCookies() {
+ return this.request.getCookies();
+ }
+
+ public long getDateHeader(String s) {
+ return this.request.getDateHeader(s);
+ }
+
+ public String getHeader(String s) {
+ return this.request.getHeader(s);
+ }
+
+ public Enumeration getHeaders(String s) {
+ return this.request.getHeaders(s);
+ }
+
+ public Enumeration getHeaderNames() {
+ return this.request.getHeaderNames();
+ }
+
+ public int getIntHeader(String s) {
+ return this.request.getIntHeader(s);
+ }
+
+ public String getMethod() {
+ return this.request.getMethod();
+ }
+
+ public String getPathInfo() {
+ return this.request.getPathInfo();
+ }
+
+ public String getPathTranslated() {
+ return this.request.getPathTranslated();
+ }
+
+ public String getContextPath() {
+ return this.request.getContextPath();
+ }
+
+ public String getQueryString() {
+ return this.request.getQueryString();
+ }
+
+ public String getRemoteUser() {
+ final org.jasig.cas.authentication.principal.Principal p = (org.jasig.cas.authentication.principal.Principal) this.request
+ .getAttribute(AbstractCasFilter.CONST_PRINCIPAL);
+
+ if (p != null) {
+ return p.getId();
+ }
+
+ final Assertion assertion = (Assertion) WebUtils
+ .getSessionAttribute(this.request,
+ AbstractCasFilter.CONST_ASSERTION);
+
+ if (assertion != null) {
+ return assertion.getPrincipal().getId();
+ }
+
+ return null;
+ }
+
+ public boolean isUserInRole(String s) {
+ return this.request.isUserInRole(s);
+ }
+
+ public Principal getUserPrincipal() {
+ return this.request.getUserPrincipal();
+ }
+
+ public String getRequestedSessionId() {
+ return this.request.getRequestedSessionId();
+ }
+
+ public String getRequestURI() {
+ return this.request.getRequestURI();
+ }
+
+ public StringBuffer getRequestURL() {
+ return this.request.getRequestURL();
+ }
+
+ public String getServletPath() {
+ return this.request.getServletPath();
+ }
+
+ public HttpSession getSession(boolean b) {
+ return this.request.getSession(b);
+ }
+
+ public HttpSession getSession() {
+ return this.request.getSession();
+ }
+
+ public boolean isRequestedSessionIdValid() {
+ return this.request.isRequestedSessionIdValid();
+ }
+
+ public boolean isRequestedSessionIdFromCookie() {
+ return this.request.isRequestedSessionIdFromCookie();
+ }
+
+ public boolean isRequestedSessionIdFromURL() {
+ return this.request.isRequestedSessionIdFromURL();
+ }
+
+ public boolean isRequestedSessionIdFromUrl() {
+ return this.request.isRequestedSessionIdFromUrl();
+ }
+
+ public Object getAttribute(String s) {
+ return this.request.getAttribute(s);
+ }
+
+ public Enumeration getAttributeNames() {
+ return this.request.getAttributeNames();
+ }
+
+ public String getCharacterEncoding() {
+ return this.request.getCharacterEncoding();
+ }
+
+ public void setCharacterEncoding(String s)
+ throws UnsupportedEncodingException {
+ this.request.setCharacterEncoding(s);
+ }
+
+ public int getContentLength() {
+ return this.request.getContentLength();
+ }
+
+ public String getContentType() {
+ return this.request.getContentType();
+ }
+
+ public ServletInputStream getInputStream() throws IOException {
+ return this.request.getInputStream();
+ }
+
+ public String getParameter(String s) {
+ return this.request.getParameter(s);
+ }
+
+ public Enumeration getParameterNames() {
+ return this.request.getParameterNames();
+ }
+
+ public String[] getParameterValues(String s) {
+ return this.request.getParameterValues(s);
+ }
+
+ public Map getParameterMap() {
+ return this.request.getParameterMap();
+ }
+
+ public String getProtocol() {
+ return this.request.getProtocol();
+ }
+
+ public String getScheme() {
+ return this.request.getScheme();
+ }
+
+ public String getServerName() {
+ return this.request.getServerName();
+ }
+
+ public int getServerPort() {
+ return this.request.getServerPort();
+ }
+
+ public BufferedReader getReader() throws IOException {
+ return this.request.getReader();
+ }
+
+ public String getRemoteAddr() {
+ return this.request.getRemoteAddr();
+ }
+
+ public String getRemoteHost() {
+ return this.request.getRemoteHost();
+ }
+
+ public void setAttribute(String s, Object o) {
+ this.request.setAttribute(s, o);
+ }
+
+ public void removeAttribute(String s) {
+ this.request.removeAttribute(s);
+ }
+
+ public Locale getLocale() {
+ return this.request.getLocale();
+ }
+
+ public Enumeration getLocales() {
+ return this.request.getLocales();
+ }
+
+ public boolean isSecure() {
+ return this.request.isSecure();
+ }
+
+ public RequestDispatcher getRequestDispatcher(String s) {
+ return this.request.getRequestDispatcher(s);
+ }
+
+ public String getRealPath(String s) {
+ return this.request.getRealPath(s);
+ }
+
+ public int getRemotePort() {
+ return this.request.getRemotePort();
+ }
+
+ public String getLocalName() {
+ return this.request.getLocalName();
+ }
+
+ public String getLocalAddr() {
+ return this.request.getLocalAddr();
+ }
+
+ public int getLocalPort() {
+ return this.request.getLocalPort();
+ }
+ }
+}
diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/web/filter/package.html b/cas-client-core/src/main/java/org/jasig/cas/client/web/filter/package.html
new file mode 100644
index 0000000..7329dac
--- /dev/null
+++ b/cas-client-core/src/main/java/org/jasig/cas/client/web/filter/package.html
@@ -0,0 +1,5 @@
+
+
+
This package contains all of the useful filters related to normal CAS processing, including Authentication, Validation and Authorization.
+
+
diff --git a/cas-client-core/src/main/resources/cas-client.properties b/cas-client-core/src/main/resources/cas-client.properties
new file mode 100644
index 0000000..d2ce241
--- /dev/null
+++ b/cas-client-core/src/main/resources/cas-client.properties
@@ -0,0 +1,4 @@
+cas.server.gateway=false
+cas.server.renew=false
+cas.server.url=https://localhost:8443/cas/
+cas.server.proxyCallbackUrl=https://localhost:8443/manager/proxy/Receptor
diff --git a/cas-client-core/src/main/resources/simpleFilterExample.xml b/cas-client-core/src/main/resources/simpleFilterExample.xml
new file mode 100644
index 0000000..39c7690
--- /dev/null
+++ b/cas-client-core/src/main/resources/simpleFilterExample.xml
@@ -0,0 +1,77 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ battags
+
+
+
+
\ No newline at end of file
diff --git a/cas-client-core/src/main/resources/web-simple-example.xml b/cas-client-core/src/main/resources/web-simple-example.xml
new file mode 100644
index 0000000..f83e745
--- /dev/null
+++ b/cas-client-core/src/main/resources/web-simple-example.xml
@@ -0,0 +1,82 @@
+
+
+
+
+ Java CAS Client
+
+
+
+ contextConfigLocation
+
+ /WEB-INF/simpleFilterExample.xml
+
+
+
+
+ CAS Authentication Filter Proxy
+ org.jasig.cas.client.util.FilterToBeanProxy
+
+ targetBean
+ casAuthenticationFilter
+
+
+
+
+ CAS Validation Filter Proxy
+ org.jasig.cas.client.util.FilterToBeanProxy
+
+ targetBean
+ casValidationFilter
+
+
+
+
+ CAS Authorization Filter Proxy
+ org.jasig.cas.client.util.FilterToBeanProxy
+
+ targetBean
+ casAuthorizationFilter
+
+
+
+
+ CAS Authentication Filter Proxy
+ /*
+
+
+
+ CAS Validation Filter Proxy
+ /*
+
+
+
+ CAS Authorization Filter Proxy
+ /*
+
+
+
+
+ org.springframework.web.context.ContextLoaderListener
+
+
+
+
+ casclient
+ org.jasig.cas.client.proxy.ProxyReceptorServlet
+ 1
+
+
+
+ casclient
+ /proxy/Receptor
+
+
\ No newline at end of file
diff --git a/cas-client-core/src/test/clover/clover.license b/cas-client-core/src/test/clover/clover.license
new file mode 100644
index 0000000..8506a9d
--- /dev/null
+++ b/cas-client-core/src/test/clover/clover.license
@@ -0,0 +1,166 @@
+Product: Clover
+License: Open Source License, 0.x, 1.x
+Issued: Sun Feb 13 2005 22:45:43 CST
+Expiry: Never
+Key: aae4c7035b1208e316fa6d684
+Name: Scott Battaglia
+Org: JA-SIG Central Authentication Service
+Certificate: AAACCG+Ow8B7/zEbxOMqqKwwrdpP+a1COmJGHco7sCNLjHkHnajPF+dQW
+Ct12PMy0uml0s9xuus5wKngJ9OFk5PFeh01dzQF66bhXH1bvegLfvja3Kle6BYtDv4LZgE
+gk3E0aJN4IbgTn+TgUckSevXDR4KzK77NWJfrVzkxV3/JepYRA9UAbsXHiki9WjMIJfzoZ
+unjvtTFd/vTOcyirgfT/dTPrG9PAGAjH+e37E9Xf7HnRSrmxtrGX+wdaBOlZFUIIcVHKT2
+IaGToLZnx7FvfE3rzyQCYtS+r0E+H61c+dANzySy5PEH2JEyL8M9JrwgYJSju1FWhxbXO2
+Gb7y3Diufo80+HWz6xrGzl9IlXRseoXHki8rllk5taXqVv5G3UIsTFzbjjWUDlykn557C2
+D4o9T0xQ/6dVFxak75o0MxP4aXGFMZNg/pCBH9DAU7/CKVKRBPAVx1PJ8vIy41MF4p9Mi1
+qmELNvjn9K9fwpaeiUG9qT8B0pfq/tTAObG2sZf7B1mFbA3YwEqjhNqLdkoca5swrS0DI1
+9OejIVIqjK+bvUZaqUDMxVX7fM6hwRvI9Wd+rwFG+X3wHYNPsZ+Cos8/BNPzIIoOh4SbTr
+8vIqWUdPXM4HO26uAAVRKz6FknmwM/GQ7FyJBWgIXgXK51SLn+NcifxO8uywGewHzP00ki
+frTPmy0+GrikleWry6BdWkg76hjrjQBalNlSmasi9yp9J8qdzVYvQlOBjS5EKWsvsSpXGY
+MIdupkiv4a25aXsgdpGBy4GzcSUDioChq287HBBmYRIMVvp5OYbV3/+ERNhTlCQqb6Ck4g
+891l1OJOEoMiDqcbDL8DNftlH4gybEE7zJXQRmmJKyw==
+License Agreement: CLOVER VERSION 1 (ONE) SOFTWARE LICENSE AGREEMENT
+
+1. Licenses and Software
+
+Cortex eBusiness Pty Ltd, an Australian Proprietary Limited Company
+("CENQUA") hereby grants to the purchaser (the "LICENSEE") a limited,
+revocable, worldwide, non-exclusive, non-transferable,
+non-sublicensable license to use the Clover version 1 (one) software
+(the "Software"), including any minor upgrades thereof during the Term
+(hereinafter defined) up to, but not including the next major version
+of the Software. The licensee shall not, or knowingly allow others to,
+reverse engineer, decompile, disassemble, modify, adapt, create
+derivative works from or otherwise attempt to derive source code from
+the Software provided. And, in accordance with the terms and
+conditions of this Software License Agreement (the "Agreement"), the
+Software shall be used solely by the licensed users in accordance with
+the following edition specific conditions:
+
+a) Server Edition
+
+A Server Edition license entitles the Licensee to execute one instance
+of Clover Server Edition on one (1) machine for the purposes of
+instrumenting source code and generating reports. There are no
+limitations on the use of the instrumented source code or generated
+reports produced by Server Edition.
+
+b) Workstation Edition
+
+A Workstation Edition license entitles the licensee to use Clover
+Workstation Edition on one (1) machine by one (1) individual end
+user. Workstation Edition does not permit the generation of reports
+for distribution.
+
+c) Team Edition
+
+A Team Edition license entitles the licensee to use Clover Team
+edition on any number of machines solely by the licensed number of
+users. Reports generated by Clover Team Edition are strictly for use
+only by the licensed number of individual end users.
+
+2. License Fee
+
+In exchange for the License(s), the Licensee shall pay to Cenqua a
+one-time, up front, non-refundable license fee. At the sole discretion
+of Cenqua this fee will be waived for non-commercial
+projects. Notwithstanding the Licensee's payment of the License Fee,
+Cenqua reserves the right to terminate the License if Cenqua discovers
+that the Licensee and/or the Licensee's use of the Software is in
+breach of this Agreement.
+
+3. Proprietary Rights
+
+Cenqua will retain all right, title and interest in and to the
+Software, all copies thereof, and Cenqua website(s), software, and
+other intellectual property, including, but not limited to, ownership
+of all copyrights, look and feel, trademark rights, design rights,
+trade secret rights and any and all other intellectual property and
+other proprietary rights therein. The Licensee will not directly or
+indirectly obtain or attempt to obtain at any time, any right, title
+or interest by registration or otherwise in or to the trademarks,
+service marks, copyrights, trade names, symbols, logos or designations
+or other intellectual property rights owned or used by Cenqua. All
+technical manuals or other information provided by Cenqua to the
+Licensee shall be the sole property of Cenqua.
+
+4. Term and Termination
+
+Subject to the other provisions hereof, this Agreement shall commence
+upon the Licensee's opting into this Agreement and continue until the
+Licensee discontinues use of the Software or the Agreement terminates
+automatically upon the Licensee's breach of any term or condition of
+this Agreement (the "Term"). Upon any such termination, the Licensee
+will delete the Software immediately.
+
+5. Copying & Transfer
+
+The Licensee may copy the Software for back-up purposes only. The
+Licensee may not assign or otherwise transfer the Software to any
+third party.
+
+6. Specific Disclaimer of Warranty and Limitation of Liability
+
+THE SOFTWARE IS PROVIDED WITHOUT WARRANTY OF ANY KIND. CENQUA
+DISCLAIMS ALL WARRANTIES, EXPRESSED OR IMPLIED, INCLUDING BUT NOT
+LIMITED TO THE WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+PARTICULAR PURPOSE. CENQUA WILL NOT BE LIABLE FOR ANY DAMAGES
+ASSOCIATED WITH THE SOFTWARE, INCLUDING, WITHOUT LIMITATION, ORDINARY,
+INCIDENTAL, INDIRECT, OR CONSEQUENTIAL DAMAGES OF ANY KIND, INCLUDING
+BUT NOT LIMITED TO DAMAGES RELATING TO LOST DATA OR LOST PROFITS, EVEN
+IF CENQUA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+
+7. Warranties and Representations
+
+Licensee Indemnification. CENQUA agrees to indemnify, defend and hold
+the Licensee harmless from and against any and all liabilities,
+damages, losses, claims, costs, and expenses (including reasonable
+legal fees) arising out of or resulting from the Software or the use
+thereof infringing upon, misappropriating or violating any patents,
+copyrights, trademarks, or trade secret rights or other proprietary
+rights of persons, firms or entities who are not parties to this
+Agreement.
+
+CENQUA Indemnification. The Licensee warrants and represents that the
+Licensee's actions with regard to the Software will be in compliance
+with all applicable laws; and the Licensee agrees to indemnify,
+defend, and hold CENQUA harmless from and against any and all
+liabilities, damages, losses, claims, costs, and expenses (including
+reasonable legal fees) arising out of or resulting from the
+Licensee's failure to observe the use restrictions set forth herein.
+
+8. Publicity
+
+The Licensee grants permission for CENQUA to use Licensee's name
+solely in customer lists. CENQUA shall not, without prior consent in
+writing, use the Licensee's name, or that of its affiliates, in any
+form with the specific exception of customer lists. CENQUA agrees to
+remove Licensee's name from any and all materials within 7 days if
+notified by the Licensee in writing.
+
+9. Governing Law
+
+This Agreement shall be governed by the laws of New South Wales,
+Australia.
+
+10. Independent Contractors
+
+The parties are independent contractors with respect to each other,
+and nothing in this Agreement shall be construed as creating an
+employer-employee relationship, a partnership, agency relationship or
+a joint venture between the parties.
+
+11. Assignment
+
+This Agreement is not assignable or transferable by the Licensee.
+CENQUA in its sole discretion may transfer a license to a third party
+at the written request of the Licensee.
+
+12. Entire Agreement
+
+This Agreement constitutes the entire agreement between the parties
+concerning the Licensee's use of the Software. This Agreement
+supersedes any prior verbal understanding between the parties and any
+Licensee purchase order or other ordering document, regardless of
+whether such document is received by CENQUA before or after execution
+of this Agreement. This Agreement may be amended only in writing by
+CENQUA.
diff --git a/cas-client-core/src/test/java/org/jasig/cas/client/PublicTestHttpServer.java b/cas-client-core/src/test/java/org/jasig/cas/client/PublicTestHttpServer.java
new file mode 100644
index 0000000..334510e
--- /dev/null
+++ b/cas-client-core/src/test/java/org/jasig/cas/client/PublicTestHttpServer.java
@@ -0,0 +1,111 @@
+package org.jasig.cas.client;
+
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.UnsupportedEncodingException;
+import java.net.ServerSocket;
+import java.net.Socket;
+
+/**
+ * @author Scott Battaglia
+ * @version $Revision$ $Date$
+ * @since 3.0
+ */
+public 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
+}
diff --git a/cas-client-core/src/test/java/org/jasig/cas/client/authorization/AbstractCasAuthorizedDeciderTests.java b/cas-client-core/src/test/java/org/jasig/cas/client/authorization/AbstractCasAuthorizedDeciderTests.java
new file mode 100644
index 0000000..4ee2957
--- /dev/null
+++ b/cas-client-core/src/test/java/org/jasig/cas/client/authorization/AbstractCasAuthorizedDeciderTests.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2006 The JA-SIG Collaborative. All rights reserved. See license
+ * distributed with this file and available online at
+ * http://www.uportal.org/license.html
+ */
+package org.jasig.cas.client.authorization;
+
+import org.jasig.cas.authentication.principal.SimplePrincipal;
+
+import junit.framework.TestCase;
+
+/**
+ * Abstract test for all CasAuthorizedDecider implementations.
+ *
+ * @author Scott Battaglia
+ * @version $Revision$ $Date$
+ * @since 3.0
+ */
+public abstract class AbstractCasAuthorizedDeciderTests extends TestCase {
+
+ private CasAuthorizedDecider casAuthorizedDecider;
+
+ protected abstract CasAuthorizedDecider getCasAuthorizedDeciderImpl();
+
+ protected void setUp() throws Exception {
+ this.casAuthorizedDecider = getCasAuthorizedDeciderImpl();
+ }
+
+ public void testIsAuthorized() {
+ assertTrue(this.casAuthorizedDecider
+ .isAuthorizedToUseApplication(new SimplePrincipal("scott")));
+ }
+
+ public void testIsNotAuthorized() {
+ assertFalse(this.casAuthorizedDecider
+ .isAuthorizedToUseApplication(new SimplePrincipal("not")));
+ }
+}
diff --git a/cas-client-core/src/test/java/org/jasig/cas/client/authorization/AuthorizationExceptionTests.java b/cas-client-core/src/test/java/org/jasig/cas/client/authorization/AuthorizationExceptionTests.java
new file mode 100644
index 0000000..5430499
--- /dev/null
+++ b/cas-client-core/src/test/java/org/jasig/cas/client/authorization/AuthorizationExceptionTests.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2006 The JA-SIG Collaborative. All rights reserved. See license
+ * distributed with this file and available online at
+ * http://www.uportal.org/license.html
+ */
+package org.jasig.cas.client.authorization;
+
+import junit.framework.TestCase;
+
+/**
+ * @author Scott Battaglia
+ * @version $Revision$ $Date$
+ * @since 3.0
+ */
+public class AuthorizationExceptionTests extends TestCase {
+
+ private static final String CONST_MESSAGE = "t";
+
+ private static final Exception CONST_THROWABLE = new RuntimeException();
+
+ public void testMessageThrowable() {
+ final AuthorizationException e = new AuthorizationException(
+ CONST_MESSAGE, CONST_THROWABLE);
+
+ assertEquals(CONST_MESSAGE, e.getMessage());
+ assertEquals(CONST_THROWABLE, e.getCause());
+ }
+
+ public void testMessage() {
+ final AuthorizationException e = new AuthorizationException(
+ CONST_MESSAGE);
+
+ assertEquals(CONST_MESSAGE, e.getMessage());
+ }
+
+ public void testThrowable() {
+ final AuthorizationException e = new AuthorizationException(
+ CONST_THROWABLE);
+
+ assertEquals(CONST_THROWABLE, e.getCause());
+ }
+}
diff --git a/cas-client-core/src/test/java/org/jasig/cas/client/authorization/DefaultCasAuthorizedDeciderImplTests.java b/cas-client-core/src/test/java/org/jasig/cas/client/authorization/DefaultCasAuthorizedDeciderImplTests.java
new file mode 100644
index 0000000..427d7ba
--- /dev/null
+++ b/cas-client-core/src/test/java/org/jasig/cas/client/authorization/DefaultCasAuthorizedDeciderImplTests.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright 2006 The JA-SIG Collaborative. All rights reserved. See license
+ * distributed with this file and available online at
+ * http://www.uportal.org/license.html
+ */
+package org.jasig.cas.client.authorization;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public final class DefaultCasAuthorizedDeciderImplTests extends
+ AbstractCasAuthorizedDeciderTests {
+
+ public CasAuthorizedDecider getCasAuthorizedDeciderImpl() {
+ final DefaultCasAuthorizedDeciderImpl impl = new DefaultCasAuthorizedDeciderImpl();
+ final List list = new ArrayList();
+ list.add("scott");
+ impl.setUsers(list);
+ impl.init();
+ return impl;
+ }
+
+}
diff --git a/cas-client-core/src/test/java/org/jasig/cas/client/proxy/AbstractProxyGrantingTicketStorageTests.java b/cas-client-core/src/test/java/org/jasig/cas/client/proxy/AbstractProxyGrantingTicketStorageTests.java
new file mode 100644
index 0000000..aca2b4b
--- /dev/null
+++ b/cas-client-core/src/test/java/org/jasig/cas/client/proxy/AbstractProxyGrantingTicketStorageTests.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2006 The JA-SIG Collaborative. All rights reserved. See license
+ * distributed with this file and available online at
+ * http://www.uportal.org/license.html
+ */
+package org.jasig.cas.client.proxy;
+
+import junit.framework.TestCase;
+
+/**
+ * @author Scott Battaglia
+ * @version $Revision$ $Date$
+ * @since 3.0
+ */
+public abstract class AbstractProxyGrantingTicketStorageTests extends TestCase {
+
+ protected ProxyGrantingTicketStorageImpl proxyGrantingTicketStorageImpl;
+
+ public void testNullValue() {
+ assertNull(this.proxyGrantingTicketStorageImpl
+ .retrieve("this should not exist"));
+ }
+
+ public void testValueExists() {
+ final String CONST_KEY = "testKey";
+ final String CONST_VALUE = "testValue";
+
+ this.proxyGrantingTicketStorageImpl.save(CONST_KEY, CONST_VALUE);
+
+ assertEquals(CONST_VALUE, this.proxyGrantingTicketStorageImpl
+ .retrieve(CONST_KEY));
+ }
+}
diff --git a/cas-client-core/src/test/java/org/jasig/cas/client/proxy/ProxyGrantingTicketStorageImplTests.java b/cas-client-core/src/test/java/org/jasig/cas/client/proxy/ProxyGrantingTicketStorageImplTests.java
new file mode 100644
index 0000000..20e686b
--- /dev/null
+++ b/cas-client-core/src/test/java/org/jasig/cas/client/proxy/ProxyGrantingTicketStorageImplTests.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright 2006 The JA-SIG Collaborative. All rights reserved. See license
+ * distributed with this file and available online at
+ * http://www.uportal.org/license.html
+ */
+package org.jasig.cas.client.proxy;
+
+/**
+ * Test cases for the ProxyGrantingTicketStorageImplTests.
+ *
+ * @author Scott Battaglia
+ * @version $Revision$ $Date$
+ * @since 3.0
+ */
+public class ProxyGrantingTicketStorageImplTests extends
+ AbstractProxyGrantingTicketStorageTests {
+
+ protected void setUp() throws Exception {
+ this.proxyGrantingTicketStorageImpl = new ProxyGrantingTicketStorageImpl();
+ this.proxyGrantingTicketStorageImpl.setTimeout(1000);
+ this.proxyGrantingTicketStorageImpl.init();
+ }
+}
diff --git a/cas-client-core/src/test/java/org/jasig/cas/client/proxy/SpringConfiguredProxyReceptorServletTests.java b/cas-client-core/src/test/java/org/jasig/cas/client/proxy/SpringConfiguredProxyReceptorServletTests.java
new file mode 100644
index 0000000..1784abb
--- /dev/null
+++ b/cas-client-core/src/test/java/org/jasig/cas/client/proxy/SpringConfiguredProxyReceptorServletTests.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2006 The JA-SIG Collaborative. All rights reserved. See license
+ * distributed with this file and available online at
+ * http://www.uportal.org/license.html
+ */
+package org.jasig.cas.client.proxy;
+
+import junit.framework.TestCase;
+import org.springframework.mock.web.MockHttpServletRequest;
+import org.springframework.mock.web.MockHttpServletResponse;
+import org.springframework.mock.web.MockServletConfig;
+import org.springframework.mock.web.MockServletContext;
+import org.springframework.web.context.WebApplicationContext;
+import org.springframework.web.context.support.XmlWebApplicationContext;
+
+import javax.servlet.ServletConfig;
+
+public class SpringConfiguredProxyReceptorServletTests extends TestCase {
+
+ private XmlWebApplicationContext webApplicationContext;
+
+ public void testNoProxyGrantingTicketStorage() {
+ AbstractProxyReceptorServlet servlet = new SpringConfiguredProxyReceptorServlet();
+ try {
+ servlet
+ .init(getServletConfig("classpath:badProxyGrantingTicketStorageConfig.xml"));
+ fail("Exception expected.");
+ } catch (final Exception e) {
+ // expected
+ }
+ }
+
+ public void testTwoProxyGrantingTicketStorage() {
+ AbstractProxyReceptorServlet servlet = new SpringConfiguredProxyReceptorServlet();
+ try {
+ servlet
+ .init(getServletConfig("classpath:twoProxyGrantingTicketStorageConfig.xml"));
+ fail("Exception expected.");
+ } catch (final Exception e) {
+ // expected
+ }
+ }
+
+ public void testOneProxyGrantingTicketStorage() {
+ AbstractProxyReceptorServlet servlet = new SpringConfiguredProxyReceptorServlet();
+ try {
+ servlet
+ .init(getServletConfig("classpath:oneProxyGrantingTicketStorageConfig.xml"));
+ } catch (final Exception e) {
+ fail("Unexpected excception.");
+ }
+ }
+
+ public void testNoPgtOrPgtIouPassed() throws Exception {
+ final AbstractProxyReceptorServlet servlet = new SpringConfiguredProxyReceptorServlet();
+ servlet
+ .init(getServletConfig("classpath:proxyGrantingTicketStorageConfig.xml"));
+
+ final MockHttpServletResponse response = new MockHttpServletResponse();
+ servlet.doGet(new MockHttpServletRequest(), response);
+
+ assertEquals("", response.getContentAsString());
+ }
+
+ public void testPgtPassed() throws Exception {
+ final AbstractProxyReceptorServlet servlet = new SpringConfiguredProxyReceptorServlet();
+ servlet
+ .init(getServletConfig("classpath:proxyGrantingTicketStorageConfig.xml"));
+
+ final ProxyGrantingTicketStorage storage = (ProxyGrantingTicketStorage) this.webApplicationContext
+ .getBean("proxyGrantingTicketStorage");
+
+ final MockHttpServletRequest request = new MockHttpServletRequest();
+ request.setParameter("pgtIou", "test");
+ request.setParameter("pgtId", "testpgtId");
+ final MockHttpServletResponse response = new MockHttpServletResponse();
+ servlet.doGet(request, response);
+
+ assertTrue(!"".equals(response.getContentAsString()));
+ assertEquals("testpgtId", storage.retrieve("test"));
+ }
+
+ private ServletConfig getServletConfig(final String contextLocation) {
+ this.webApplicationContext = new XmlWebApplicationContext();
+ this.webApplicationContext
+ .setConfigLocations(new String[] {contextLocation});
+ this.webApplicationContext.refresh();
+
+ MockServletContext context = new MockServletContext();
+ context.setAttribute(
+ WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE,
+ this.webApplicationContext);
+
+ return new MockServletConfig(context);
+ }
+}
diff --git a/cas-client-core/src/test/java/org/jasig/cas/client/util/CommonUtilsTests.java b/cas-client-core/src/test/java/org/jasig/cas/client/util/CommonUtilsTests.java
new file mode 100644
index 0000000..ee3d5f2
--- /dev/null
+++ b/cas-client-core/src/test/java/org/jasig/cas/client/util/CommonUtilsTests.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2006 The JA-SIG Collaborative. All rights reserved. See license
+ * distributed with this file and available online at
+ * http://www.uportal.org/license.html
+ */
+package org.jasig.cas.client.util;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+import junit.framework.TestCase;
+
+/**
+ * Tests for the CommonUtils.
+ *
+ * @author Scott Battaglia
+ * @version $Revision$ $Date$
+ * @since 3.0
+ */
+public 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(" "));
+ }
+}
diff --git a/cas-client-core/src/test/java/org/jasig/cas/client/util/DelegatingFilterTests.java b/cas-client-core/src/test/java/org/jasig/cas/client/util/DelegatingFilterTests.java
new file mode 100644
index 0000000..a64b1d3
--- /dev/null
+++ b/cas-client-core/src/test/java/org/jasig/cas/client/util/DelegatingFilterTests.java
@@ -0,0 +1,143 @@
+/*
+ * Copyright 2006 The JA-SIG Collaborative. All rights reserved. See license
+ * distributed with this file and available online at
+ * http://www.uportal.org/license.html
+ */
+package org.jasig.cas.client.util;
+
+import junit.framework.TestCase;
+import org.springframework.mock.web.MockHttpServletRequest;
+import org.springframework.mock.web.MockHttpServletResponse;
+
+import javax.servlet.*;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Test Cases for DelegatingFilter
+ *
+ * @author Scott Battaglia
+ * @version $Revision$ $Date$
+ * @since 3.0
+ */
+public class DelegatingFilterTests extends TestCase {
+
+ private DelegatingFilter delegatingFilter;
+
+ protected int filterExecuted = -1;
+
+ protected void setUp() throws Exception {
+ final Map delegators = new HashMap();
+
+ delegators.put("1", new TestFilter(1));
+
+ this.filterExecuted = -1;
+ this.delegatingFilter = new DelegatingFilter();
+ this.delegatingFilter.setDefaultFilter(new TestFilter(0));
+ this.delegatingFilter.setExactMatch(true);
+ this.delegatingFilter.setDelegators(delegators);
+ this.delegatingFilter.setRequestParameterName("test");
+ this.delegatingFilter.init();
+ this.delegatingFilter.init(null);
+ }
+
+ protected void tearDown() throws Exception {
+ this.delegatingFilter.destroy();
+ }
+
+ public void testExactMatchFound() throws Exception {
+ final MockHttpServletRequest request = new MockHttpServletRequest();
+ request.addParameter("test", "1");
+
+ this.delegatingFilter.doFilter(request, new MockHttpServletResponse(),
+ null);
+
+ assertEquals(1, this.filterExecuted);
+ }
+
+ public void testNoMatchFound() throws Exception {
+ final MockHttpServletRequest request = new MockHttpServletRequest();
+ request.addParameter("test", "0");
+
+ this.delegatingFilter.doFilter(request, new MockHttpServletResponse(),
+ null);
+
+ assertEquals(0, this.filterExecuted);
+ }
+
+ public void testNoParam() throws Exception {
+ this.delegatingFilter.doFilter(new MockHttpServletRequest(),
+ new MockHttpServletResponse(), null);
+
+ assertEquals(0, this.filterExecuted);
+ }
+
+ public void testRegularExpressionMatch() throws Exception {
+
+ final Map delegators = new HashMap();
+
+ delegators.put("1.*", new TestFilter(1));
+
+ this.delegatingFilter.setExactMatch(false);
+ this.delegatingFilter.setDelegators(delegators);
+ MockHttpServletRequest request = new MockHttpServletRequest();
+ request.addParameter("test", "1");
+
+ this.delegatingFilter.doFilter(request, new MockHttpServletResponse(),
+ null);
+
+ assertEquals(1, this.filterExecuted);
+ request = new MockHttpServletRequest();
+ request.addParameter("test", "15");
+
+ this.delegatingFilter.doFilter(request, new MockHttpServletResponse(),
+ null);
+
+ assertEquals(1, this.filterExecuted);
+ request = new MockHttpServletRequest();
+ request.addParameter("test", "0");
+
+ this.delegatingFilter.doFilter(request, new MockHttpServletResponse(),
+ null);
+
+ assertEquals(0, this.filterExecuted);
+ }
+
+ public void testForIllegalArgument() {
+ Map map = new HashMap();
+ map.put("test", new Object());
+
+ this.delegatingFilter.setDelegators(map);
+
+ try {
+ this.delegatingFilter.init();
+ fail("Exception expected.");
+ } catch (IllegalArgumentException e) {
+ // expected
+ }
+ }
+
+ private class TestFilter implements Filter {
+
+ private final int i;
+
+ public TestFilter(final int i) {
+ this.i = i;
+ }
+
+ public void destroy() {
+ // nothing to do here
+ }
+
+ public void doFilter(ServletRequest arg0, ServletResponse arg1,
+ FilterChain arg2) throws IOException, ServletException {
+ DelegatingFilterTests.this.filterExecuted = this.i;
+
+ }
+
+ public void init(FilterConfig arg0) throws ServletException {
+ // nothing to do
+ }
+ }
+}
diff --git a/cas-client-core/src/test/java/org/jasig/cas/client/validation/AbstractTicketValidatorTests.java b/cas-client-core/src/test/java/org/jasig/cas/client/validation/AbstractTicketValidatorTests.java
new file mode 100644
index 0000000..2b5d242
--- /dev/null
+++ b/cas-client-core/src/test/java/org/jasig/cas/client/validation/AbstractTicketValidatorTests.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2006 The JA-SIG Collaborative. All rights reserved. See license
+ * distributed with this file and available online at
+ * http://www.uportal.org/license.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$ $Date$
+ * @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";
+}
diff --git a/cas-client-core/src/test/java/org/jasig/cas/client/validation/AssertionImplTests.java b/cas-client-core/src/test/java/org/jasig/cas/client/validation/AssertionImplTests.java
new file mode 100644
index 0000000..1b33057
--- /dev/null
+++ b/cas-client-core/src/test/java/org/jasig/cas/client/validation/AssertionImplTests.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2006 The JA-SIG Collaborative. All rights reserved. See license
+ * distributed with this file and available online at
+ * http://www.uportal.org/license.html
+ */
+package org.jasig.cas.client.validation;
+
+import junit.framework.TestCase;
+import org.jasig.cas.authentication.principal.Principal;
+import org.jasig.cas.authentication.principal.SimplePrincipal;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Test cases for the {@link AssertionImpl}.
+ *
+ * @author Scott Battaglia
+ * @version $Revision$ $Date$
+ * @since 3.0
+ */
+public final class AssertionImplTests extends TestCase {
+
+ private static final Principal CONST_PRINCIPAL = new SimplePrincipal("test");
+
+ private static final String CONST_PROXY_GRANTING_TICKET_IOU = "proxyGrantingTicketIou";
+
+ 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.getProxyGrantingTicketId());
+ }
+
+ public void testCompleteConstructor() {
+ final Assertion assertion = new AssertionImpl(CONST_PRINCIPAL,
+ CONST_ATTRIBUTES, CONST_PROXY_GRANTING_TICKET_IOU);
+
+ assertEquals(CONST_PRINCIPAL, assertion.getPrincipal());
+ assertEquals(CONST_ATTRIBUTES, assertion.getAttributes());
+ assertEquals(CONST_PROXY_GRANTING_TICKET_IOU, assertion
+ .getProxyGrantingTicketId());
+ }
+}
diff --git a/cas-client-core/src/test/java/org/jasig/cas/client/validation/Cas10TicketValidatorTests.java b/cas-client-core/src/test/java/org/jasig/cas/client/validation/Cas10TicketValidatorTests.java
new file mode 100644
index 0000000..1604b75
--- /dev/null
+++ b/cas-client-core/src/test/java/org/jasig/cas/client/validation/Cas10TicketValidatorTests.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2006 The JA-SIG Collaborative. All rights reserved. See license
+ * distributed with this file and available online at
+ * http://www.uportal.org/license.html
+ */
+package org.jasig.cas.client.validation;
+
+
+import org.apache.commons.httpclient.HttpClient;
+import org.jasig.cas.authentication.principal.SimpleService;
+import org.jasig.cas.client.PublicTestHttpServer;
+
+import java.io.UnsupportedEncodingException;
+
+/**
+ * Test cases for the {@link Cas10TicketValidator}.
+ *
+ * @author Scott Battaglia
+ * @version $Revision$ $Date$
+ * @since 3.0
+ */
+public final class Cas10TicketValidatorTests extends AbstractTicketValidatorTests {
+
+ private Cas10TicketValidator ticketValidator;
+
+ public Cas10TicketValidatorTests() {
+ super();
+ }
+
+ protected void setUp() throws Exception {
+ this.ticketValidator = new Cas10TicketValidator();
+ this.ticketValidator.setCasServerUrl(CONST_CAS_SERVER_URL);
+ this.ticketValidator.setRenew(true);
+ this.ticketValidator.setHttpClient(new HttpClient());
+ this.ticketValidator.init();
+ }
+
+ public void testNoResponse() throws Exception {
+ PublicTestHttpServer.instance().content = "no\n\n"
+ .getBytes(PublicTestHttpServer.instance().encoding);
+ try {
+ this.ticketValidator.validate("testTicket", new SimpleService(
+ "myService"));
+ fail("ValidationException expected.");
+ } catch (final ValidationException e) {
+ // expected
+ }
+ }
+
+ public void testYesResponse() throws ValidationException,
+ UnsupportedEncodingException {
+ PublicTestHttpServer.instance().content = "yes\nusername\n\n"
+ .getBytes(PublicTestHttpServer.instance().encoding);
+ final Assertion assertion = this.ticketValidator.validate("testTicket",
+ new SimpleService("myService"));
+ assertEquals(CONST_USERNAME, assertion.getPrincipal().getId());
+ }
+
+ public void testBadResponse() throws UnsupportedEncodingException {
+ PublicTestHttpServer.instance().content = "falalala\n\n"
+ .getBytes(PublicTestHttpServer.instance().encoding);
+ try {
+ this.ticketValidator.validate("testTicket", new SimpleService(
+ "myService"));
+ fail("ValidationException expected.");
+ } catch (final ValidationException e) {
+ // expected
+ }
+ }
+}
diff --git a/cas-client-core/src/test/java/org/jasig/cas/client/validation/Cas20ProxyTicketValidatorTests.java b/cas-client-core/src/test/java/org/jasig/cas/client/validation/Cas20ProxyTicketValidatorTests.java
new file mode 100644
index 0000000..99e7129
--- /dev/null
+++ b/cas-client-core/src/test/java/org/jasig/cas/client/validation/Cas20ProxyTicketValidatorTests.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2006 The JA-SIG Collaborative. All rights reserved. See license
+ * distributed with this file and available online at
+ * http://www.uportal.org/license.html
+ */
+package org.jasig.cas.client.validation;
+
+
+import org.apache.commons.httpclient.HttpClient;
+import org.jasig.cas.authentication.principal.SimpleService;
+import org.jasig.cas.client.PublicTestHttpServer;
+import org.jasig.cas.client.proxy.ProxyGrantingTicketStorage;
+import org.jasig.cas.client.proxy.ProxyGrantingTicketStorageImpl;
+
+import java.io.UnsupportedEncodingException;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Test cases for the {@link Cas20ProxyTicketValidator}.
+ *
+ * @author Scott Battaglia
+ * @version $Revision$ $Date$
+ * @since 3.0
+ */
+public final class Cas20ProxyTicketValidatorTests extends
+ AbstractTicketValidatorTests {
+
+ private Cas20ProxyTicketValidator ticketValidator;
+
+ public Cas20ProxyTicketValidatorTests() {
+ super();
+ }
+
+ protected void setUp() throws Exception {
+ ProxyGrantingTicketStorage proxyGrantingTicketStorage = getProxyGrantingTicketStorage();
+ this.ticketValidator = new Cas20ProxyTicketValidator();
+ this.ticketValidator.setCasServerUrl(CONST_CAS_SERVER_URL);
+ this.ticketValidator.setRenew(true);
+ this.ticketValidator
+ .setProxyGrantingTicketStorage(proxyGrantingTicketStorage);
+ this.ticketValidator.setHttpClient(new HttpClient());
+
+ final List list = new ArrayList();
+ list.add("proxy1 proxy2 proxy3");
+ this.ticketValidator.setProxyChains(list);
+
+ this.ticketValidator.init();
+ }
+
+ private ProxyGrantingTicketStorage getProxyGrantingTicketStorage()
+ throws Exception {
+ ProxyGrantingTicketStorageImpl proxyGrantingTicketStorageImpl = new ProxyGrantingTicketStorageImpl();
+ proxyGrantingTicketStorageImpl.init();
+
+ return proxyGrantingTicketStorageImpl;
+ }
+
+ public void testProxyChainWithValidProxy() throws ValidationException,
+ UnsupportedEncodingException {
+ final String USERNAME = "username";
+ final String RESPONSE = "usernamePGTIOU-84678-8a9d...proxy1proxy2proxy3";
+ PublicTestHttpServer.instance().content = RESPONSE
+ .getBytes(PublicTestHttpServer.instance().encoding);
+
+ final Assertion assertion = this.ticketValidator.validate("test",
+ new SimpleService("test"));
+ assertEquals(USERNAME, assertion.getPrincipal().getId());
+ }
+
+ public void testProxyChainWithInvalidProxy() throws ValidationException,
+ UnsupportedEncodingException {
+ final String RESPONSE = "usernamePGTIOU-84678-8a9d...proxy7proxy2proxy3";
+ PublicTestHttpServer.instance().content = RESPONSE
+ .getBytes(PublicTestHttpServer.instance().encoding);
+
+ try {
+ this.ticketValidator.validate("test", new SimpleService("test"));
+ fail("Invalid proxy chain");
+ } catch (InvalidProxyChainValidationException e) {
+ // expected
+ }
+ }
+}
diff --git a/cas-client-core/src/test/java/org/jasig/cas/client/validation/Cas20ServiceTicketValidatorTests.java b/cas-client-core/src/test/java/org/jasig/cas/client/validation/Cas20ServiceTicketValidatorTests.java
new file mode 100644
index 0000000..c8eb98b
--- /dev/null
+++ b/cas-client-core/src/test/java/org/jasig/cas/client/validation/Cas20ServiceTicketValidatorTests.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright 2006 The JA-SIG Collaborative. All rights reserved. See license
+ * distributed with this file and available online at
+ * http://www.uportal.org/license.html
+ */
+package org.jasig.cas.client.validation;
+
+
+import org.apache.commons.httpclient.HttpClient;
+import org.jasig.cas.authentication.principal.SimpleService;
+import org.jasig.cas.client.PublicTestHttpServer;
+import org.jasig.cas.client.proxy.ProxyGrantingTicketStorage;
+import org.jasig.cas.client.proxy.ProxyGrantingTicketStorageImpl;
+
+import java.io.UnsupportedEncodingException;
+
+/**
+ * Test cases for the {@link Cas20ServiceTicketValidator}.
+ *
+ * @author Scott Battaglia
+ * @version $Revision$ $Date$
+ * @since 3.0
+ */
+public final class Cas20ServiceTicketValidatorTests extends
+ AbstractTicketValidatorTests {
+
+ private Cas20ServiceTicketValidator ticketValidator;
+
+ private ProxyGrantingTicketStorage proxyGrantingTicketStorage;
+
+ public Cas20ServiceTicketValidatorTests() {
+ super();
+ }
+
+ protected void setUp() throws Exception {
+ this.proxyGrantingTicketStorage = getProxyGrantingTicketStorage();
+ this.ticketValidator = new Cas20ServiceTicketValidator();
+ this.ticketValidator.setCasServerUrl(CONST_CAS_SERVER_URL);
+ this.ticketValidator.setRenew(true);
+ this.ticketValidator
+ .setProxyGrantingTicketStorage(this.proxyGrantingTicketStorage);
+ this.ticketValidator.setHttpClient(new HttpClient());
+ this.ticketValidator.init();
+ }
+
+ private ProxyGrantingTicketStorage getProxyGrantingTicketStorage()
+ throws Exception {
+ ProxyGrantingTicketStorageImpl proxyGrantingTicketStorageImpl = new ProxyGrantingTicketStorageImpl();
+ proxyGrantingTicketStorageImpl.init();
+
+ return proxyGrantingTicketStorageImpl;
+ }
+
+ public void testNoResponse() throws UnsupportedEncodingException {
+ final String RESPONSE = "Ticket ST-1856339-aA5Yuvrxzpv8Tau1cYQ7 not recognized";
+ PublicTestHttpServer.instance().content = RESPONSE
+ .getBytes(PublicTestHttpServer.instance().encoding);
+ try {
+ this.ticketValidator.validate("test", new SimpleService("test"));
+ fail("ValidationException expected due to 'no' response");
+ } catch (final ValidationException e) {
+ // expected
+ }
+ }
+
+ public void testYesResponseButNoPgt() throws ValidationException,
+ UnsupportedEncodingException {
+ final String USERNAME = "username";
+ final String RESPONSE = ""
+ + USERNAME
+ + "";
+ PublicTestHttpServer.instance().content = RESPONSE
+ .getBytes(PublicTestHttpServer.instance().encoding);
+
+ final Assertion assertion = this.ticketValidator.validate("test",
+ new SimpleService("test"));
+ assertEquals(USERNAME, assertion.getPrincipal().getId());
+ }
+
+ public void testYesResponseWithPgt() throws ValidationException,
+ UnsupportedEncodingException {
+ final String USERNAME = "username";
+ final String PGTIOU = "testPgtIou";
+ final String PGT = "test";
+ final String RESPONSE = ""
+ + USERNAME
+ + ""
+ + PGTIOU
+ + "";
+
+ PublicTestHttpServer.instance().content = RESPONSE
+ .getBytes(PublicTestHttpServer.instance().encoding);
+
+ this.proxyGrantingTicketStorage.save(PGTIOU, PGT);
+
+ final Assertion assertion = this.ticketValidator.validate("test",
+ new SimpleService("test"));
+ assertEquals(USERNAME, assertion.getPrincipal().getId());
+ assertEquals(PGT, assertion.getProxyGrantingTicketId());
+ }
+
+ public void testInvalidResponse() throws Exception {
+ final String RESPONSE = "";
+ PublicTestHttpServer.instance().content = RESPONSE
+ .getBytes(PublicTestHttpServer.instance().encoding);
+ try {
+ this.ticketValidator.validate("test", new SimpleService("test"));
+ fail("ValidationException expected due to invalid response.");
+ } catch (final ValidationException e) {
+ // expected
+ }
+ }
+}
diff --git a/cas-client-core/src/test/java/org/jasig/cas/client/web/filter/CasAuthenticationFilterTests.java b/cas-client-core/src/test/java/org/jasig/cas/client/web/filter/CasAuthenticationFilterTests.java
new file mode 100644
index 0000000..a4dba6f
--- /dev/null
+++ b/cas-client-core/src/test/java/org/jasig/cas/client/web/filter/CasAuthenticationFilterTests.java
@@ -0,0 +1,162 @@
+/*
+ * Copyright 2006 The JA-SIG Collaborative. All rights reserved. See license
+ * distributed with this file and available online at
+ * http://www.uportal.org/license.html
+ */
+package org.jasig.cas.client.web.filter;
+
+import junit.framework.TestCase;
+import org.jasig.cas.authentication.principal.SimplePrincipal;
+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 CasAuthenticationFilter.
+ *
+ * @author Scott Battaglia
+ * @version $Revision$ $Date$
+ * @since 3.0
+ */
+public final class CasAuthenticationFilterTests 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 CasAuthenticationFilter filter;
+
+ protected void setUp() throws Exception {
+ this.filter = new CasAuthenticationFilter();
+ this.filter.setCasServerLoginUrl(CAS_LOGIN_URL);
+ this.filter.setGateway(false);
+ this.filter.setRenew(false);
+ this.filter.setServiceUrl(CAS_SERVICE_URL);
+ this.filter.init(new MockFilterConfig());
+ this.filter.init();
+ }
+
+ 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.setServiceUrl(null);
+ this.filter.setServerName("localhost:8443");
+ 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_ASSERTION,
+ new AssertionImpl(new SimplePrincipal("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.setGateway(true);
+ this.filter.doFilter(request, response, filterChain);
+ assertNotNull(session.getAttribute(AbstractCasFilter.CONST_GATEWAY));
+ assertNotNull(response.getRedirectedUrl());
+
+ final MockHttpServletResponse response2 = new MockHttpServletResponse();
+ this.filter.doFilter(request, response2, filterChain);
+ assertNull(session.getAttribute(AbstractCasFilter.CONST_GATEWAY));
+ assertNull(response2.getRedirectedUrl());
+ }
+}
diff --git a/cas-client-core/src/test/java/org/jasig/cas/client/web/filter/CasAuthorizationFilterTests.java b/cas-client-core/src/test/java/org/jasig/cas/client/web/filter/CasAuthorizationFilterTests.java
new file mode 100644
index 0000000..fe0ed5e
--- /dev/null
+++ b/cas-client-core/src/test/java/org/jasig/cas/client/web/filter/CasAuthorizationFilterTests.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright 2006 The JA-SIG Collaborative. All rights reserved. See license
+ * distributed with this file and available online at
+ * http://www.uportal.org/license.html
+ */
+package org.jasig.cas.client.web.filter;
+
+import junit.framework.TestCase;
+import org.jasig.cas.authentication.principal.Principal;
+import org.jasig.cas.authentication.principal.SimplePrincipal;
+import org.jasig.cas.client.authorization.AuthorizationException;
+import org.jasig.cas.client.authorization.CasAuthorizedDecider;
+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;
+
+/**
+ * Tests for the CasAuthorizationFilter.
+ *
+ * @author Scott Battaglia
+ * @version $Revision$ $Date$
+ * @since 3.0
+ */
+public final class CasAuthorizationFilterTests extends TestCase {
+
+ private CasAuthorizationFilter casAuthorizationFilter;
+
+ protected void setUp() throws Exception {
+ this.casAuthorizationFilter = new CasAuthorizationFilter();
+ this.casAuthorizationFilter.setDecider(new CasAuthorizedDecider(){
+
+ public boolean isAuthorizedToUseApplication(Principal principal) {
+ return principal.getId().equals("scott");
+ }
+ });
+ this.casAuthorizationFilter.init();
+ this.casAuthorizationFilter.init(new MockFilterConfig());
+ }
+
+ protected void tearDown() throws Exception {
+ this.casAuthorizationFilter.destroy();
+ }
+
+ public void testSuccesfulAuthorization() {
+ final MockHttpServletRequest request = new MockHttpServletRequest();
+ final MockHttpServletResponse response = new MockHttpServletResponse();
+ final MockHttpSession session = new MockHttpSession();
+ request.setSession(session);
+
+ session.setAttribute(AbstractCasFilter.CONST_ASSERTION,
+ new AssertionImpl(new SimplePrincipal("scott")));
+
+ try {
+ this.casAuthorizationFilter.doFilter(request, response,
+ new FilterChain(){
+
+ public void doFilter(ServletRequest arg0,
+ ServletResponse arg1) throws IOException,
+ ServletException {
+ // nothing to do
+ }
+ });
+ } catch (Exception e) {
+ fail("No exception expected");
+ }
+ }
+
+ public void testFailedAuthorization() {
+ final MockHttpServletRequest request = new MockHttpServletRequest();
+ final MockHttpServletResponse response = new MockHttpServletResponse();
+ final MockHttpSession session = new MockHttpSession();
+ request.setSession(session);
+
+ session.setAttribute(AbstractCasFilter.CONST_ASSERTION,
+ new AssertionImpl(new SimplePrincipal("test")));
+
+ try {
+ this.casAuthorizationFilter.doFilter(request, response, null);
+ fail("ServletException expected.");
+ } catch (AuthorizationException e) {
+ // expectd
+ } catch (Exception e) {
+ fail("AuthorizationException expected, not IOException.");
+ }
+ }
+
+ public void testNoAssertionFound() {
+ final MockHttpServletRequest request = new MockHttpServletRequest();
+ final MockHttpServletResponse response = new MockHttpServletResponse();
+ final MockHttpSession session = new MockHttpSession();
+ request.setSession(session);
+
+ try {
+ this.casAuthorizationFilter.doFilter(request, response, null);
+ fail("ServletException expected.");
+ } catch (ServletException e) {
+ // expected
+ } catch (Exception e) {
+ fail("ServletException expected, not IOException.");
+ }
+ }
+}
diff --git a/cas-client-core/src/test/java/org/jasig/cas/client/web/filter/CasValidationFilterTests.java b/cas-client-core/src/test/java/org/jasig/cas/client/web/filter/CasValidationFilterTests.java
new file mode 100644
index 0000000..eeb7090
--- /dev/null
+++ b/cas-client-core/src/test/java/org/jasig/cas/client/web/filter/CasValidationFilterTests.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright 2006 The JA-SIG Collaborative. All rights reserved. See license
+ * distributed with this file and available online at
+ * http://www.uportal.org/license.html
+ */
+package org.jasig.cas.client.web.filter;
+
+import junit.framework.TestCase;
+import org.jasig.cas.authentication.principal.Service;
+import org.jasig.cas.authentication.principal.SimplePrincipal;
+import org.jasig.cas.client.validation.Assertion;
+import org.jasig.cas.client.validation.AssertionImpl;
+import org.jasig.cas.client.validation.TicketValidator;
+import org.jasig.cas.client.validation.ValidationException;
+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;
+
+/**
+ * Tests for the CasValidationFilter.
+ *
+ * @author Scott Battaglia
+ * @version $Revision$ $Date$
+ * @since 3.0
+ */
+public final class CasValidationFilterTests extends TestCase {
+
+ private CasValidationFilter filter;
+
+ protected void setUp() throws Exception {
+ this.filter = new CasValidationFilter();
+ this.filter.setServerName("https://localhost");
+ this.filter.setTicketValidator(new TicketValidator(){
+
+ public Assertion validate(final String ticketId,
+ final Service service) throws ValidationException {
+ if (ticketId.equals("true")) {
+ return new AssertionImpl(new SimplePrincipal("test"));
+ }
+ throw new ValidationException("error validating ticket.");
+ }
+ });
+ this.filter.init();
+ }
+
+ protected void tearDown() throws Exception {
+ this.filter.destroy();
+ }
+
+ public void testNoTicket() throws Exception {
+ final MockHttpServletRequest request = new MockHttpServletRequest();
+ final MockHttpServletResponse response = new MockHttpServletResponse();
+ final MockHttpSession session = new MockHttpSession();
+ request.setSession(session);
+ final FilterChain filterChain = new FilterChain(){
+
+ public void doFilter(final ServletRequest arg0,
+ final ServletResponse arg1) throws IOException,
+ ServletException {
+ // nothing to do
+ }
+ };
+
+ this.filter.doFilter(request, response, filterChain);
+
+ assertNull(session.getAttribute(AbstractCasFilter.CONST_ASSERTION));
+ }
+
+ public void testValidationSuccess() throws Exception {
+ final MockHttpServletRequest request = new MockHttpServletRequest();
+ final MockHttpServletResponse response = new MockHttpServletResponse();
+ final MockHttpSession session = new MockHttpSession();
+ request.setSession(session);
+ request.setParameter(AbstractCasFilter.PARAM_TICKET, "true");
+ final FilterChain filterChain = new FilterChain(){
+
+ public void doFilter(final ServletRequest arg0,
+ final ServletResponse arg1) throws IOException,
+ ServletException {
+ // nothing to do
+ }
+ };
+
+ this.filter.doFilter(request, response, filterChain);
+
+ assertNotNull(session.getAttribute(AbstractCasFilter.CONST_ASSERTION));
+ }
+
+ public void testValidationFailure() throws Exception {
+ final MockHttpServletRequest request = new MockHttpServletRequest();
+ final MockHttpServletResponse response = new MockHttpServletResponse();
+ final MockHttpSession session = new MockHttpSession();
+ request.setSession(session);
+ request.setParameter(AbstractCasFilter.PARAM_TICKET, "false");
+ final FilterChain filterChain = new FilterChain(){
+
+ public void doFilter(final ServletRequest arg0,
+ final ServletResponse arg1) throws IOException,
+ ServletException {
+ // nothing to do
+ }
+ };
+
+ try {
+ this.filter.doFilter(request, response, filterChain);
+ fail("Exception expected.");
+ } catch (final ServletException e) {
+ assertTrue(e.getRootCause().getClass().isAssignableFrom(
+ ValidationException.class));
+ // expected
+ }
+ }
+}
diff --git a/cas-client-core/src/test/java/org/jasig/cas/client/web/filter/HttpServletRequestWrapperFilterTests.java b/cas-client-core/src/test/java/org/jasig/cas/client/web/filter/HttpServletRequestWrapperFilterTests.java
new file mode 100644
index 0000000..f267378
--- /dev/null
+++ b/cas-client-core/src/test/java/org/jasig/cas/client/web/filter/HttpServletRequestWrapperFilterTests.java
@@ -0,0 +1,155 @@
+/*
+ * Copyright 2006 The JA-SIG Collaborative. All rights reserved. See license
+ * distributed with this file and available online at
+ * http://www.uportal.org/license.html
+ */
+package org.jasig.cas.client.web.filter;
+
+import junit.framework.TestCase;
+import org.jasig.cas.authentication.principal.SimplePrincipal;
+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$ $Date$
+ * @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_ASSERTION,
+ new AssertionImpl(new SimplePrincipal("test")));
+
+ request.setSession(session);
+
+ this.filter.doFilter(request, new MockHttpServletResponse(),
+ filterChain);
+ assertEquals("test", this.mockRequest.getRemoteUser());
+ assertEquals(request.getAttributeNames(), this.mockRequest
+ .getAttributeNames());
+ assertEquals(request.getAuthType(), this.mockRequest.getAuthType());
+
+ this.mockRequest.setCharacterEncoding("test");
+
+ assertEquals(request.getCharacterEncoding(), this.mockRequest
+ .getCharacterEncoding());
+ assertNotSame(request.getClass(), this.mockRequest.getClass());
+ assertEquals(request.getContentLength(), this.mockRequest
+ .getContentLength());
+ assertEquals(request.getContentType(), this.mockRequest
+ .getContentType());
+ assertEquals(request.getContextPath(), this.mockRequest
+ .getContextPath());
+ assertEquals(request.getCookies(), this.mockRequest.getCookies());
+ assertEquals(request.getHeaderNames(), this.mockRequest
+ .getHeaderNames());
+ assertEquals(request.getInputStream(), this.mockRequest
+ .getInputStream());
+ assertEquals(request.getLocalAddr(), this.mockRequest.getLocalAddr());
+ assertEquals(request.getLocale(), this.mockRequest.getLocale());
+ assertEquals(request.getLocales().hasMoreElements(), this.mockRequest
+ .getLocales().hasMoreElements());
+ assertEquals(request.getLocalName(), this.mockRequest.getLocalName());
+ assertEquals(request.getLocalPort(), this.mockRequest.getLocalPort());
+ assertEquals(request.getMethod(), this.mockRequest.getMethod());
+ assertEquals(request.getParameterMap(), this.mockRequest
+ .getParameterMap());
+ assertEquals(request.getParameterNames().hasMoreElements(),
+ this.mockRequest.getParameterNames().hasMoreElements());
+ assertEquals(request.getPathInfo(), this.mockRequest.getPathInfo());
+ assertEquals(request.getPathTranslated(), this.mockRequest
+ .getPathTranslated());
+ assertEquals(request.getProtocol(), this.mockRequest.getProtocol());
+ assertEquals(request.getQueryString(), this.mockRequest
+ .getQueryString());
+ assertEquals(request.getReader(), this.mockRequest.getReader());
+ assertEquals(request.getRemoteAddr(), this.mockRequest.getRemoteAddr());
+ assertEquals(request.getRemoteHost(), this.mockRequest.getRemoteHost());
+ assertEquals(request.getRemotePort(), this.mockRequest.getRemotePort());
+ assertEquals(request.getRequestedSessionId(), this.mockRequest
+ .getRequestedSessionId());
+ assertEquals(request.getRequestURI(), this.mockRequest.getRequestURI());
+ assertEquals(request.getRequestURL().toString(), this.mockRequest
+ .getRequestURL().toString());
+ assertEquals(request.getScheme(), this.mockRequest.getScheme());
+ assertEquals(request.getServerName(), this.mockRequest.getServerName());
+ assertEquals(request.getServerPort(), this.mockRequest.getServerPort());
+ assertEquals(request.getServletPath(), this.mockRequest
+ .getServletPath());
+ assertEquals(request.getSession(), this.mockRequest.getSession());
+ assertEquals(request.getSession(false), this.mockRequest
+ .getSession(false));
+ assertEquals(request.getUserPrincipal(), this.mockRequest
+ .getUserPrincipal());
+ assertEquals(request.isRequestedSessionIdFromCookie(), this.mockRequest
+ .isRequestedSessionIdFromCookie());
+ assertEquals(request.isRequestedSessionIdFromUrl(), this.mockRequest
+ .isRequestedSessionIdFromUrl());
+ assertEquals(request.isRequestedSessionIdFromURL(), this.mockRequest
+ .isRequestedSessionIdFromURL());
+ assertEquals(request.isRequestedSessionIdValid(), this.mockRequest
+ .isRequestedSessionIdValid());
+ assertEquals(request.isSecure(), this.mockRequest.isSecure());
+ assertEquals(request.isUserInRole("test"), this.mockRequest
+ .isUserInRole("test"));
+ assertEquals(request.getDateHeader("test"), this.mockRequest
+ .getDateHeader("test"));
+ assertEquals(request.getHeader("test"), this.mockRequest
+ .getHeader("test"));
+ assertEquals(request.getHeaders("test").hasMoreElements(),
+ this.mockRequest.getHeaders("test").hasMoreElements());
+ assertEquals(request.getIntHeader("test"), this.mockRequest
+ .getIntHeader("test"));
+
+ this.mockRequest.setAttribute("test", "test");
+
+ assertEquals(request.getAttribute("test"), this.mockRequest
+ .getAttribute("test"));
+
+ this.mockRequest.removeAttribute("test");
+
+ assertEquals(request.getAttribute("test"), this.mockRequest
+ .getAttribute("test"));
+ assertEquals(request.getParameter("test"), this.mockRequest
+ .getParameter("test"));
+ assertEquals(request.getParameterValues("test"), this.mockRequest
+ .getParameterValues("test"));
+ assertEquals(request.getRealPath("test"), this.mockRequest
+ .getRealPath("test"));
+ assertEquals(request.getRequestDispatcher("test").getClass(),
+ this.mockRequest.getRequestDispatcher("test").getClass());
+
+ }
+}
diff --git a/cas-client-core/src/test/resources/badProxyGrantingTicketStorageConfig.xml b/cas-client-core/src/test/resources/badProxyGrantingTicketStorageConfig.xml
new file mode 100644
index 0000000..2e8ef16
--- /dev/null
+++ b/cas-client-core/src/test/resources/badProxyGrantingTicketStorageConfig.xml
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/cas-client-core/src/test/resources/oneProxyGrantingTicketStorageConfig.xml b/cas-client-core/src/test/resources/oneProxyGrantingTicketStorageConfig.xml
new file mode 100644
index 0000000..c6bcf86
--- /dev/null
+++ b/cas-client-core/src/test/resources/oneProxyGrantingTicketStorageConfig.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/cas-client-core/src/test/resources/proxyGrantingTicketStorageConfig.xml b/cas-client-core/src/test/resources/proxyGrantingTicketStorageConfig.xml
new file mode 100644
index 0000000..8ed6a2c
--- /dev/null
+++ b/cas-client-core/src/test/resources/proxyGrantingTicketStorageConfig.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/cas-client-core/src/test/resources/twoProxyGrantingTicketStorageConfig.xml b/cas-client-core/src/test/resources/twoProxyGrantingTicketStorageConfig.xml
new file mode 100644
index 0000000..af49ab8
--- /dev/null
+++ b/cas-client-core/src/test/resources/twoProxyGrantingTicketStorageConfig.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/cas-client-uportal/.classpath b/cas-client-uportal/.classpath
new file mode 100644
index 0000000..e23cd59
--- /dev/null
+++ b/cas-client-uportal/.classpath
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/cas-client-uportal/.cvsignore b/cas-client-uportal/.cvsignore
new file mode 100644
index 0000000..eb5a316
--- /dev/null
+++ b/cas-client-uportal/.cvsignore
@@ -0,0 +1 @@
+target
diff --git a/cas-client-uportal/.project b/cas-client-uportal/.project
new file mode 100644
index 0000000..9eab0c0
--- /dev/null
+++ b/cas-client-uportal/.project
@@ -0,0 +1,17 @@
+
+ cas-client-uportal
+ 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.
+
+ cas-client-core
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+
+
+ org.eclipse.jdt.core.javanature
+
+
\ No newline at end of file
diff --git a/cas-client-uportal/.settings/org.eclipse.jdt.core.prefs b/cas-client-uportal/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000..57e31ff
--- /dev/null
+++ b/cas-client-uportal/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,5 @@
+#Mon Aug 07 13:41:21 EDT 2006
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.4
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.source=1.4
+org.eclipse.jdt.core.compiler.compliance=1.4
diff --git a/cas-client-uportal/LICENSE.txt b/cas-client-uportal/LICENSE.txt
new file mode 100644
index 0000000..30c8573
--- /dev/null
+++ b/cas-client-uportal/LICENSE.txt
@@ -0,0 +1,29 @@
+License for Use
+
+Copyright (c) 2000 The JA-SIG Collaborative. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. 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.
+
+ 3. Redistributions of any form whatsoever must retain the following
+ acknowledgment:
+ "This product includes software developed by the JA-SIG Collaborative
+ (http://www.ja-sig.org/)."
+
+This software is provided by the JA-SIG collaborative "as is" and any expressed
+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 JA-SIG collaborative or its 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.
\ No newline at end of file
diff --git a/cas-client-uportal/README.txt b/cas-client-uportal/README.txt
new file mode 100644
index 0000000..f5cd476
--- /dev/null
+++ b/cas-client-uportal/README.txt
@@ -0,0 +1,28 @@
+CENTRAL AUTHENTICATION SERVICE (CAS)
+--------------------------------------------------------------------
+http://www.ja-sig.org/products/cas/
+
+1. INTRODUCTION
+
+The Central Authentication Service (CAS) is the standard mechanism by which web
+applications should authenticate users. Any custom applications written benefit
+from using CAS.
+
+Note that CAS provides authentication; that is, it determines that your users
+are who they say they are. CAS should not be viewed as an access-control system;
+in particular, providers of applications that grant access to anyone who
+possesses a NetID should understand that loose affiliates of an organization may
+be granted NetIDs.
+
+The JA-SIG CAS Client for Java is a support library for Java applications to communicate
+with the CAS server.
+
+2. RELEASE INFO
+
+CAS requires J2SE 1.4 and J2EE1.3.
+
+Release conents:
+* "src/main/java" contains the Java source files for the framework
+* "src/test/java" contains the Java source files for CAS's test suite
+
+
diff --git a/cas-client-uportal/cas-client-uportal.iml b/cas-client-uportal/cas-client-uportal.iml
new file mode 100644
index 0000000..375f369
--- /dev/null
+++ b/cas-client-uportal/cas-client-uportal.iml
@@ -0,0 +1,165 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/cas-client-uportal/pom.xml b/cas-client-uportal/pom.xml
new file mode 100644
index 0000000..c74a97d
--- /dev/null
+++ b/cas-client-uportal/pom.xml
@@ -0,0 +1,114 @@
+
+
+ org.jasig.cas
+ cas-client
+ 3.0-SNAPSHOT
+
+ 4.0.0
+ org.jasig.cas
+ cas-client-uportal
+ jar
+ 3.0-SNAPSHOT
+ JA-SIG CAS Client for Java - uPortal Integration
+ http://www.ja-sig.org/products/cas/
+
+
+ src/main/java
+ src/test/java
+
+
+ src/test/resources
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+ 1.4
+ 1.4
+
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+
+
+ **/*Tests*
+
+
+
+
+ org.apache.maven.plugins
+ maven-clover-plugin
+
+ ${basedir}/src/test/clover/clover.license
+
+
+
+ pre-site
+
+ instrument
+
+
+
+
+
+
+
+
+
+ junit
+ junit
+ 3.8.1
+ test
+
+
+ jasig
+ uportal
+ 2.5.3-rc1
+
+
+ org.jasig.cas
+ cas-client-core
+ 3.0-SNAPSHOT
+
+
+
+ false
+
+
+ org.apache.maven.plugins
+ maven-clover-plugin
+
+ ${basedir}/src/test/clover/clover.license
+
+
+
+ org.apache.maven.plugins
+ maven-checkstyle-plugin
+
+
+ org.apache.maven.plugins
+ maven-javadoc-plugin
+
+ 128m
+ 512m
+
+
+
+ org.apache.maven.plugins
+ maven-jxr-plugin
+
+
+ org.apache.maven.plugins
+ maven-surefire-report-plugin
+
+
+ org.codehaus.mojo
+ jdepend-maven-plugin
+
+
+
+
diff --git a/cas-client-uportal/src/main/java/org/jasig/cas/client/integration/uportal/AbstractCasSecurityContextFactory.java b/cas-client-uportal/src/main/java/org/jasig/cas/client/integration/uportal/AbstractCasSecurityContextFactory.java
new file mode 100644
index 0000000..7b7e645
--- /dev/null
+++ b/cas-client-uportal/src/main/java/org/jasig/cas/client/integration/uportal/AbstractCasSecurityContextFactory.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2006 The JA-SIG Collaborative. All rights reserved. See license
+ * distributed with this file and available online at
+ * http://www.uportal.org/license.html
+ */
+package org.jasig.cas.client.integration.uportal;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.jasig.cas.authentication.principal.Service;
+import org.jasig.cas.client.proxy.ProxyRetriever;
+import org.jasig.cas.client.validation.TicketValidator;
+import org.jasig.portal.security.InitialSecurityContextFactory;
+import org.jasig.portal.spring.PortalApplicationContextFacade;
+
+/**
+ * Abstract implementation of a SecurityContextFactory that can load all the dependences if a
+ * CasSecurityCcontext.
+ *
+ * @author Scott Battaglia
+ * @version $Revision$ $Date$
+ * @since 3.0
+ *
+ */
+public abstract class AbstractCasSecurityContextFactory extends
+ InitialSecurityContextFactory {
+
+
+ /** Spring Bean ID for the Ticket Validator. */
+ public static final String CONST_CAS_TICKET_VALIDATOR = "casTicketValidator";
+
+ /** Spring Bean ID for the Proxy Retriever. */
+ public static final String CONST_CAS_PROXY_RETRIEVER = "casProxyRetriever";
+
+ /** Spring Bean ID for the Service. */
+ public static final String CONST_CAS_SERVICE = "casService";
+
+ /** Spring Bean ID for the ProxyGrantingTicketStorage. */
+ public static final String CONST_CAS_PROXY_GRANTING_TICKET_STORAGE = "casProxyGrantingTicketStorage";
+
+ /** Instance of Commons Logging. */
+ protected final Log log = LogFactory.getLog(this.getClass());
+
+ /**
+ * The Ticket Validator referenced by the constant
+ * CONST_CAS_TICKET_VALIDATOR.
+ */
+ protected TicketValidator ticketValidator;
+
+ /**
+ * The ProxyRetriever referenced by the constant
+ * CONST_CAS_PROXY_RETRIEVER.
+ */
+ protected ProxyRetriever proxyRetriever;
+
+ /** The Service referenced by the constant CONST_CAS_SERVICE. */
+ protected Service service;
+
+ /**
+ * Default constructor retrieves and caches results from looking up entries
+ * in the PortalApplicationContext for the Ticket Validator, Proxy Retriever
+ * and Service.
+ */
+ public AbstractCasSecurityContextFactory() {
+ this.ticketValidator = (TicketValidator) PortalApplicationContextFacade
+ .getPortalApplicationContext().getBean(CONST_CAS_TICKET_VALIDATOR);
+ if (PortalApplicationContextFacade.getPortalApplicationContext()
+ .containsBean(CONST_CAS_PROXY_RETRIEVER)) {
+ this.proxyRetriever = (ProxyRetriever) PortalApplicationContextFacade
+ .getPortalApplicationContext().getBean(
+ CONST_CAS_PROXY_RETRIEVER);
+ } else {
+ log
+ .warn("No Proxy Retriever found in PortalApplicationFacade. No Proxying capabilities will be provided by CAS.");
+ }
+ this.service = (Service) PortalApplicationContextFacade
+ .getPortalApplicationContext().getBean(CONST_CAS_SERVICE);
+ }
+
+}
diff --git a/cas-client-uportal/src/main/java/org/jasig/cas/client/integration/uportal/CasConnectionContext.java b/cas-client-uportal/src/main/java/org/jasig/cas/client/integration/uportal/CasConnectionContext.java
new file mode 100644
index 0000000..1dff5f7
--- /dev/null
+++ b/cas-client-uportal/src/main/java/org/jasig/cas/client/integration/uportal/CasConnectionContext.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2006 The JA-SIG Collaborative. All rights reserved. See license
+ * distributed with this file and available online at
+ * http://www.uportal.org/license.html
+ */
+package org.jasig.cas.client.integration.uportal;
+
+import org.jasig.cas.authentication.principal.SimpleService;
+import org.jasig.portal.ChannelRuntimeData;
+import org.jasig.portal.ChannelStaticData;
+import org.jasig.portal.security.ISecurityContext;
+import org.jasig.portal.security.LocalConnectionContext;
+
+import java.util.Enumeration;
+
+/**
+ * Extension to LocalConnectionContext that will retrieve and append a proxy
+ * ticket to a given descriptor.
+ *
+ * @author Scott Battaglia
+ * @version $Revision$ $Date$
+ * @since 3.0
+ */
+public final class CasConnectionContext extends LocalConnectionContext {
+
+ /** Instance of ICasSecurityContext. */
+ private ICasSecurityContext casSecurityContext;
+
+ public String getDescriptor(String descriptor,
+ final ChannelRuntimeData channelRuntimeData) {
+ if (log.isTraceEnabled()) {
+ log.trace("getDescriptor(" + descriptor + ", " + channelRuntimeData
+ + ")");
+ }
+
+ descriptor = descriptor == null ? "null" : descriptor;
+
+ if (channelRuntimeData.getHttpRequestMethod().equals("GET")) {
+
+ if (this.casSecurityContext != null) {
+ final String proxyTicket = this.casSecurityContext
+ .getProxyTicket(new SimpleService(descriptor));
+
+ if (proxyTicket != null) {
+ // append ticket parameter and value to query string
+ if (descriptor.indexOf("?") != -1) {
+ descriptor = descriptor + "&ticket=" + proxyTicket;
+ } else {
+ descriptor = descriptor + "?ticket=" + proxyTicket;
+ }
+ }
+ }
+ }
+
+ return descriptor;
+ }
+
+ public void init(final ChannelStaticData channelStaticData) {
+ final ISecurityContext securityContext = channelStaticData.getPerson()
+ .getSecurityContext();
+
+ if (ICasSecurityContext.class.isAssignableFrom(securityContext
+ .getClass())
+ && securityContext.isAuthenticated()) {
+ this.casSecurityContext = (ICasSecurityContext) securityContext;
+ }
+
+ final Enumeration enumeration = securityContext.getSubContexts();
+
+ while (enumeration.hasMoreElements()) {
+ final ISecurityContext context = (ISecurityContext) enumeration
+ .nextElement();
+
+ if (ISecurityContext.class.isAssignableFrom(context.getClass())
+ && context.isAuthenticated()) {
+ this.casSecurityContext = (ICasSecurityContext) context;
+ }
+ }
+
+ if (this.casSecurityContext == null) {
+ log.warn("Unable to find authenticated ICasSecurityContext");
+ }
+ }
+}
diff --git a/cas-client-uportal/src/main/java/org/jasig/cas/client/integration/uportal/CasSecurityContext.java b/cas-client-uportal/src/main/java/org/jasig/cas/client/integration/uportal/CasSecurityContext.java
new file mode 100644
index 0000000..68728d3
--- /dev/null
+++ b/cas-client-uportal/src/main/java/org/jasig/cas/client/integration/uportal/CasSecurityContext.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright 2006 The JA-SIG Collaborative. All rights reserved. See license
+ * distributed with this file and available online at
+ * http://www.uportal.org/license.html
+ */
+package org.jasig.cas.client.integration.uportal;
+
+import org.jasig.cas.authentication.principal.Service;
+import org.jasig.cas.client.proxy.ProxyRetriever;
+import org.jasig.cas.client.util.CommonUtils;
+import org.jasig.cas.client.validation.Assertion;
+import org.jasig.cas.client.validation.TicketValidator;
+import org.jasig.cas.client.validation.ValidationException;
+import org.jasig.portal.security.PortalSecurityException;
+import org.jasig.portal.security.provider.ChainingSecurityContext;
+
+/**
+ * Implementation of ICasSecurityContext that knows how to handle CAS ticket
+ * validation, as well as the retrieval of Proxy Tickets.
+ *
+ * @author Scott Battaglia
+ * @version $Revision$ $Date$
+ * @since 3.0
+ */
+public class CasSecurityContext extends ChainingSecurityContext implements
+ ICasSecurityContext {
+
+ /** Unique Id for Serialization */
+ private static final long serialVersionUID = 1L;
+
+ /** Instance of TicketValidator to validate tickets. */
+ private final TicketValidator ticketValidator;
+
+ /** Instance of ProxyRetriever to obtain proxy tickets. */
+ private final ProxyRetriever proxyRetriever;
+
+ /** Instance of Service representing uPortal instance. */
+ private final Service service;
+
+ /** Assertion about the person this security context is for. */
+ private Assertion assertion;
+
+ /**
+ * Instantiate a new CasSecurityContext, setting the required fields.
+ *
+ */
+ public CasSecurityContext(final TicketValidator ticketValidator, final Service service, final ProxyRetriever proxyRetriever
+ ) {
+ CommonUtils.assertNotNull(ticketValidator, "ticketValidator cannot be null.");
+ CommonUtils.assertNotNull(service, "service cannot be null.");
+
+ log.trace("Initalizing CasSecurityContext");
+ this.ticketValidator = ticketValidator;
+ this.service = service;
+ this.proxyRetriever = proxyRetriever;
+ }
+
+ public final String getProxyTicket(final Service service) {
+ if (this.proxyRetriever == null
+ || CommonUtils.isEmpty(this.assertion.getProxyGrantingTicketId())) {
+ return null;
+ }
+
+ return this.proxyRetriever.getProxyTicketIdFor(this.assertion
+ .getProxyGrantingTicketId(), service);
+ }
+
+ public final int getAuthType() {
+ return ICasSecurityContext.CAS_AUTHTYPE;
+ }
+
+ public final synchronized void authenticate() throws PortalSecurityException {
+ this.isauth = false;
+ final String serviceTicket = new String(
+ this.myOpaqueCredentials.credentialstring);
+ final Service service = getService();
+
+ if (log.isDebugEnabled()) {
+ log.debug("Attempting to validate ticket [" + serviceTicket
+ + "] for service [" + service.toString());
+ }
+
+ try {
+ this.assertion = this.ticketValidator.validate(serviceTicket,
+ service);
+ this.myAdditionalDescriptor = null;
+ this.myPrincipal.setUID(this.assertion.getPrincipal().getId());
+ this.isauth = true;
+ super.authenticate();
+ } catch (final ValidationException e) {
+ log.warn(e, e);
+ throw new PortalSecurityException(e.getMessage(), e);
+ }
+ }
+
+ protected Service getService() {
+ return this.service;
+ }
+}
diff --git a/cas-client-uportal/src/main/java/org/jasig/cas/client/integration/uportal/CasSecurityContextFactory.java b/cas-client-uportal/src/main/java/org/jasig/cas/client/integration/uportal/CasSecurityContextFactory.java
new file mode 100644
index 0000000..29a4510
--- /dev/null
+++ b/cas-client-uportal/src/main/java/org/jasig/cas/client/integration/uportal/CasSecurityContextFactory.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2006 The JA-SIG Collaborative. All rights reserved. See license
+ * distributed with this file and available online at
+ * http://www.uportal.org/license.html
+ */
+package org.jasig.cas.client.integration.uportal;
+
+import org.jasig.portal.security.ISecurityContext;
+import org.jasig.portal.security.ISecurityContextFactory;
+
+/**
+ * Implementation of an {@link ISecurityContextFactory} that on creation will
+ * retrieve references to Spring managed CAS client objects and pass them to all
+ * new CasSecurityContexts that are created.
+ *
+ * @author Scott Battaglia
+ * @version $Revision$ $Date$
+ * @since 3.0
+ */
+public final class CasSecurityContextFactory extends AbstractCasSecurityContextFactory {
+
+ /**
+ * Instantiate a new instance of CasSecurityContext.
+ */
+ public ISecurityContext getSecurityContext() {
+ log
+ .trace("Returning CasSecurityContext from CasSecurityContextFactory.");
+ return new CasSecurityContext(this.ticketValidator, this.service, this.proxyRetriever
+ );
+ }
+}
diff --git a/cas-client-uportal/src/main/java/org/jasig/cas/client/integration/uportal/ICasSecurityContext.java b/cas-client-uportal/src/main/java/org/jasig/cas/client/integration/uportal/ICasSecurityContext.java
new file mode 100644
index 0000000..ba7dae9
--- /dev/null
+++ b/cas-client-uportal/src/main/java/org/jasig/cas/client/integration/uportal/ICasSecurityContext.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2006 The JA-SIG Collaborative. All rights reserved. See license
+ * distributed with this file and available online at
+ * http://www.uportal.org/license.html
+ */
+package org.jasig.cas.client.integration.uportal;
+
+import org.jasig.cas.authentication.principal.Service;
+
+/**
+ * Interface implemented by CAS security contexts. These implementations are
+ * aware of proxying, and can retrieve a ticket from CAS for accessing a
+ * specific service.
+ *
+ * @author Scott Battaglia
+ * @version $Revision$ $Date$
+ * @since 3.0
+ */
+public interface ICasSecurityContext {
+
+ /** Authentication type for CAS authentication */
+ public static final int CAS_AUTHTYPE = 0x1701;
+
+ /** Retrieve a Proxy Ticket Id for a particular service we wish to proxy against.
+ *
+ * @param service the service to retrieve a proxy ticket for.
+ * @return the ticket id, or null if no ticket could be retrieved.
+ */
+ String getProxyTicket(Service service);
+}
diff --git a/cas-client-uportal/src/main/java/org/jasig/cas/client/integration/uportal/ServiceHolder.java b/cas-client-uportal/src/main/java/org/jasig/cas/client/integration/uportal/ServiceHolder.java
new file mode 100644
index 0000000..043f624
--- /dev/null
+++ b/cas-client-uportal/src/main/java/org/jasig/cas/client/integration/uportal/ServiceHolder.java
@@ -0,0 +1,38 @@
+package org.jasig.cas.client.integration.uportal;
+
+import org.jasig.cas.authentication.principal.Service;
+import org.jasig.cas.client.util.CommonUtils;
+
+/**
+ * ThreadLocal container that exposes the service to lower layers in the authentication stack. Because of the ISecurityCcontext
+ * API this service url is not normally available.
+ *
+ * @author Scott Battaglia
+ * @version $Revision$ $Date$
+ * @since 3.0
+ */
+public final class ServiceHolder {
+
+ private static final ThreadLocal threadLocal = new ThreadLocal();
+
+ public static void setService(final Service service) {
+ CommonUtils.assertNotNull(service, "service cannot be null.");
+ threadLocal.set(service);
+ }
+
+ /**
+ * Method to retrieve the service from the ThreadLocal
+ *
+ * @return the service. Should not ever be null.
+ */
+ public static Service getService() {
+ return (Service) threadLocal.get();
+ }
+
+ /**
+ * Reset the context to clear it out.
+ */
+ public static void clearContext() {
+ threadLocal.set(null);
+ }
+}
diff --git a/cas-client-uportal/src/main/java/org/jasig/cas/client/integration/uportal/ThreadLocalAwareCasSecurityContext.java b/cas-client-uportal/src/main/java/org/jasig/cas/client/integration/uportal/ThreadLocalAwareCasSecurityContext.java
new file mode 100644
index 0000000..437de4a
--- /dev/null
+++ b/cas-client-uportal/src/main/java/org/jasig/cas/client/integration/uportal/ThreadLocalAwareCasSecurityContext.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2006 The JA-SIG Collaborative. All rights reserved. See license
+ * distributed with this file and available online at
+ * http://www.uportal.org/license.html
+ */
+package org.jasig.cas.client.integration.uportal;
+
+import org.jasig.cas.authentication.principal.Service;
+import org.jasig.cas.client.proxy.ProxyRetriever;
+import org.jasig.cas.client.validation.TicketValidator;
+
+/**
+ * Extension of AbstractCasSecurityContext that retrieves the Service from the
+ * ServiceHolder ThreadLocal object. This allows for a more flexible service to
+ * be provided for ticket validation. This is needed as the normal
+ * ISecurityContext has no mechanism for service urls based on requests.
+ *
+ * @author Scott Battaglia
+ * @version $Revision$ $Date$
+ * @since 3.0
+ */
+public final class ThreadLocalAwareCasSecurityContext extends
+ CasSecurityContext {
+
+ /** Unique Id for Serialization. */
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Instantiate a new CasSecurityContext, setting the required fields.
+ *
+ * @param ticketValidator the Ticket Validator.
+ * @param service the Service instance representing this uPortal instance.
+ * @param proxyRetriever the object used to retrieve proxies.
+ */
+ public ThreadLocalAwareCasSecurityContext(
+ final TicketValidator ticketValidator, final Service service,
+ final ProxyRetriever proxyRetriever) {
+ super(ticketValidator, service, proxyRetriever);
+ }
+
+ protected Service getService() {
+ return ServiceHolder.getService();
+ }
+}
diff --git a/cas-client-uportal/src/main/java/org/jasig/cas/client/integration/uportal/ThreadLocalAwareCasSecurityContextFactory.java b/cas-client-uportal/src/main/java/org/jasig/cas/client/integration/uportal/ThreadLocalAwareCasSecurityContextFactory.java
new file mode 100644
index 0000000..24aae2b
--- /dev/null
+++ b/cas-client-uportal/src/main/java/org/jasig/cas/client/integration/uportal/ThreadLocalAwareCasSecurityContextFactory.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2006 The JA-SIG Collaborative. All rights reserved. See license
+ * distributed with this file and available online at
+ * http://www.uportal.org/license.html
+ */
+package org.jasig.cas.client.integration.uportal;
+
+import org.jasig.portal.security.ISecurityContext;
+
+/**
+ * Factory to instantiate ThreadLocalAwareCasSecurityContexts.
+ *
+ * @author Scott Battaglia
+ * @version $Revision$ $Date$
+ * @since 3.0
+ */
+public final class ThreadLocalAwareCasSecurityContextFactory extends
+ AbstractCasSecurityContextFactory {
+
+ public ISecurityContext getSecurityContext() {
+ return new ThreadLocalAwareCasSecurityContext(this.ticketValidator,
+ this.service, this.proxyRetriever);
+ }
+}
diff --git a/cas-client-uportal/src/main/java/org/jasig/cas/client/integration/uportal/ThreadLocalAwareCasServiceFilter.java b/cas-client-uportal/src/main/java/org/jasig/cas/client/integration/uportal/ThreadLocalAwareCasServiceFilter.java
new file mode 100644
index 0000000..f20a934
--- /dev/null
+++ b/cas-client-uportal/src/main/java/org/jasig/cas/client/integration/uportal/ThreadLocalAwareCasServiceFilter.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2006 The JA-SIG Collaborative. All rights reserved. See license
+ * distributed with this file and available online at
+ * http://www.uportal.org/license.html
+ */
+package org.jasig.cas.client.integration.uportal;
+
+import org.jasig.cas.authentication.principal.Service;
+import org.jasig.cas.authentication.principal.SimpleService;
+import org.jasig.cas.client.util.CommonUtils;
+import org.jasig.cas.client.web.filter.AbstractCasFilter;
+
+import javax.servlet.FilterChain;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+
+/**
+ * Filter to construct the service url from the request and place it in a
+ * ThreadLocal so its available to the
+ * {@link ThreadLocalAwareCasSecurityContext} in order to use it for Ticket
+ * validation.
+ *
This filter places the Service in a {@link ServiceHolder}.
+ *
+ * @author Scott Battaglia
+ * @version $Revision$ $Date$
+ * @since 3.0
+ */
+public final class ThreadLocalAwareCasServiceFilter extends AbstractCasFilter {
+
+ protected void doFilterInternal(final HttpServletRequest request,
+ final HttpServletResponse response, final FilterChain filterChain)
+ throws IOException, ServletException {
+ final boolean hasTicket = CommonUtils.isNotBlank(request
+ .getParameter("ticket"));
+ try {
+ if (hasTicket) {
+ final Service service = new SimpleService(constructServiceUrl(
+ request, response));
+ ServiceHolder.setService(service);
+ }
+
+ filterChain.doFilter(request, response);
+ } finally {
+ if (hasTicket) {
+ ServiceHolder.clearContext();
+ }
+ }
+ }
+}
diff --git a/cas-client-uportal/src/main/java/org/jasig/cas/client/integration/uportal/UPortalConfiguredProxyReceptorServlet.java b/cas-client-uportal/src/main/java/org/jasig/cas/client/integration/uportal/UPortalConfiguredProxyReceptorServlet.java
new file mode 100644
index 0000000..3281922
--- /dev/null
+++ b/cas-client-uportal/src/main/java/org/jasig/cas/client/integration/uportal/UPortalConfiguredProxyReceptorServlet.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2006 The JA-SIG Collaborative. All rights reserved. See license
+ * distributed with this file and available online at
+ * http://www.uportal.org/license.html
+ */
+package org.jasig.cas.client.integration.uportal;
+
+import org.jasig.cas.client.proxy.AbstractProxyReceptorServlet;
+import org.jasig.cas.client.proxy.ProxyGrantingTicketStorage;
+import org.jasig.portal.spring.PortalApplicationContextFacade;
+
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletException;
+
+/**
+ * Implementation of AbstractProxyReceptorServlet that retrieves the
+ * ProxyGrantingTicket storage from the Portal Application Context instead of a
+ * WebApplicationContext.
+ *
+ * @author Scott Battaglia
+ * @version $Revision$ $Date$
+ * @since 3.0
+ */
+public final class UPortalConfiguredProxyReceptorServlet extends
+ AbstractProxyReceptorServlet {
+
+ /** Unique Id for Serialization. */
+ private static final long serialVersionUID = 6596608588362834646L;
+
+ public void init(final ServletConfig servletConfig) throws ServletException {
+ logger.info("Retrieving ProxyGrantingTicketStorage from PortalApplicationContextFacade.");
+ setProxyGrantingTicketStorage((ProxyGrantingTicketStorage) PortalApplicationContextFacade
+ .getPortalApplicationContext()
+ .getBean(
+ AbstractCasSecurityContextFactory.CONST_CAS_PROXY_GRANTING_TICKET_STORAGE));
+ }
+}
diff --git a/cas-client-uportal/src/main/resources/uportalCasConfigurationContext.xml b/cas-client-uportal/src/main/resources/uportalCasConfigurationContext.xml
new file mode 100644
index 0000000..98a413b
--- /dev/null
+++ b/cas-client-uportal/src/main/resources/uportalCasConfigurationContext.xml
@@ -0,0 +1,73 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/cas-client-uportal/src/test/clover/clover.license b/cas-client-uportal/src/test/clover/clover.license
new file mode 100644
index 0000000..8506a9d
--- /dev/null
+++ b/cas-client-uportal/src/test/clover/clover.license
@@ -0,0 +1,166 @@
+Product: Clover
+License: Open Source License, 0.x, 1.x
+Issued: Sun Feb 13 2005 22:45:43 CST
+Expiry: Never
+Key: aae4c7035b1208e316fa6d684
+Name: Scott Battaglia
+Org: JA-SIG Central Authentication Service
+Certificate: AAACCG+Ow8B7/zEbxOMqqKwwrdpP+a1COmJGHco7sCNLjHkHnajPF+dQW
+Ct12PMy0uml0s9xuus5wKngJ9OFk5PFeh01dzQF66bhXH1bvegLfvja3Kle6BYtDv4LZgE
+gk3E0aJN4IbgTn+TgUckSevXDR4KzK77NWJfrVzkxV3/JepYRA9UAbsXHiki9WjMIJfzoZ
+unjvtTFd/vTOcyirgfT/dTPrG9PAGAjH+e37E9Xf7HnRSrmxtrGX+wdaBOlZFUIIcVHKT2
+IaGToLZnx7FvfE3rzyQCYtS+r0E+H61c+dANzySy5PEH2JEyL8M9JrwgYJSju1FWhxbXO2
+Gb7y3Diufo80+HWz6xrGzl9IlXRseoXHki8rllk5taXqVv5G3UIsTFzbjjWUDlykn557C2
+D4o9T0xQ/6dVFxak75o0MxP4aXGFMZNg/pCBH9DAU7/CKVKRBPAVx1PJ8vIy41MF4p9Mi1
+qmELNvjn9K9fwpaeiUG9qT8B0pfq/tTAObG2sZf7B1mFbA3YwEqjhNqLdkoca5swrS0DI1
+9OejIVIqjK+bvUZaqUDMxVX7fM6hwRvI9Wd+rwFG+X3wHYNPsZ+Cos8/BNPzIIoOh4SbTr
+8vIqWUdPXM4HO26uAAVRKz6FknmwM/GQ7FyJBWgIXgXK51SLn+NcifxO8uywGewHzP00ki
+frTPmy0+GrikleWry6BdWkg76hjrjQBalNlSmasi9yp9J8qdzVYvQlOBjS5EKWsvsSpXGY
+MIdupkiv4a25aXsgdpGBy4GzcSUDioChq287HBBmYRIMVvp5OYbV3/+ERNhTlCQqb6Ck4g
+891l1OJOEoMiDqcbDL8DNftlH4gybEE7zJXQRmmJKyw==
+License Agreement: CLOVER VERSION 1 (ONE) SOFTWARE LICENSE AGREEMENT
+
+1. Licenses and Software
+
+Cortex eBusiness Pty Ltd, an Australian Proprietary Limited Company
+("CENQUA") hereby grants to the purchaser (the "LICENSEE") a limited,
+revocable, worldwide, non-exclusive, non-transferable,
+non-sublicensable license to use the Clover version 1 (one) software
+(the "Software"), including any minor upgrades thereof during the Term
+(hereinafter defined) up to, but not including the next major version
+of the Software. The licensee shall not, or knowingly allow others to,
+reverse engineer, decompile, disassemble, modify, adapt, create
+derivative works from or otherwise attempt to derive source code from
+the Software provided. And, in accordance with the terms and
+conditions of this Software License Agreement (the "Agreement"), the
+Software shall be used solely by the licensed users in accordance with
+the following edition specific conditions:
+
+a) Server Edition
+
+A Server Edition license entitles the Licensee to execute one instance
+of Clover Server Edition on one (1) machine for the purposes of
+instrumenting source code and generating reports. There are no
+limitations on the use of the instrumented source code or generated
+reports produced by Server Edition.
+
+b) Workstation Edition
+
+A Workstation Edition license entitles the licensee to use Clover
+Workstation Edition on one (1) machine by one (1) individual end
+user. Workstation Edition does not permit the generation of reports
+for distribution.
+
+c) Team Edition
+
+A Team Edition license entitles the licensee to use Clover Team
+edition on any number of machines solely by the licensed number of
+users. Reports generated by Clover Team Edition are strictly for use
+only by the licensed number of individual end users.
+
+2. License Fee
+
+In exchange for the License(s), the Licensee shall pay to Cenqua a
+one-time, up front, non-refundable license fee. At the sole discretion
+of Cenqua this fee will be waived for non-commercial
+projects. Notwithstanding the Licensee's payment of the License Fee,
+Cenqua reserves the right to terminate the License if Cenqua discovers
+that the Licensee and/or the Licensee's use of the Software is in
+breach of this Agreement.
+
+3. Proprietary Rights
+
+Cenqua will retain all right, title and interest in and to the
+Software, all copies thereof, and Cenqua website(s), software, and
+other intellectual property, including, but not limited to, ownership
+of all copyrights, look and feel, trademark rights, design rights,
+trade secret rights and any and all other intellectual property and
+other proprietary rights therein. The Licensee will not directly or
+indirectly obtain or attempt to obtain at any time, any right, title
+or interest by registration or otherwise in or to the trademarks,
+service marks, copyrights, trade names, symbols, logos or designations
+or other intellectual property rights owned or used by Cenqua. All
+technical manuals or other information provided by Cenqua to the
+Licensee shall be the sole property of Cenqua.
+
+4. Term and Termination
+
+Subject to the other provisions hereof, this Agreement shall commence
+upon the Licensee's opting into this Agreement and continue until the
+Licensee discontinues use of the Software or the Agreement terminates
+automatically upon the Licensee's breach of any term or condition of
+this Agreement (the "Term"). Upon any such termination, the Licensee
+will delete the Software immediately.
+
+5. Copying & Transfer
+
+The Licensee may copy the Software for back-up purposes only. The
+Licensee may not assign or otherwise transfer the Software to any
+third party.
+
+6. Specific Disclaimer of Warranty and Limitation of Liability
+
+THE SOFTWARE IS PROVIDED WITHOUT WARRANTY OF ANY KIND. CENQUA
+DISCLAIMS ALL WARRANTIES, EXPRESSED OR IMPLIED, INCLUDING BUT NOT
+LIMITED TO THE WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+PARTICULAR PURPOSE. CENQUA WILL NOT BE LIABLE FOR ANY DAMAGES
+ASSOCIATED WITH THE SOFTWARE, INCLUDING, WITHOUT LIMITATION, ORDINARY,
+INCIDENTAL, INDIRECT, OR CONSEQUENTIAL DAMAGES OF ANY KIND, INCLUDING
+BUT NOT LIMITED TO DAMAGES RELATING TO LOST DATA OR LOST PROFITS, EVEN
+IF CENQUA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+
+7. Warranties and Representations
+
+Licensee Indemnification. CENQUA agrees to indemnify, defend and hold
+the Licensee harmless from and against any and all liabilities,
+damages, losses, claims, costs, and expenses (including reasonable
+legal fees) arising out of or resulting from the Software or the use
+thereof infringing upon, misappropriating or violating any patents,
+copyrights, trademarks, or trade secret rights or other proprietary
+rights of persons, firms or entities who are not parties to this
+Agreement.
+
+CENQUA Indemnification. The Licensee warrants and represents that the
+Licensee's actions with regard to the Software will be in compliance
+with all applicable laws; and the Licensee agrees to indemnify,
+defend, and hold CENQUA harmless from and against any and all
+liabilities, damages, losses, claims, costs, and expenses (including
+reasonable legal fees) arising out of or resulting from the
+Licensee's failure to observe the use restrictions set forth herein.
+
+8. Publicity
+
+The Licensee grants permission for CENQUA to use Licensee's name
+solely in customer lists. CENQUA shall not, without prior consent in
+writing, use the Licensee's name, or that of its affiliates, in any
+form with the specific exception of customer lists. CENQUA agrees to
+remove Licensee's name from any and all materials within 7 days if
+notified by the Licensee in writing.
+
+9. Governing Law
+
+This Agreement shall be governed by the laws of New South Wales,
+Australia.
+
+10. Independent Contractors
+
+The parties are independent contractors with respect to each other,
+and nothing in this Agreement shall be construed as creating an
+employer-employee relationship, a partnership, agency relationship or
+a joint venture between the parties.
+
+11. Assignment
+
+This Agreement is not assignable or transferable by the Licensee.
+CENQUA in its sole discretion may transfer a license to a third party
+at the written request of the Licensee.
+
+12. Entire Agreement
+
+This Agreement constitutes the entire agreement between the parties
+concerning the Licensee's use of the Software. This Agreement
+supersedes any prior verbal understanding between the parties and any
+Licensee purchase order or other ordering document, regardless of
+whether such document is received by CENQUA before or after execution
+of this Agreement. This Agreement may be amended only in writing by
+CENQUA.
diff --git a/cas-client-uportal/src/test/java/org/jasig/cas/client/integration/uportal/CasSecurityContextFactoryTests.java b/cas-client-uportal/src/test/java/org/jasig/cas/client/integration/uportal/CasSecurityContextFactoryTests.java
new file mode 100644
index 0000000..c397b64
--- /dev/null
+++ b/cas-client-uportal/src/test/java/org/jasig/cas/client/integration/uportal/CasSecurityContextFactoryTests.java
@@ -0,0 +1,24 @@
+package org.jasig.cas.client.integration.uportal;
+
+import junit.framework.TestCase;
+import org.jasig.portal.security.ISecurityContext;
+
+/**
+ * @author Scott Battaglia
+ * @version $Revision$ $Date$
+ * @since 3.0
+ */
+public class CasSecurityContextFactoryTests extends TestCase {
+
+ private CasSecurityContextFactory casSecurityContextFactory;
+
+
+ protected void setUp() throws Exception {
+ this.casSecurityContextFactory = new CasSecurityContextFactory();
+ }
+
+ public void testGetter() {
+ final ISecurityContext casSecurityContext = this.casSecurityContextFactory.getSecurityContext();
+ assertNotNull(casSecurityContext);
+ }
+}
diff --git a/cas-client-uportal/src/test/java/org/jasig/cas/client/integration/uportal/CasSecurityContextTests.java b/cas-client-uportal/src/test/java/org/jasig/cas/client/integration/uportal/CasSecurityContextTests.java
new file mode 100644
index 0000000..5817c60
--- /dev/null
+++ b/cas-client-uportal/src/test/java/org/jasig/cas/client/integration/uportal/CasSecurityContextTests.java
@@ -0,0 +1,82 @@
+package org.jasig.cas.client.integration.uportal;
+
+import junit.framework.TestCase;
+import org.jasig.cas.authentication.principal.Service;
+import org.jasig.cas.authentication.principal.SimplePrincipal;
+import org.jasig.cas.authentication.principal.SimpleService;
+import org.jasig.cas.client.validation.Assertion;
+import org.jasig.cas.client.validation.AssertionImpl;
+import org.jasig.cas.client.validation.TicketValidator;
+import org.jasig.cas.client.validation.ValidationException;
+import org.jasig.cas.client.proxy.ProxyRetriever;
+import org.jasig.portal.security.PortalSecurityException;
+
+import java.util.HashMap;
+
+/**
+ * @author Scott Battaglia
+ * @version $Revision$ $Date$
+ * @since 3.0
+ */
+public class CasSecurityContextTests extends TestCase {
+
+ private CasSecurityContext context;
+
+
+ protected void setUp() throws Exception {
+ this.context = new CasSecurityContext(new TicketValidator() {
+
+ public Assertion validate(String ticketId, Service service) throws ValidationException {
+ return new AssertionImpl(new SimplePrincipal("test"), new HashMap(), null);
+ }
+ }, new SimpleService("test"), null);
+ this.context.getOpaqueCredentialsInstance().setCredentials("ticket");
+ }
+
+ public void testAuthenticate() throws Exception {
+ this.context.authenticate();
+
+ assertEquals("test", this.context.getPrincipal().getUID());
+ assertTrue(this.context.isAuthenticated());
+ assertNull(this.context.getProxyTicket(new SimpleService("test")));
+ }
+
+ public void testAuthenticateWithProxy() throws Exception {
+ this.context = new CasSecurityContext(new TicketValidator() {
+
+ public Assertion validate(String ticketId, Service service) throws ValidationException {
+ return new AssertionImpl(new SimplePrincipal("test"), new HashMap(), "test");
+ }
+ }, new SimpleService("test"), new ProxyRetriever() {
+
+ public String getProxyTicketIdFor(String proxyGrantingTicketId, Service targetService) {
+ return "test";
+ }
+ });
+ this.context.getOpaqueCredentialsInstance().setCredentials("ticket");
+ this.context.authenticate();
+ assertEquals("test", this.context.getProxyTicket(new SimpleService("test")));
+
+ }
+
+ public void testAuthenticateFail() {
+ this.context = new CasSecurityContext(new TicketValidator() {
+
+ public Assertion validate(String ticketId, Service service) throws ValidationException {
+ throw new ValidationException("test");
+ }
+ }, new SimpleService("test"), null);
+ this.context.getOpaqueCredentialsInstance().setCredentials("ticket");
+
+ try {
+ this.context.authenticate();
+ fail("Exception expected.");
+ } catch (PortalSecurityException e) {
+ assertTrue(e.getCause() instanceof ValidationException);
+ }
+ }
+
+ public void testGetAuthType() {
+ assertEquals(ICasSecurityContext.CAS_AUTHTYPE, this.context.getAuthType());
+ }
+}
diff --git a/cas-client-uportal/src/test/java/org/jasig/cas/client/integration/uportal/ServiceHolderTests.java b/cas-client-uportal/src/test/java/org/jasig/cas/client/integration/uportal/ServiceHolderTests.java
new file mode 100644
index 0000000..a51511a
--- /dev/null
+++ b/cas-client-uportal/src/test/java/org/jasig/cas/client/integration/uportal/ServiceHolderTests.java
@@ -0,0 +1,32 @@
+package org.jasig.cas.client.integration.uportal;
+
+import junit.framework.TestCase;
+import org.jasig.cas.authentication.principal.Service;
+import org.jasig.cas.authentication.principal.SimpleService;
+
+/**
+ * @author Scott Battaglia
+ * @version $Revision$ $Datet$
+ * @since 3.0
+ *
+ */
+public class ServiceHolderTests extends TestCase {
+
+ public void testSetGetService() {
+ final Service service = new SimpleService("test");
+ ServiceHolder.setService(service);
+
+ assertEquals(service, ServiceHolder.getService());
+ }
+
+ public void testClearContext() {
+ final Service service = new SimpleService("test");
+ ServiceHolder.setService(service);
+
+ assertEquals(service, ServiceHolder.getService());
+
+ ServiceHolder.clearContext();
+
+ assertNull(ServiceHolder.getService());
+ }
+}
diff --git a/cas-client-uportal/src/test/java/org/jasig/cas/client/integration/uportal/ThreadLocalAwareCasSecurityContextFactoryTests.java b/cas-client-uportal/src/test/java/org/jasig/cas/client/integration/uportal/ThreadLocalAwareCasSecurityContextFactoryTests.java
new file mode 100644
index 0000000..24857ee
--- /dev/null
+++ b/cas-client-uportal/src/test/java/org/jasig/cas/client/integration/uportal/ThreadLocalAwareCasSecurityContextFactoryTests.java
@@ -0,0 +1,25 @@
+package org.jasig.cas.client.integration.uportal;
+
+import junit.framework.TestCase;
+import org.jasig.portal.security.ISecurityContext;
+
+/**
+ * @author Scott Battaglia
+ * @version $Revision$ $Date$
+ * @since 3.0
+ */
+public class ThreadLocalAwareCasSecurityContextFactoryTests extends TestCase {
+
+ private ThreadLocalAwareCasSecurityContextFactory factory;
+
+ protected void setUp() throws Exception {
+ this.factory = new ThreadLocalAwareCasSecurityContextFactory();
+ }
+
+ public void testGetter() {
+ ISecurityContext context = this.factory.getSecurityContext();
+
+ assertNotNull(context);
+ assertTrue(context instanceof ThreadLocalAwareCasSecurityContext);
+ }
+}
diff --git a/cas-client-uportal/src/test/java/org/jasig/cas/client/integration/uportal/ThreadLocalAwareCasSecurityContextTests.java b/cas-client-uportal/src/test/java/org/jasig/cas/client/integration/uportal/ThreadLocalAwareCasSecurityContextTests.java
new file mode 100644
index 0000000..30125a2
--- /dev/null
+++ b/cas-client-uportal/src/test/java/org/jasig/cas/client/integration/uportal/ThreadLocalAwareCasSecurityContextTests.java
@@ -0,0 +1,28 @@
+package org.jasig.cas.client.integration.uportal;
+
+import junit.framework.TestCase;
+import org.jasig.cas.authentication.principal.Service;
+import org.jasig.cas.authentication.principal.SimpleService;
+
+/**
+ * @author Scott
+ */
+public class ThreadLocalAwareCasSecurityContextTests extends TestCase {
+
+ private ThreadLocalAwareCasSecurityContext context;
+
+
+ protected void setUp() throws Exception {
+ final ThreadLocalAwareCasSecurityContextFactory factory = new ThreadLocalAwareCasSecurityContextFactory();
+ this.context = (ThreadLocalAwareCasSecurityContext) factory.getSecurityContext();
+ }
+
+ public void testGetService() {
+ final Service service = new SimpleService("test");
+ ServiceHolder.setService(service);
+
+ assertEquals(service, this.context.getService());
+
+ ServiceHolder.clearContext();
+ }
+}
diff --git a/cas-client-uportal/src/test/java/org/jasig/cas/client/integration/uportal/ThreadLocalAwareCasServiceFilterTests.java b/cas-client-uportal/src/test/java/org/jasig/cas/client/integration/uportal/ThreadLocalAwareCasServiceFilterTests.java
new file mode 100644
index 0000000..7983ff0
--- /dev/null
+++ b/cas-client-uportal/src/test/java/org/jasig/cas/client/integration/uportal/ThreadLocalAwareCasServiceFilterTests.java
@@ -0,0 +1,53 @@
+package org.jasig.cas.client.integration.uportal;
+
+import junit.framework.TestCase;
+import org.springframework.mock.web.MockHttpServletRequest;
+import org.springframework.mock.web.MockHttpServletResponse;
+import org.jasig.cas.authentication.principal.SimpleService;
+
+import javax.servlet.FilterChain;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import java.io.IOException;
+
+/**
+ * @author Scott Battaglia
+ * @version $Revision$ $Date$
+ * @since 3.0
+ */
+public class ThreadLocalAwareCasServiceFilterTests extends TestCase {
+
+ private ThreadLocalAwareCasServiceFilter filter;
+
+
+ protected void setUp() throws Exception {
+ this.filter = new ThreadLocalAwareCasServiceFilter();
+ this.filter.setServiceUrl("http://localhost");
+ this.filter.init();
+ }
+
+ public void testServiceSetter() throws IOException, ServletException {
+ final MockHttpServletRequest request = new MockHttpServletRequest();
+
+ request.setParameter("ticket", "test");
+ this.filter.doFilter(request, new MockHttpServletResponse(), new FilterChain() {
+
+ public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse) throws IOException, ServletException {
+ assertNotNull(ServiceHolder.getService());
+ assertEquals(new SimpleService("http://localhost"), ServiceHolder.getService());
+ }
+ });
+ }
+
+ public void testNoServiceSetter() throws IOException, ServletException {
+ final MockHttpServletRequest request = new MockHttpServletRequest();
+
+ this.filter.doFilter(request, new MockHttpServletResponse(), new FilterChain() {
+
+ public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse) throws IOException, ServletException {
+ assertNull(ServiceHolder.getService());
+ }
+ });
+ }
+}
diff --git a/cas-client-uportal/src/test/java/org/jasig/cas/client/integration/uportal/UPortalConfiguredProxyReceptorServletTests.java b/cas-client-uportal/src/test/java/org/jasig/cas/client/integration/uportal/UPortalConfiguredProxyReceptorServletTests.java
new file mode 100644
index 0000000..35acb2a
--- /dev/null
+++ b/cas-client-uportal/src/test/java/org/jasig/cas/client/integration/uportal/UPortalConfiguredProxyReceptorServletTests.java
@@ -0,0 +1,18 @@
+package org.jasig.cas.client.integration.uportal;
+
+import junit.framework.TestCase;
+import org.springframework.mock.web.MockServletContext;
+import org.springframework.mock.web.MockServletConfig;
+
+/**
+ * @author Scott Battaglia
+ * @version $Revision$ $Date$
+ * @since 3.0
+ */
+public class UPortalConfiguredProxyReceptorServletTests extends TestCase {
+
+ public void testInitialization() throws Exception {
+ final UPortalConfiguredProxyReceptorServlet servlet = new UPortalConfiguredProxyReceptorServlet();
+ servlet.init(new MockServletConfig(new MockServletContext()));
+ }
+}
diff --git a/cas-client-uportal/src/test/resources/properties/beanRefFactory.xml b/cas-client-uportal/src/test/resources/properties/beanRefFactory.xml
new file mode 100644
index 0000000..a2e0090
--- /dev/null
+++ b/cas-client-uportal/src/test/resources/properties/beanRefFactory.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+ properties/uPortalConfigContext.xml
+
+
+
+
\ No newline at end of file
diff --git a/cas-client-uportal/src/test/resources/properties/uPortalConfigContext.xml b/cas-client-uportal/src/test/resources/properties/uPortalConfigContext.xml
new file mode 100644
index 0000000..6fab676
--- /dev/null
+++ b/cas-client-uportal/src/test/resources/properties/uPortalConfigContext.xml
@@ -0,0 +1,64 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/cas-client.iml b/cas-client.iml
new file mode 100644
index 0000000..fd6d193
--- /dev/null
+++ b/cas-client.iml
@@ -0,0 +1,98 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/cas-client.ipr b/cas-client.ipr
new file mode 100644
index 0000000..bbe3802
--- /dev/null
+++ b/cas-client.ipr
@@ -0,0 +1,284 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/cas-client.iws b/cas-client.iws
new file mode 100644
index 0000000..be7ef31
--- /dev/null
+++ b/cas-client.iws
@@ -0,0 +1,737 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+