merge with master
This commit is contained in:
commit
6f84cc2356
|
|
@ -23,8 +23,6 @@ before_install:
|
|||
|
||||
language: java
|
||||
|
||||
sudo: false
|
||||
|
||||
script: "mvn install --settings travis/settings.xml"
|
||||
|
||||
jdk:
|
||||
|
|
|
|||
1
NOTICE
1
NOTICE
|
|
@ -39,6 +39,7 @@ This project includes:
|
|||
Jasig CAS Client for Java - SAML Protocol Support under Apache License Version 2.0
|
||||
Jasig CAS Client for Java - Tomcat 6.x Integration under Apache License Version 2.0
|
||||
Jasig CAS Client for Java - Tomcat 7.x Integration under Apache License Version 2.0
|
||||
Jasig CAS Client for Java - Tomcat 8.x Integration under Apache License Version 2.0
|
||||
Java Servlet API under CDDL + GPLv2 with classpath exception
|
||||
JavaBeans Activation Framework (JAF) under Common Development and Distribution License (CDDL) v1.0
|
||||
JavaMail API under Common Development and Distribution License (CDDL) v1.0
|
||||
|
|
|
|||
181
README.md
181
README.md
|
|
@ -1,4 +1,4 @@
|
|||
# Java Apereo CAS Client [](https://maven-badges.herokuapp.com/maven-central/org.jasig.cas/cas-server)
|
||||
# Java Apereo CAS Client [](https://maven-badges.herokuapp.com/maven-central/org.jasig.cas.client/cas-client)
|
||||
|
||||
<a name="intro"></a>
|
||||
## Intro
|
||||
|
|
@ -10,7 +10,7 @@ All client artifacts are published to Maven central. Depending on functionality,
|
|||
## Build [](https://travis-ci.org/Jasig/java-cas-client)
|
||||
|
||||
```bash
|
||||
git clone git@github.com:Jasig/java-cas-client.git
|
||||
git clone git@github.com:apereo/java-cas-client.git
|
||||
cd java-cas-client
|
||||
mvn clean package
|
||||
```
|
||||
|
|
@ -36,7 +36,7 @@ files in the modules (`cas-client-integration-jboss` and `cas-client-support-dis
|
|||
|
||||
```xml
|
||||
<dependency>
|
||||
<groupId>org.jasig.cas</groupId>
|
||||
<groupId>org.jasig.cas.client</groupId>
|
||||
<artifactId>cas-client-support-saml</artifactId>
|
||||
<version>${java.cas.client.version}</version>
|
||||
</dependency>
|
||||
|
|
@ -46,7 +46,7 @@ files in the modules (`cas-client-integration-jboss` and `cas-client-support-dis
|
|||
|
||||
```xml
|
||||
<dependency>
|
||||
<groupId>org.jasig.cas</groupId>
|
||||
<groupId>org.jasig.cas.client</groupId>
|
||||
<artifactId>cas-client-support-distributed-ehcache</artifactId>
|
||||
<version>${java.cas.client.version}</version>
|
||||
</dependency>
|
||||
|
|
@ -56,7 +56,7 @@ files in the modules (`cas-client-integration-jboss` and `cas-client-support-dis
|
|||
|
||||
```xml
|
||||
<dependency>
|
||||
<groupId>org.jasig.cas</groupId>
|
||||
<groupId>org.jasig.cas.client</groupId>
|
||||
<artifactId>cas-client-support-distributed-memcached</artifactId>
|
||||
<version>${java.cas.client.version}</version>
|
||||
</dependency>
|
||||
|
|
@ -66,7 +66,7 @@ files in the modules (`cas-client-integration-jboss` and `cas-client-support-dis
|
|||
|
||||
```xml
|
||||
<dependency>
|
||||
<groupId>org.jasig.cas</groupId>
|
||||
<groupId>org.jasig.cas.client</groupId>
|
||||
<artifactId>cas-client-integration-atlassian</artifactId>
|
||||
<version>${java.cas.client.version}</version>
|
||||
</dependency>
|
||||
|
|
@ -76,7 +76,7 @@ files in the modules (`cas-client-integration-jboss` and `cas-client-support-dis
|
|||
|
||||
```xml
|
||||
<dependency>
|
||||
<groupId>org.jasig.cas</groupId>
|
||||
<groupId>org.jasig.cas.client</groupId>
|
||||
<artifactId>cas-client-integration-jboss</artifactId>
|
||||
<version>${java.cas.client.version}</version>
|
||||
</dependency>
|
||||
|
|
@ -86,7 +86,7 @@ files in the modules (`cas-client-integration-jboss` and `cas-client-support-dis
|
|||
|
||||
```xml
|
||||
<dependency>
|
||||
<groupId>org.jasig.cas</groupId>
|
||||
<groupId>org.jasig.cas.client</groupId>
|
||||
<artifactId>cas-client-integration-tomcat-v6</artifactId>
|
||||
<version>${java.cas.client.version}</version>
|
||||
</dependency>
|
||||
|
|
@ -96,12 +96,21 @@ files in the modules (`cas-client-integration-jboss` and `cas-client-support-dis
|
|||
|
||||
```xml
|
||||
<dependency>
|
||||
<groupId>org.jasig.cas</groupId>
|
||||
<groupId>org.jasig.cas.client</groupId>
|
||||
<artifactId>cas-client-integration-tomcat-v7</artifactId>
|
||||
<version>${java.cas.client.version}</version>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
- Tomcat 8 is provided by this dependency:
|
||||
|
||||
```xml
|
||||
<dependency>
|
||||
<groupId>org.jasig.cas.client</groupId>
|
||||
<artifactId>cas-client-integration-tomcat-v8</artifactId>
|
||||
<version>${java.cas.client.version}</version>
|
||||
</dependency>
|
||||
```
|
||||
<a name="configurtion"></a>
|
||||
## Configuration
|
||||
|
||||
|
|
@ -220,7 +229,7 @@ The SAML 1.1 `AuthenticationFilter` is what detects whether a user needs to be a
|
|||
| `encodeServiceUrl ` | Whether the client should auto encode the service url. Defaults to `true` | No
|
||||
|
||||
<a name="rgjasigcasclientvalidationcas10ticketvalidationfilter"></a>
|
||||
####org.jasig.cas.client.validation.Cas10TicketValidationFilter
|
||||
#### org.jasig.cas.client.validation.Cas10TicketValidationFilter
|
||||
Validates tickets using the CAS 1.0 Protocol.
|
||||
|
||||
```xml
|
||||
|
|
@ -421,12 +430,42 @@ Places the `Assertion` in a `ThreadLocal` for portions of the application that n
|
|||
</filter-mapping>
|
||||
```
|
||||
|
||||
<a name="orgjasigcasclientutilerrorredirectfilter"></a>
|
||||
#### org.jasig.cas.client.util.ErrorRedirectFilter
|
||||
Filters that redirects to the supplied url based on an exception. Exceptions and the urls are configured via init filter name/param values.
|
||||
|
||||
| Property | Description | Required
|
||||
|----------|-------|-----------
|
||||
| `defaultErrorRedirectPage` | Default url to redirect to, in case no erorr matches are found. | Yes
|
||||
| `java.lang.Exception` | Fully qualified exception name. Its value must be redirection url | No
|
||||
|
||||
|
||||
```xml
|
||||
<filter>
|
||||
<filter-name>CAS Error Redirect Filter</filter-name>
|
||||
<filter-class>org.jasig.cas.client.util.ErrorRedirectFilter</filter-class>
|
||||
<init-param>
|
||||
<param-name>java.lang.Exception</param-name>
|
||||
<param-value>/error.jsp</param-value>
|
||||
</init-param>
|
||||
<init-param>
|
||||
<param-name>defaultErrorRedirectPage</param-name>
|
||||
<param-value>/defaulterror.jsp</param-value>
|
||||
</init-param>
|
||||
</filter>
|
||||
<filter-mapping>
|
||||
<filter-name>CAS Error Redirect Filter</filter-name>
|
||||
<url-pattern>/*</url-pattern>
|
||||
</filter-mapping>
|
||||
```
|
||||
|
||||
|
||||
<a name="client-configuration-using-spring"></a>
|
||||
### Client Configuration Using Spring
|
||||
|
||||
Configuration via Spring IoC will depend heavily on `DelegatingFilterProxy` class. For each filter that will be configured for CAS via Spring, a corresponding `DelegatingFilterProxy` is needed in the web.xml.
|
||||
|
||||
As the `SingleSignOutFilter`, `HttpServletRequestWrapperFilter` and `AssertionThreadLocalFilter` have no configuration options, we recommend you just configure them in the `web.xml`
|
||||
As the `HttpServletRequestWrapperFilter` and `AssertionThreadLocalFilter` have no configuration options, we recommend you just configure them in the `web.xml`
|
||||
|
||||
```xml
|
||||
<filter>
|
||||
|
|
@ -614,6 +653,10 @@ The `SingleSignOutFilter` can affect character encoding. This becomes most obvio
|
|||
<filter>
|
||||
<filter-name>CAS Single Sign Out Filter</filter-name>
|
||||
<filter-class>org.jasig.cas.client.session.SingleSignOutFilter</filter-class>
|
||||
<init-param>
|
||||
<param-name>casServerUrlPrefix</param-name>
|
||||
<param-value>https://cas.example.com/cas</param-value>
|
||||
</init-param>
|
||||
</filter>
|
||||
...
|
||||
<filter-mapping>
|
||||
|
|
@ -637,6 +680,10 @@ The `SingleSignOutFilter` can affect character encoding. This becomes most obvio
|
|||
<param-name>artifactParameterName</param-name>
|
||||
<param-value>SAMLart</param-value>
|
||||
</init-param>
|
||||
<init-param>
|
||||
<param-name>casServerUrlPrefix</param-name>
|
||||
<param-value>https://cas.example.com/cas</param-value>
|
||||
</init-param>
|
||||
</filter>
|
||||
...
|
||||
<filter-mapping>
|
||||
|
|
@ -783,27 +830,27 @@ If you have any trouble, you can enable the log of cas in `jboss-logging.xml` by
|
|||
</logger>
|
||||
```
|
||||
|
||||
<a name="tomcat-67-integration"></a>
|
||||
## Tomcat 6/7 Integration
|
||||
<a name="tomcat-678-integration"></a>
|
||||
## Tomcat 6/7/8 Integration
|
||||
The client supports container-based CAS authentication and authorization support for the Tomcat servlet container.
|
||||
|
||||
Suppose a single Tomcat container hosts multiple Web applications with similar authentication and authorization needs. Prior to Tomcat container support, each application would require a similar configuration of CAS servlet filters and authorization configuration in the `web.xml` servlet descriptor. Using the new container-based authentication/authorization feature, a single CAS configuration can be applied to the container and leveraged by all Web applications hosted by the container.
|
||||
|
||||
CAS authentication support for Tomcat is based on the Tomcat-specific Realm component. The Realm component has a fairly broad surface area and RealmBase is provided as a convenient superclass for custom implementations; the CAS realm implementations derive from `RealmBase`. Unfortunately RealmBase and related components have proven to change over both major and minor number releases, which requires version-specific CAS components for integration. We have provided two packages with similar components with the hope of supporting all 6.x and 7.x versions. **No support for 5.x is provided.**
|
||||
CAS authentication support for Tomcat is based on the Tomcat-specific Realm component. The Realm component has a fairly broad surface area and RealmBase is provided as a convenient superclass for custom implementations; the CAS realm implementations derive from `RealmBase`. Unfortunately RealmBase and related components have proven to change over both major and minor number releases, which requires version-specific CAS components for integration. We have provided 3 packages with similar components with the hope of supporting all 6.x, 7.x and 8.x versions. **No support for 5.x is provided.**
|
||||
|
||||
<a name="component-overview"></a>
|
||||
### Component Overview
|
||||
In the following discussion of components, only the Tomcat 6.x components are mentioned. The Tomcat 7.0.x components have exactly the same name, but **are in the tomcat.v7 package**, e.g. `org.jasig.cas.client.tomcat.v7.Cas20CasAuthenticator`.
|
||||
In the following discussion of components, only the Tomcat 8.x components are mentioned. The Tomcat 7.0.x and 6.0.x components have exactly the same name, but **are in the tomcat.v7 and tomcat.v6 packages**, e.g. `org.jasig.cas.client.tomcat.v7.Cas20CasAuthenticator` or `org.jasig.cas.client.tomcat.v6.Cas20CasAuthenticator`.
|
||||
|
||||
<a name="authenticators"></a>
|
||||
#### Authenticators
|
||||
Authenticators are responsible for performing CAS authentication using a particular protocol. All protocols supported by the Jasig Java CAS client are supported: CAS 1.0, CAS 2.0, and SAML 1.1. The following components provide protocol-specific support:
|
||||
|
||||
```
|
||||
org.jasig.cas.client.tomcat.v6.Cas10CasAuthenticator
|
||||
org.jasig.cas.client.tomcat.v6.Cas20CasAuthenticator
|
||||
org.jasig.cas.client.tomcat.v6.Cas20ProxyCasAuthenticator
|
||||
org.jasig.cas.client.tomcat.v6.Saml11Authenticator
|
||||
org.jasig.cas.client.tomcat.v8.Cas10CasAuthenticator
|
||||
org.jasig.cas.client.tomcat.v8.Cas20CasAuthenticator
|
||||
org.jasig.cas.client.tomcat.v8.Cas20ProxyCasAuthenticator
|
||||
org.jasig.cas.client.tomcat.v8.Saml11Authenticator
|
||||
```
|
||||
|
||||
<a name="realms"></a>
|
||||
|
|
@ -811,8 +858,8 @@ org.jasig.cas.client.tomcat.v6.Saml11Authenticator
|
|||
In terms of CAS configuration, Tomcat realms serve as containers for users and role definitions. The roles defined in a Tomcat realm may be referenced in the web.xml servlet descriptor to define authorization constraints on Web applications hosted by the container. Two sources of user/role data are supported:
|
||||
|
||||
```
|
||||
org.jasig.cas.client.tomcat.v6.PropertiesCasRealm
|
||||
org.jasig.cas.client.tomcat.v6.AssertionCasRealm
|
||||
org.jasig.cas.client.tomcat.v8.PropertiesCasRealm
|
||||
org.jasig.cas.client.tomcat.v8.AssertionCasRealm
|
||||
```
|
||||
|
||||
`PropertiesCasRealm` uses a Java properties file as a source of static user/role information. This component is conceptually similar to the `MemoryRealm` component that ships with Tomcat and defines user/role data via XML configuration. The PropertiesCasRealm is different in that it explicitly lacks support for passwords, which have no use with CAS.
|
||||
|
|
@ -827,15 +874,15 @@ A number of Tomcat valves are provided to handle functionality outside Realms an
|
|||
Logout valves provide a way of destroying the CAS authentication state bound to the container for a particular user/session; the destruction of authenticated state is synonymous with logout for the container and its hosted applications. (Note this does not destroy the CAS SSO session.) The implementations provide various strategies to map a URI onto the state-destroying logout function.
|
||||
|
||||
```
|
||||
org.jasig.cas.client.tomcat.v6.StaticUriLogoutValve
|
||||
org.jasig.cas.client.tomcat.v6.RegexUriLogoutValve
|
||||
org.jasig.cas.client.tomcat.v8.StaticUriLogoutValve
|
||||
org.jasig.cas.client.tomcat.v8.RegexUriLogoutValve
|
||||
```
|
||||
|
||||
##### SingleSignOutValve
|
||||
The `org.jasig.cas.client.tomcat.v6.SingleSignOutValve` allows the container to participate in CAS single sign-out. In particular this valve handles the SAML LogoutRequest message sent from the CAS server that is delivered when the CAS SSO session ends.
|
||||
The `org.jasig.cas.client.tomcat.v8.SingleSignOutValve` allows the container to participate in CAS single sign-out. In particular this valve handles the SAML LogoutRequest message sent from the CAS server that is delivered when the CAS SSO session ends.
|
||||
|
||||
##### ProxyCallbackValve
|
||||
The `org.jasig.cas.client.tomcat.v6.ProxyCallbackValve` provides a handler for watching request URIs for requests that contain a proxy callback request in support of the CAS 2.0 protocol proxy feature.
|
||||
The `org.jasig.cas.client.tomcat.v8.ProxyCallbackValve` provides a handler for watching request URIs for requests that contain a proxy callback request in support of the CAS 2.0 protocol proxy feature.
|
||||
|
||||
<a name="container-setup"></a>
|
||||
### Container Setup
|
||||
|
|
@ -865,11 +912,11 @@ Alternatively, CAS configuration can be applied to individual Web applications t
|
|||
This example also configures the container for CAS single sign-out.
|
||||
-->
|
||||
<Realm
|
||||
className="org.jasig.cas.client.tomcat.v6.PropertiesCasRealm"
|
||||
className="org.jasig.cas.client.tomcat.v8.PropertiesCasRealm"
|
||||
propertiesFilePath="conf/manager-user-roles.properties"
|
||||
/>
|
||||
<Valve
|
||||
className="org.jasig.cas.client.tomcat.v6.Cas20CasAuthenticator"
|
||||
className="org.jasig.cas.client.tomcat.v8.Cas20CasAuthenticator"
|
||||
encoding="UTF-8"
|
||||
casServerLoginUrl="https://server.example.com/cas/login"
|
||||
casServerUrlPrefix="https://server.example.com/cas/"
|
||||
|
|
@ -878,7 +925,7 @@ Alternatively, CAS configuration can be applied to individual Web applications t
|
|||
|
||||
<!-- Single sign-out support -->
|
||||
<Valve
|
||||
className="org.jasig.cas.client.tomcat.v6.SingleSignOutValve"
|
||||
className="org.jasig.cas.client.tomcat.v8.SingleSignOutValve"
|
||||
artifactParameterName="SAMLart"
|
||||
/>
|
||||
|
||||
|
|
@ -888,11 +935,11 @@ Alternatively, CAS configuration can be applied to individual Web applications t
|
|||
-->
|
||||
<!--
|
||||
<Valve
|
||||
className="org.jasig.cas.client.tomcat.v6.RegexUriLogoutValve"
|
||||
className="org.jasig.cas.client.tomcat.v8.RegexUriLogoutValve"
|
||||
logoutUriRegex="/manager/logout.*"
|
||||
/>
|
||||
<Valve
|
||||
className="org.jasig.cas.client.tomcat.v6.StaticUriLogoutValve"
|
||||
className="org.jasig.cas.client.tomcat.v8.StaticUriLogoutValve"
|
||||
logoutUri="/manager/logout.html"
|
||||
/>
|
||||
-->
|
||||
|
|
@ -910,11 +957,11 @@ The following example shows how to configure a Context for dynamic role data pro
|
|||
The attribute used for role data is "memberOf".
|
||||
-->
|
||||
<Realm
|
||||
className="org.jasig.cas.client.tomcat.v6.AssertionCasRealm"
|
||||
className="org.jasig.cas.client.tomcat.v8.AssertionCasRealm"
|
||||
roleAttributeName="memberOf"
|
||||
/>
|
||||
<Valve
|
||||
className="org.jasig.cas.client.tomcat.v6.Saml11Authenticator"
|
||||
className="org.jasig.cas.client.tomcat.v8.Saml11Authenticator"
|
||||
encoding="UTF-8"
|
||||
casServerLoginUrl="https://server.example.com/cas/login"
|
||||
casServerUrlPrefix="https://server.example.com/cas/"
|
||||
|
|
@ -923,12 +970,76 @@ The following example shows how to configure a Context for dynamic role data pro
|
|||
|
||||
<!-- Single sign-out support -->
|
||||
<Valve
|
||||
className="org.jasig.cas.client.tomcat.v6.SingleSignOutValve"
|
||||
className="org.jasig.cas.client.tomcat.v8.SingleSignOutValve"
|
||||
artifactParameterName="SAMLart"
|
||||
/>
|
||||
</Context>
|
||||
```
|
||||
|
||||
<a name="jetty-integration"></a>
|
||||
## Jetty Integration
|
||||
Since version 3.4.2, the Java CAS Client supports Jetty container integration via the following module:
|
||||
|
||||
```xml
|
||||
<dependency>
|
||||
<groupId>org.jasig.cas.client</groupId>
|
||||
<artifactId>cas-client-integration-jetty</artifactId>
|
||||
<version>${cas-client.version}</version>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
Both programmatic (embedded) and context configuration are supported.
|
||||
|
||||
### Jetty Embedded Configuration
|
||||
```
|
||||
# CAS configuration parameters
|
||||
String hostName = "app.example.com";
|
||||
String casServerBaseUrl = "cas.example.com/cas";
|
||||
String casRoleAttribute = "memberOf";
|
||||
boolean casRenew = false;
|
||||
int casTolerance = 5000;
|
||||
|
||||
# Jetty wiring
|
||||
WebAppContext context = new WebAppContext("/path/to/context", "contextPath");
|
||||
context.setTempDirectory("/tmp/jetty/work"));
|
||||
context.setInitParameter("org.eclipse.jetty.servlet.Default.dirAllowed", "false");
|
||||
SessionCookieConfig config = context.getSessionHandler().getSessionManager().getSessionCookieConfig();
|
||||
config.setHttpOnly(true);
|
||||
config.setSecure(true);
|
||||
Saml11TicketValidator validator = new Saml11TicketValidator(casServerBaseUrl);
|
||||
validator.setRenew(casRenew);
|
||||
validator.setTolerance(casTolerance);
|
||||
CasAuthenticator authenticator = new CasAuthenticator();
|
||||
authenticator.setRoleAttribute(casRoleAttribute);
|
||||
authenticator.setServerNames(hostName);
|
||||
authenticator.setTicketValidator(validator);
|
||||
context.getSecurityHandler().setAuthenticator(authenticator);
|
||||
```
|
||||
|
||||
### Jetty Context Configuration
|
||||
```xml
|
||||
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure.dtd">
|
||||
|
||||
<Configure class="org.eclipse.jetty.webapp.WebAppContext">
|
||||
<Set name="contextPath">/</Set>
|
||||
<Set name="war"><SystemProperty name="jetty.base"/>/webapps/yourapp</Set>
|
||||
<Get name="securityHandler">
|
||||
<Set name="authenticator">
|
||||
<New class="org.jasig.cas.client.jetty.CasAuthenticator">
|
||||
<Set name="serverNames">app.example.com</Set>
|
||||
<Set name="ticketValidator">
|
||||
<New class="org.jasig.cas.client.validation.Cas20ServiceTicketValidator">
|
||||
<Arg>https://cas.example.com/cas</Arg>
|
||||
<!--<Set name="renew">true</Set>-->
|
||||
</New>
|
||||
</Set>
|
||||
</New>
|
||||
</Set>
|
||||
</Get>
|
||||
</Configure>
|
||||
```
|
||||
|
||||
<a name="atlassian-integration"></a>
|
||||
## Atlassian Integration
|
||||
The clien includes Atlassian Confluence and JIRA support. Support is enabled by a custom CAS authenticator that extends the default authenticators.
|
||||
|
|
@ -1079,6 +1190,10 @@ This configuration tested against the sample application that is included with S
|
|||
<filter>
|
||||
<filter-name>CAS Single Sign Out Filter</filter-name>
|
||||
<filter-class>org.jasig.cas.client.session.SingleSignOutFilter</filter-class>
|
||||
<init-param>
|
||||
<param-name>casServerUrlPrefix</param-name>
|
||||
<param-value>https://cas.example.com/cas</param-value>
|
||||
</init-param>
|
||||
</filter>
|
||||
|
||||
<filter>
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@
|
|||
<artifactId>cas-client</artifactId>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.jasig.cas.client</groupId>
|
||||
<artifactId>cas-client-core</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<name>Jasig CAS Client for Java - Core</name>
|
||||
|
|
@ -36,14 +35,6 @@
|
|||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>commons-codec</groupId>
|
||||
<artifactId>commons-codec</artifactId>
|
||||
<version>1.4</version>
|
||||
<type>jar</type>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-beans</artifactId>
|
||||
|
|
|
|||
|
|
@ -212,4 +212,10 @@ public class AuthenticationFilter extends AbstractCasFilter {
|
|||
final String requestUri = urlBuffer.toString();
|
||||
return this.ignoreUrlPatternMatcherStrategyClass.matches(requestUri);
|
||||
}
|
||||
|
||||
public final void setIgnoreUrlPatternMatcherStrategyClass(
|
||||
final UrlPatternMatcherStrategy ignoreUrlPatternMatcherStrategyClass) {
|
||||
this.ignoreUrlPatternMatcherStrategyClass = ignoreUrlPatternMatcherStrategyClass;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -60,4 +60,9 @@ public final class ConfigurationKey<E> {
|
|||
public E getDefaultValue() {
|
||||
return this.defaultValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getName();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -77,6 +77,5 @@ public interface ConfigurationKeys {
|
|||
ConfigurationKey<String> ALLOWED_PROXY_CHAINS = new ConfigurationKey<String>("allowedProxyChains", null);
|
||||
ConfigurationKey<Class<? extends Cas20ServiceTicketValidator>> TICKET_VALIDATOR_CLASS = new ConfigurationKey<Class<? extends Cas20ServiceTicketValidator>>("ticketValidatorClass", null);
|
||||
ConfigurationKey<String> PROXY_CALLBACK_URL = new ConfigurationKey<String>("proxyCallbackUrl", null);
|
||||
ConfigurationKey<String> FRONT_LOGOUT_PARAMETER_NAME = new ConfigurationKey<String>("frontLogoutParameterName", "SAMLRequest");
|
||||
ConfigurationKey<String> RELAY_STATE_PARAMETER_NAME = new ConfigurationKey<String>("relayStateParameterName", "RelayState");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ public enum ConfigurationStrategyName {
|
|||
try {
|
||||
final Class<?> clazz = Class.forName(value);
|
||||
|
||||
if (clazz.isAssignableFrom(ConfigurationStrategy.class)) {
|
||||
if (ConfigurationStrategy.class.isAssignableFrom(clazz)) {
|
||||
return (Class<? extends ConfigurationStrategy>) clazz;
|
||||
}
|
||||
} catch (final ClassNotFoundException e) {
|
||||
|
|
|
|||
|
|
@ -94,7 +94,9 @@ public final class Cas20ProxyRetriever implements ProxyRetriever {
|
|||
return null;
|
||||
}
|
||||
|
||||
return XmlUtils.getTextForElement(response, "proxyTicket");
|
||||
final String ticket = XmlUtils.getTextForElement(response, "proxyTicket");
|
||||
logger.debug("Got proxy ticket {}", ticket);
|
||||
return ticket;
|
||||
}
|
||||
|
||||
private URL constructUrl(final String proxyGrantingTicketId, final String targetService) {
|
||||
|
|
|
|||
|
|
@ -46,7 +46,6 @@ public final class SingleSignOutFilter extends AbstractConfigurationFilter {
|
|||
if (!isIgnoreInitConfiguration()) {
|
||||
setArtifactParameterName(getString(ConfigurationKeys.ARTIFACT_PARAMETER_NAME));
|
||||
setLogoutParameterName(getString(ConfigurationKeys.LOGOUT_PARAMETER_NAME));
|
||||
setFrontLogoutParameterName(getString(ConfigurationKeys.FRONT_LOGOUT_PARAMETER_NAME));
|
||||
setRelayStateParameterName(getString(ConfigurationKeys.RELAY_STATE_PARAMETER_NAME));
|
||||
setCasServerUrlPrefix(getString(ConfigurationKeys.CAS_SERVER_URL_PREFIX));
|
||||
HANDLER.setArtifactParameterOverPost(getBoolean(ConfigurationKeys.ARTIFACT_PARAMETER_OVER_POST));
|
||||
|
|
@ -63,11 +62,7 @@ public final class SingleSignOutFilter extends AbstractConfigurationFilter {
|
|||
public void setLogoutParameterName(final String name) {
|
||||
HANDLER.setLogoutParameterName(name);
|
||||
}
|
||||
|
||||
public void setFrontLogoutParameterName(final String name) {
|
||||
HANDLER.setFrontLogoutParameterName(name);
|
||||
}
|
||||
|
||||
|
||||
public void setRelayStateParameterName(final String name) {
|
||||
HANDLER.setRelayStateParameterName(name);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@
|
|||
package org.jasig.cas.client.session;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.zip.Inflater;
|
||||
|
||||
|
|
@ -26,8 +27,8 @@ import javax.servlet.ServletException;
|
|||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.http.HttpSession;
|
||||
import javax.xml.bind.DatatypeConverter;
|
||||
|
||||
import org.apache.commons.codec.binary.Base64;
|
||||
import org.jasig.cas.client.Protocol;
|
||||
import org.jasig.cas.client.configuration.ConfigurationKeys;
|
||||
import org.jasig.cas.client.util.CommonUtils;
|
||||
|
|
@ -56,12 +57,9 @@ public final class SingleSignOutHandler {
|
|||
/** The name of the artifact parameter. This is used to capture the session identifier. */
|
||||
private String artifactParameterName = Protocol.CAS2.getArtifactParameterName();
|
||||
|
||||
/** Parameter name that stores logout request for back channel SLO */
|
||||
/** Parameter name that stores logout request for SLO */
|
||||
private String logoutParameterName = ConfigurationKeys.LOGOUT_PARAMETER_NAME.getDefaultValue();
|
||||
|
||||
/** Parameter name that stores logout request for front channel SLO */
|
||||
private String frontLogoutParameterName = ConfigurationKeys.FRONT_LOGOUT_PARAMETER_NAME.getDefaultValue();
|
||||
|
||||
|
||||
/** Parameter name that stores the state of the CAS server webflow for the callback */
|
||||
private String relayStateParameterName = ConfigurationKeys.RELAY_STATE_PARAMETER_NAME.getDefaultValue();
|
||||
|
||||
|
|
@ -74,7 +72,7 @@ public final class SingleSignOutHandler {
|
|||
|
||||
private List<String> safeParameters;
|
||||
|
||||
private LogoutStrategy logoutStrategy = isServlet30() ? new Servlet30LogoutStrategy() : new Servlet25LogoutStrategy();
|
||||
private final LogoutStrategy logoutStrategy = isServlet30() ? new Servlet30LogoutStrategy() : new Servlet25LogoutStrategy();
|
||||
|
||||
public void setSessionMappingStorage(final SessionMappingStorage storage) {
|
||||
this.sessionMappingStorage = storage;
|
||||
|
|
@ -96,7 +94,7 @@ public final class SingleSignOutHandler {
|
|||
}
|
||||
|
||||
/**
|
||||
* @param name Name of parameter containing CAS logout request message for back channel SLO.
|
||||
* @param name Name of parameter containing CAS logout request message for SLO.
|
||||
*/
|
||||
public void setLogoutParameterName(final String name) {
|
||||
this.logoutParameterName = name;
|
||||
|
|
@ -108,14 +106,7 @@ public final class SingleSignOutHandler {
|
|||
public void setCasServerUrlPrefix(final String casServerUrlPrefix) {
|
||||
this.casServerUrlPrefix = casServerUrlPrefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param name Name of parameter containing CAS logout request message for front channel SLO.
|
||||
*/
|
||||
public void setFrontLogoutParameterName(final String name) {
|
||||
this.frontLogoutParameterName = name;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param name Name of parameter containing the state of the CAS server webflow.
|
||||
*/
|
||||
|
|
@ -134,7 +125,6 @@ public final class SingleSignOutHandler {
|
|||
if (this.safeParameters == null) {
|
||||
CommonUtils.assertNotNull(this.artifactParameterName, "artifactParameterName cannot be null.");
|
||||
CommonUtils.assertNotNull(this.logoutParameterName, "logoutParameterName cannot be null.");
|
||||
CommonUtils.assertNotNull(this.frontLogoutParameterName, "frontLogoutParameterName cannot be null.");
|
||||
CommonUtils.assertNotNull(this.sessionMappingStorage, "sessionMappingStorage cannot be null.");
|
||||
CommonUtils.assertNotNull(this.relayStateParameterName, "relayStateParameterName cannot be null.");
|
||||
CommonUtils.assertNotNull(this.casServerUrlPrefix, "casServerUrlPrefix cannot be null.");
|
||||
|
|
@ -146,7 +136,7 @@ public final class SingleSignOutHandler {
|
|||
if (this.artifactParameterOverPost) {
|
||||
this.safeParameters = Arrays.asList(this.logoutParameterName, this.artifactParameterName);
|
||||
} else {
|
||||
this.safeParameters = Arrays.asList(this.logoutParameterName);
|
||||
this.safeParameters = Collections.singletonList(this.logoutParameterName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -164,32 +154,25 @@ public final class SingleSignOutHandler {
|
|||
}
|
||||
|
||||
/**
|
||||
* Determines whether the given request is a CAS back channel logout request.
|
||||
* Determines whether the given request is a CAS logout request.
|
||||
*
|
||||
* @param request HTTP request.
|
||||
*
|
||||
* @return True if request is logout request, false otherwise.
|
||||
*/
|
||||
private boolean isBackChannelLogoutRequest(final HttpServletRequest request) {
|
||||
return "POST".equals(request.getMethod())
|
||||
&& !isMultipartRequest(request)
|
||||
&& CommonUtils.isNotBlank(CommonUtils.safeGetParameter(request, this.logoutParameterName,
|
||||
this.safeParameters));
|
||||
private boolean isLogoutRequest(final HttpServletRequest request) {
|
||||
if ("POST".equalsIgnoreCase(request.getMethod())) {
|
||||
return !isMultipartRequest(request)
|
||||
&& CommonUtils.isNotBlank(CommonUtils.safeGetParameter(request, this.logoutParameterName,
|
||||
this.safeParameters));
|
||||
}
|
||||
|
||||
if ("GET".equalsIgnoreCase(request.getMethod())) {
|
||||
return CommonUtils.isNotBlank(CommonUtils.safeGetParameter(request, this.logoutParameterName, this.safeParameters));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether the given request is a CAS front channel logout request. Front Channel log out requests are only supported
|
||||
* when the 'casServerUrlPrefix' value is set.
|
||||
*
|
||||
* @param request HTTP request.
|
||||
*
|
||||
* @return True if request is logout request, false otherwise.
|
||||
*/
|
||||
private boolean isFrontChannelLogoutRequest(final HttpServletRequest request) {
|
||||
return "GET".equals(request.getMethod()) && CommonUtils.isNotBlank(this.casServerUrlPrefix)
|
||||
&& CommonUtils.isNotBlank(CommonUtils.safeGetParameter(request, this.frontLogoutParameterName));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Process a request regarding the SLO process: record the session or destroy it.
|
||||
*
|
||||
|
|
@ -202,26 +185,15 @@ public final class SingleSignOutHandler {
|
|||
logger.trace("Received a token request");
|
||||
recordSession(request);
|
||||
return true;
|
||||
|
||||
} else if (isBackChannelLogoutRequest(request)) {
|
||||
logger.trace("Received a back channel logout request");
|
||||
}
|
||||
|
||||
if (isLogoutRequest(request)) {
|
||||
logger.trace("Received a logout request");
|
||||
destroySession(request);
|
||||
return false;
|
||||
|
||||
} else if (isFrontChannelLogoutRequest(request)) {
|
||||
logger.trace("Received a front channel logout request");
|
||||
destroySession(request);
|
||||
// redirection url to the CAS server
|
||||
final String redirectionUrl = computeRedirectionToServer(request);
|
||||
if (redirectionUrl != null) {
|
||||
CommonUtils.sendRedirect(response, redirectionUrl);
|
||||
}
|
||||
return false;
|
||||
|
||||
} else {
|
||||
logger.trace("Ignoring URI for logout: {}", request.getRequestURI());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
logger.trace("Ignoring URI for logout: {}", request.getRequestURI());
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -244,7 +216,7 @@ public final class SingleSignOutHandler {
|
|||
try {
|
||||
this.sessionMappingStorage.removeBySessionById(session.getId());
|
||||
} catch (final Exception e) {
|
||||
// ignore if the session is already marked as invalid. Nothing we can do!
|
||||
// ignore if the session is already marked as invalid. Nothing we can do!
|
||||
}
|
||||
sessionMappingStorage.addSessionById(token, session);
|
||||
}
|
||||
|
|
@ -256,7 +228,7 @@ public final class SingleSignOutHandler {
|
|||
* @return the uncompressed logout message.
|
||||
*/
|
||||
private String uncompressLogoutMessage(final String originalMessage) {
|
||||
final byte[] binaryMessage = Base64.decodeBase64(originalMessage);
|
||||
final byte[] binaryMessage = DatatypeConverter.parseBase64Binary(originalMessage);
|
||||
|
||||
Inflater decompresser = null;
|
||||
try {
|
||||
|
|
@ -285,16 +257,17 @@ public final class SingleSignOutHandler {
|
|||
* @param request HTTP request containing a CAS logout message.
|
||||
*/
|
||||
private void destroySession(final HttpServletRequest request) {
|
||||
final String logoutMessage;
|
||||
// front channel logout -> the message needs to be base64 decoded + decompressed
|
||||
if (isFrontChannelLogoutRequest(request)) {
|
||||
logoutMessage = uncompressLogoutMessage(CommonUtils.safeGetParameter(request,
|
||||
this.frontLogoutParameterName));
|
||||
} else {
|
||||
logoutMessage = CommonUtils.safeGetParameter(request, this.logoutParameterName, this.safeParameters);
|
||||
String logoutMessage = CommonUtils.safeGetParameter(request, this.logoutParameterName, this.safeParameters);
|
||||
if (CommonUtils.isBlank(logoutMessage)) {
|
||||
logger.error("Could not locate logout message of the request from {}", this.logoutParameterName);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!logoutMessage.contains("SessionIndex")) {
|
||||
logoutMessage = uncompressLogoutMessage(logoutMessage);
|
||||
}
|
||||
|
||||
logger.trace("Logout request:\n{}", logoutMessage);
|
||||
|
||||
final String token = XmlUtils.getTextForElement(logoutMessage, "SessionIndex");
|
||||
if (CommonUtils.isNotBlank(token)) {
|
||||
final HttpSession session = this.sessionMappingStorage.removeSessionByMappingId(token);
|
||||
|
|
@ -313,33 +286,6 @@ public final class SingleSignOutHandler {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the redirection url to the CAS server when it's a front channel SLO
|
||||
* (depending on the relay state parameter).
|
||||
*
|
||||
* @param request The HTTP request.
|
||||
* @return the redirection url to the CAS server.
|
||||
*/
|
||||
private String computeRedirectionToServer(final HttpServletRequest request) {
|
||||
final String relayStateValue = CommonUtils.safeGetParameter(request, this.relayStateParameterName);
|
||||
// if we have a state value -> redirect to the CAS server to continue the logout process
|
||||
if (CommonUtils.isNotBlank(relayStateValue)) {
|
||||
final StringBuilder buffer = new StringBuilder();
|
||||
buffer.append(casServerUrlPrefix);
|
||||
if (!this.casServerUrlPrefix.endsWith("/")) {
|
||||
buffer.append("/");
|
||||
}
|
||||
buffer.append("logout?_eventId=next&");
|
||||
buffer.append(this.relayStateParameterName);
|
||||
buffer.append("=");
|
||||
buffer.append(CommonUtils.urlEncode(relayStateValue));
|
||||
final String redirectUrl = buffer.toString();
|
||||
logger.debug("Redirection url to the CAS server: {}", redirectUrl);
|
||||
return redirectUrl;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private boolean isMultipartRequest(final HttpServletRequest request) {
|
||||
return request.getContentType() != null && request.getContentType().toLowerCase().startsWith("multipart");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,6 +26,8 @@ import java.net.URLEncoder;
|
|||
import java.util.*;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.jasig.cas.client.Protocol;
|
||||
import org.jasig.cas.client.proxy.ProxyGrantingTicketStorage;
|
||||
import org.jasig.cas.client.ssl.HttpURLConnectionFactory;
|
||||
import org.jasig.cas.client.ssl.HttpsURLConnectionFactory;
|
||||
|
|
@ -57,10 +59,21 @@ public final class CommonUtils {
|
|||
|
||||
private static final HttpURLConnectionFactory DEFAULT_URL_CONNECTION_FACTORY = new HttpsURLConnectionFactory();
|
||||
|
||||
private static final String SERVICE_PARAMETER_NAMES;
|
||||
|
||||
private CommonUtils() {
|
||||
// nothing to do
|
||||
}
|
||||
|
||||
static {
|
||||
final Set<String> serviceParameterSet = new HashSet<String>(4);
|
||||
for (final Protocol protocol : Protocol.values()) {
|
||||
serviceParameterSet.add(protocol.getServiceParameterName());
|
||||
}
|
||||
SERVICE_PARAMETER_NAMES = serviceParameterSet.toString()
|
||||
.replaceAll("\\[|\\]", "")
|
||||
.replaceAll("\\s", "");
|
||||
}
|
||||
/**
|
||||
* Check whether the object is null or not. If it is, throw an exception and
|
||||
* display the message.
|
||||
|
|
@ -122,7 +135,7 @@ public final class CommonUtils {
|
|||
* @return true if its null or length of 0, false otherwise.
|
||||
*/
|
||||
public static boolean isEmpty(final String string) {
|
||||
return string == null || string.length() == 0;
|
||||
return string == null || string.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -144,7 +157,7 @@ public final class CommonUtils {
|
|||
* @return true if its blank, false otherwise.
|
||||
*/
|
||||
public static boolean isBlank(final String string) {
|
||||
return isEmpty(string) || string.trim().length() == 0;
|
||||
return isEmpty(string) || string.trim().isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -180,7 +193,7 @@ public final class CommonUtils {
|
|||
* @param value the value to encode.
|
||||
* @return the encoded value.
|
||||
*/
|
||||
public static String urlEncode(String value) {
|
||||
public static String urlEncode(final String value) {
|
||||
try {
|
||||
return URLEncoder.encode(value, "UTF-8");
|
||||
} catch (final UnsupportedEncodingException e) {
|
||||
|
|
@ -215,7 +228,7 @@ public final class CommonUtils {
|
|||
protected static String findMatchingServerName(final HttpServletRequest request, final String serverName) {
|
||||
final String[] serverNames = serverName.split(" ");
|
||||
|
||||
if (serverNames == null || serverNames.length == 0 || serverNames.length == 1) {
|
||||
if (serverNames.length == 0 || serverNames.length == 1) {
|
||||
return serverName;
|
||||
}
|
||||
|
||||
|
|
@ -259,6 +272,30 @@ public final class CommonUtils {
|
|||
return serverPort == 80 || serverPort == 443;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a service url from the HttpServletRequest or from the given
|
||||
* serviceUrl. Prefers the serviceUrl provided if both a serviceUrl and a
|
||||
* serviceName. Compiles a list of all service parameters for supported protocols
|
||||
* and removes them all from the query string.
|
||||
*
|
||||
* @param request the HttpServletRequest
|
||||
* @param response the HttpServletResponse
|
||||
* @param service the configured service url (this will be used if not null)
|
||||
* @param serverNames the server name to use to construct the service url if the service param is empty. Note, prior to CAS Client 3.3, this was a single value.
|
||||
* As of 3.3, it can be a space-separated value. We keep it as a single value, but will convert it to an array internally to get the matching value. This keeps backward compatability with anything using this public
|
||||
* method.
|
||||
* @param artifactParameterName the artifact parameter name to remove (i.e. ticket)
|
||||
* @param encode whether to encode the url or not (i.e. Jsession).
|
||||
* @return the service url to use.
|
||||
*/
|
||||
@Deprecated
|
||||
public static String constructServiceUrl(final HttpServletRequest request, final HttpServletResponse response,
|
||||
final String service, final String serverNames,
|
||||
final String artifactParameterName, final boolean encode) {
|
||||
return constructServiceUrl(request, response, service, serverNames, SERVICE_PARAMETER_NAMES
|
||||
, artifactParameterName, encode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a service url from the HttpServletRequest or from the given
|
||||
* serviceUrl. Prefers the serviceUrl provided if both a serviceUrl and a
|
||||
|
|
@ -267,7 +304,7 @@ public final class CommonUtils {
|
|||
* @param request the HttpServletRequest
|
||||
* @param response the HttpServletResponse
|
||||
* @param service the configured service url (this will be used if not null)
|
||||
* @param serverNames the server name to use to constuct the service url if the service param is empty. Note, prior to CAS Client 3.3, this was a single value.
|
||||
* @param serverNames the server name to use to construct the service url if the service param is empty. Note, prior to CAS Client 3.3, this was a single value.
|
||||
* As of 3.3, it can be a space-separated value. We keep it as a single value, but will convert it to an array internally to get the matching value. This keeps backward compatability with anything using this public
|
||||
* method.
|
||||
* @param serviceParameterName the service parameter name to remove (i.e. service)
|
||||
|
|
@ -286,7 +323,7 @@ public final class CommonUtils {
|
|||
final URIBuilder originalRequestUrl = new URIBuilder(request.getRequestURL().toString(), encode);
|
||||
originalRequestUrl.setParameters(request.getQueryString());
|
||||
|
||||
URIBuilder builder = null;
|
||||
final URIBuilder builder;
|
||||
|
||||
boolean containsScheme = true;
|
||||
if (!serverName.startsWith("https://") && !serverName.startsWith("http://")) {
|
||||
|
|
@ -305,9 +342,12 @@ public final class CommonUtils {
|
|||
|
||||
builder.setEncodedPath(request.getRequestURI());
|
||||
|
||||
for (final URIBuilder.BasicNameValuePair pair : originalRequestUrl.getQueryParams()) {
|
||||
if (!pair.getName().equals(artifactParameterName) && !pair.getName().equals(serviceParameterName)) {
|
||||
builder.addParameter(pair.getName(), pair.getValue());
|
||||
final List<String> serviceParameterNames = Arrays.asList(serviceParameterName.split(","));
|
||||
if (!serviceParameterNames.isEmpty() && !originalRequestUrl.getQueryParams().isEmpty()) {
|
||||
for (final URIBuilder.BasicNameValuePair pair : originalRequestUrl.getQueryParams()) {
|
||||
if (!pair.getName().equals(artifactParameterName) && !serviceParameterNames.contains(pair.getName())) {
|
||||
builder.addParameter(pair.getName(), pair.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ import java.beans.BeanInfo;
|
|||
import java.beans.IntrospectionException;
|
||||
import java.beans.Introspector;
|
||||
import java.beans.PropertyDescriptor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
|
||||
/**
|
||||
|
|
@ -148,4 +149,35 @@ public final class ReflectUtils {
|
|||
throw new RuntimeException("Error setting property " + propertyName, e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value of the given declared field on the target object or any of its superclasses.
|
||||
*
|
||||
* @param fieldName Name of field to get.
|
||||
* @param target Target object that possesses field.
|
||||
*
|
||||
* @return Field value.
|
||||
*/
|
||||
public static Object getField(final String fieldName, final Object target) {
|
||||
Class<?> clazz = target.getClass();
|
||||
Field field = null;
|
||||
do {
|
||||
try {
|
||||
field = clazz.getDeclaredField(fieldName);
|
||||
} catch (NoSuchFieldException e) {
|
||||
clazz = clazz.getSuperclass();
|
||||
}
|
||||
} while (field == null && clazz != null);
|
||||
if (field == null) {
|
||||
throw new IllegalArgumentException(fieldName + " does not exist on " + target);
|
||||
}
|
||||
try {
|
||||
if (!field.isAccessible()) {
|
||||
field.setAccessible(true);
|
||||
}
|
||||
return field.get(target);
|
||||
} catch (Exception e) {
|
||||
throw new IllegalArgumentException("Error getting field " + fieldName, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -126,7 +126,7 @@ public final class URIBuilder {
|
|||
} catch (final UnsupportedEncodingException e) {
|
||||
LOGGER.error(e.getMessage(), e);
|
||||
}
|
||||
return Collections.emptyList();
|
||||
return new ArrayList<BasicNameValuePair>();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -238,8 +238,9 @@ public final class URIBuilder {
|
|||
return this.encode ? CommonUtils.urlEncode(fragment) : fragment;
|
||||
}
|
||||
|
||||
public void setEncode(boolean encode) {
|
||||
public URIBuilder setEncode(boolean encode) {
|
||||
this.encode = encode;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -469,6 +470,18 @@ public final class URIBuilder {
|
|||
return this;
|
||||
}
|
||||
|
||||
public URIBuilder setEncodedFragment(final String fragment) {
|
||||
this.fragment = null;
|
||||
this.encodedFragment = fragment;
|
||||
return this;
|
||||
}
|
||||
|
||||
public URIBuilder setEncodedQuery(final String query) {
|
||||
this.query = null;
|
||||
this.encodedFragment = query;
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean isAbsolute() {
|
||||
return this.scheme != null;
|
||||
}
|
||||
|
|
@ -531,6 +544,54 @@ public final class URIBuilder {
|
|||
return s;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
final URIBuilder that = (URIBuilder) o;
|
||||
|
||||
if (port != that.port) return false;
|
||||
if (encode != that.encode) return false;
|
||||
if (scheme != null ? !scheme.equals(that.scheme) : that.scheme != null) return false;
|
||||
if (encodedSchemeSpecificPart != null ? !encodedSchemeSpecificPart.equals(that.encodedSchemeSpecificPart) : that.encodedSchemeSpecificPart != null)
|
||||
return false;
|
||||
if (encodedAuthority != null ? !encodedAuthority.equals(that.encodedAuthority) : that.encodedAuthority != null)
|
||||
return false;
|
||||
if (userInfo != null ? !userInfo.equals(that.userInfo) : that.userInfo != null) return false;
|
||||
if (encodedUserInfo != null ? !encodedUserInfo.equals(that.encodedUserInfo) : that.encodedUserInfo != null)
|
||||
return false;
|
||||
if (host != null ? !host.equals(that.host) : that.host != null) return false;
|
||||
if (path != null ? !path.equals(that.path) : that.path != null) return false;
|
||||
if (encodedPath != null ? !encodedPath.equals(that.encodedPath) : that.encodedPath != null) return false;
|
||||
if (encodedQuery != null ? !encodedQuery.equals(that.encodedQuery) : that.encodedQuery != null) return false;
|
||||
if (queryParams != null ? !queryParams.equals(that.queryParams) : that.queryParams != null) return false;
|
||||
if (query != null ? !query.equals(that.query) : that.query != null) return false;
|
||||
if (fragment != null ? !fragment.equals(that.fragment) : that.fragment != null) return false;
|
||||
return !(encodedFragment != null ? !encodedFragment.equals(that.encodedFragment) : that.encodedFragment != null);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = scheme != null ? scheme.hashCode() : 0;
|
||||
result = 31 * result + (encodedSchemeSpecificPart != null ? encodedSchemeSpecificPart.hashCode() : 0);
|
||||
result = 31 * result + (encodedAuthority != null ? encodedAuthority.hashCode() : 0);
|
||||
result = 31 * result + (userInfo != null ? userInfo.hashCode() : 0);
|
||||
result = 31 * result + (encodedUserInfo != null ? encodedUserInfo.hashCode() : 0);
|
||||
result = 31 * result + (host != null ? host.hashCode() : 0);
|
||||
result = 31 * result + port;
|
||||
result = 31 * result + (path != null ? path.hashCode() : 0);
|
||||
result = 31 * result + (encodedPath != null ? encodedPath.hashCode() : 0);
|
||||
result = 31 * result + (encodedQuery != null ? encodedQuery.hashCode() : 0);
|
||||
result = 31 * result + (queryParams != null ? queryParams.hashCode() : 0);
|
||||
result = 31 * result + (query != null ? query.hashCode() : 0);
|
||||
result = 31 * result + (encode ? 1 : 0);
|
||||
result = 31 * result + (fragment != null ? fragment.hashCode() : 0);
|
||||
result = 31 * result + (encodedFragment != null ? encodedFragment.hashCode() : 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
public static class BasicNameValuePair implements Cloneable, Serializable {
|
||||
private static final long serialVersionUID = -6437800749411518984L;
|
||||
|
||||
|
|
|
|||
|
|
@ -101,32 +101,39 @@ public final class AssertionImpl implements Assertion {
|
|||
CommonUtils.assertNotNull(this.attributes, "attributes cannot be null.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Date getAuthenticationDate() {
|
||||
return this.authenticationDate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Date getValidFromDate() {
|
||||
return this.validFromDate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Date getValidUntilDate() {
|
||||
return this.validUntilDate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> getAttributes() {
|
||||
return this.attributes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AttributePrincipal getPrincipal() {
|
||||
return this.principal;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValid() {
|
||||
if (this.validFromDate == null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
final Date now = new Date();
|
||||
return this.validFromDate.before(now) && (this.validUntilDate == null || this.validUntilDate.after(now));
|
||||
return (this.validFromDate.before(now) || this.validFromDate.equals(now))
|
||||
&& (this.validUntilDate == null || this.validUntilDate.after(now) || this.validUntilDate.equals(now));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ public class Cas20ProxyReceivingTicketValidationFilter extends AbstractTicketVal
|
|||
TOLERANCE.getName(), IGNORE_PATTERN.getName(), IGNORE_URL_PATTERN_TYPE.getName(), HOSTNAME_VERIFIER.getName(), HOSTNAME_VERIFIER_CONFIG.getName(),
|
||||
EXCEPTION_ON_VALIDATION_FAILURE.getName(), REDIRECT_AFTER_VALIDATION.getName(), USE_SESSION.getName(), SECRET_KEY.getName(), CIPHER_ALGORITHM.getName(), PROXY_RECEPTOR_URL.getName(),
|
||||
PROXY_GRANTING_TICKET_STORAGE_CLASS.getName(), MILLIS_BETWEEN_CLEAN_UPS.getName(), ACCEPT_ANY_PROXY.getName(), ALLOWED_PROXY_CHAINS.getName(), TICKET_VALIDATOR_CLASS.getName(),
|
||||
PROXY_CALLBACK_URL.getName(), FRONT_LOGOUT_PARAMETER_NAME.getName(), RELAY_STATE_PARAMETER_NAME.getName()
|
||||
PROXY_CALLBACK_URL.getName(), RELAY_STATE_PARAMETER_NAME.getName()
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -20,6 +20,9 @@ package org.jasig.cas.client.configuration;
|
|||
|
||||
import org.junit.Test;
|
||||
|
||||
import javax.servlet.Filter;
|
||||
import javax.servlet.FilterConfig;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
public final class ConfigurationStrategyNameTests {
|
||||
|
|
@ -33,4 +36,22 @@ public final class ConfigurationStrategyNameTests {
|
|||
assertEquals(LegacyConfigurationStrategyImpl.class, ConfigurationStrategyName.resolveToConfigurationStrategy(ConfigurationStrategyName.DEFAULT.name()));
|
||||
assertEquals(LegacyConfigurationStrategyImpl.class, ConfigurationStrategyName.resolveToConfigurationStrategy("bleh!"));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void resolveToClass() {
|
||||
assertEquals(TestClass.class, ConfigurationStrategyName.resolveToConfigurationStrategy(TestClass.class.getName()));
|
||||
}
|
||||
|
||||
private class TestClass extends BaseConfigurationStrategy {
|
||||
|
||||
@Override
|
||||
protected String get(ConfigurationKey configurationKey) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public void init(FilterConfig filterConfig, Class<? extends Filter> filterClazz) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,12 +18,11 @@
|
|||
*/
|
||||
package org.jasig.cas.client.session;
|
||||
|
||||
import javax.xml.bind.DatatypeConverter;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.Date;
|
||||
import java.util.zip.Deflater;
|
||||
|
||||
import org.apache.commons.codec.binary.Base64;
|
||||
|
||||
/**
|
||||
* Logout message generator to perform tests on Single Sign Out feature.
|
||||
* Greatly inspired by the source code in the CAS server itself.
|
||||
|
|
@ -51,6 +50,6 @@ public final class LogoutMessageGenerator {
|
|||
final int resultSize = deflater.deflate(buffer);
|
||||
final byte[] output = new byte[resultSize];
|
||||
System.arraycopy(buffer, 0, output, 0, resultSize);
|
||||
return Base64.encodeBase64String(output);
|
||||
return DatatypeConverter.printBase64Binary(output);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -87,8 +87,8 @@ public class SingleSignOutFilterTests {
|
|||
@Test
|
||||
public void frontChannelRequest() throws IOException, ServletException {
|
||||
final String logoutMessage = LogoutMessageGenerator.generateFrontChannelLogoutMessage(TICKET);
|
||||
request.setParameter(ConfigurationKeys.FRONT_LOGOUT_PARAMETER_NAME.getDefaultValue(), logoutMessage);
|
||||
request.setQueryString(ConfigurationKeys.FRONT_LOGOUT_PARAMETER_NAME.getDefaultValue() + "=" + logoutMessage);
|
||||
request.setParameter(ConfigurationKeys.LOGOUT_PARAMETER_NAME.getDefaultValue(), logoutMessage);
|
||||
request.setQueryString(ConfigurationKeys.LOGOUT_PARAMETER_NAME.getDefaultValue() + "=" + logoutMessage);
|
||||
request.setMethod("GET");
|
||||
final MockHttpSession session = new MockHttpSession();
|
||||
SingleSignOutFilter.getSingleSignOutHandler().getSessionMappingStorage().addSessionById(TICKET, session);
|
||||
|
|
@ -100,16 +100,14 @@ public class SingleSignOutFilterTests {
|
|||
@Test
|
||||
public void frontChannelRequestRelayState() throws IOException, ServletException {
|
||||
final String logoutMessage = LogoutMessageGenerator.generateFrontChannelLogoutMessage(TICKET);
|
||||
request.setParameter(ConfigurationKeys.FRONT_LOGOUT_PARAMETER_NAME.getDefaultValue(), logoutMessage);
|
||||
request.setParameter(ConfigurationKeys.LOGOUT_PARAMETER_NAME.getDefaultValue(), logoutMessage);
|
||||
request.setParameter(ConfigurationKeys.RELAY_STATE_PARAMETER_NAME.getDefaultValue(), RELAY_STATE);
|
||||
request.setQueryString(ConfigurationKeys.FRONT_LOGOUT_PARAMETER_NAME.getDefaultValue() + "=" + logoutMessage + "&" +
|
||||
request.setQueryString(ConfigurationKeys.LOGOUT_PARAMETER_NAME.getDefaultValue() + "=" + logoutMessage + "&" +
|
||||
ConfigurationKeys.RELAY_STATE_PARAMETER_NAME.getDefaultValue() + "=" + RELAY_STATE);
|
||||
request.setMethod("GET");
|
||||
final MockHttpSession session = new MockHttpSession();
|
||||
SingleSignOutFilter.getSingleSignOutHandler().getSessionMappingStorage().addSessionById(TICKET, session);
|
||||
filter.doFilter(request, response, filterChain);
|
||||
assertNull(SingleSignOutFilter.getSingleSignOutHandler().getSessionMappingStorage().removeSessionByMappingId(TICKET));
|
||||
assertEquals(CAS_SERVER_URL_PREFIX + "/logout?_eventId=next&" +
|
||||
ConfigurationKeys.RELAY_STATE_PARAMETER_NAME.getDefaultValue() + "=" + RELAY_STATE, response.getRedirectedUrl());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,7 +31,6 @@ import org.springframework.mock.web.MockHttpSession;
|
|||
|
||||
/**
|
||||
* @author Matt Brown <matt.brown@citrix.com>
|
||||
* @version $Revision$ $Date$
|
||||
* @since 3.2.1
|
||||
*/
|
||||
public final class SingleSignOutHandlerTests {
|
||||
|
|
@ -39,9 +38,8 @@ public final class SingleSignOutHandlerTests {
|
|||
private final static String ANOTHER_PARAMETER = "anotherParameter";
|
||||
private final static String TICKET = "ST-xxxxxxxx";
|
||||
private final static String URL = "http://mycasserver";
|
||||
private final static String LOGOUT_PARAMETER_NAME = "logoutRequest2";
|
||||
private final static String FRONT_LOGOUT_PARAMETER_NAME = "SAMLRequest2";
|
||||
private final static String RELAY_STATE_PARAMETER_NAME = "RelayState2";
|
||||
private final static String LOGOUT_PARAMETER_NAME = "logoutRequest";
|
||||
private final static String RELAY_STATE_PARAMETER_NAME = "RelayState";
|
||||
private final static String ARTIFACT_PARAMETER_NAME = "ticket2";
|
||||
|
||||
private SingleSignOutHandler handler;
|
||||
|
|
@ -52,7 +50,6 @@ public final class SingleSignOutHandlerTests {
|
|||
public void setUp() throws Exception {
|
||||
handler = new SingleSignOutHandler();
|
||||
handler.setLogoutParameterName(LOGOUT_PARAMETER_NAME);
|
||||
handler.setFrontLogoutParameterName(FRONT_LOGOUT_PARAMETER_NAME);
|
||||
handler.setRelayStateParameterName(RELAY_STATE_PARAMETER_NAME);
|
||||
handler.setArtifactParameterName(ARTIFACT_PARAMETER_NAME);
|
||||
handler.setCasServerUrlPrefix(URL);
|
||||
|
|
@ -143,8 +140,8 @@ public final class SingleSignOutHandlerTests {
|
|||
@Test
|
||||
public void frontChannelLogoutFailsIfNoSessionIndex() {
|
||||
final String logoutMessage = LogoutMessageGenerator.generateFrontChannelLogoutMessage("");
|
||||
request.setParameter(FRONT_LOGOUT_PARAMETER_NAME, logoutMessage);
|
||||
request.setQueryString(FRONT_LOGOUT_PARAMETER_NAME + "=" + logoutMessage);
|
||||
request.setParameter(LOGOUT_PARAMETER_NAME, logoutMessage);
|
||||
request.setQueryString(LOGOUT_PARAMETER_NAME + "=" + logoutMessage);
|
||||
request.setMethod("GET");
|
||||
final MockHttpSession session = new MockHttpSession();
|
||||
handler.getSessionMappingStorage().addSessionById(TICKET, session);
|
||||
|
|
@ -155,8 +152,8 @@ public final class SingleSignOutHandlerTests {
|
|||
@Test
|
||||
public void frontChannelLogoutOK() {
|
||||
final String logoutMessage = LogoutMessageGenerator.generateFrontChannelLogoutMessage(TICKET);
|
||||
request.setParameter(FRONT_LOGOUT_PARAMETER_NAME, logoutMessage);
|
||||
request.setQueryString(FRONT_LOGOUT_PARAMETER_NAME + "=" + logoutMessage);
|
||||
request.setParameter(LOGOUT_PARAMETER_NAME, logoutMessage);
|
||||
request.setQueryString(LOGOUT_PARAMETER_NAME + "=" + logoutMessage);
|
||||
request.setMethod("GET");
|
||||
final MockHttpSession session = new MockHttpSession();
|
||||
handler.getSessionMappingStorage().addSessionById(TICKET, session);
|
||||
|
|
@ -168,15 +165,13 @@ public final class SingleSignOutHandlerTests {
|
|||
@Test
|
||||
public void frontChannelLogoutRelayStateOK() {
|
||||
final String logoutMessage = LogoutMessageGenerator.generateFrontChannelLogoutMessage(TICKET);
|
||||
request.setParameter(FRONT_LOGOUT_PARAMETER_NAME, logoutMessage);
|
||||
request.setParameter(LOGOUT_PARAMETER_NAME, logoutMessage);
|
||||
request.setParameter(RELAY_STATE_PARAMETER_NAME, TICKET);
|
||||
request.setQueryString(FRONT_LOGOUT_PARAMETER_NAME + "=" + logoutMessage + "&" + RELAY_STATE_PARAMETER_NAME + "=" + TICKET);
|
||||
request.setQueryString(LOGOUT_PARAMETER_NAME + "=" + logoutMessage + "&" + RELAY_STATE_PARAMETER_NAME + "=" + TICKET);
|
||||
request.setMethod("GET");
|
||||
final MockHttpSession session = new MockHttpSession();
|
||||
handler.getSessionMappingStorage().addSessionById(TICKET, session);
|
||||
assertFalse(handler.process(request, response));
|
||||
assertTrue(session.isInvalid());
|
||||
assertEquals(URL + "/logout?_eventId=next&" + RELAY_STATE_PARAMETER_NAME + "=" + TICKET,
|
||||
response.getRedirectedUrl());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -152,6 +152,20 @@ public final class CommonUtilsTests extends TestCase {
|
|||
assertEquals("https://www.myserver.com/hello/hithere/?custom=custom", constructedUrl);
|
||||
}
|
||||
|
||||
public void testConstructServiceUrlWithParamsCasAndServerNameWithSchema() {
|
||||
final String CONST_MY_URL = "https://www.myserver.com/hello/hithere/";
|
||||
final MockHttpServletRequest request = new MockHttpServletRequest("GET", "/hello/hithere/");
|
||||
request.setScheme("https");
|
||||
request.setSecure(true);
|
||||
request.setQueryString("service=this&ticket=that&custom=custom");
|
||||
|
||||
final MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
final String constructedUrl = CommonUtils.constructServiceUrl(request, response, null, "https://www.myserver.com",
|
||||
Protocol.CAS3.getServiceParameterName(), Protocol.CAS3.getArtifactParameterName() , false);
|
||||
|
||||
assertEquals("https://www.myserver.com/hello/hithere/?custom=custom", constructedUrl);
|
||||
}
|
||||
|
||||
|
||||
public void testConstructServiceUrlWithParamsSaml() {
|
||||
final String CONST_MY_URL = "https://www.myserver.com/hello/hithere/";
|
||||
|
|
@ -181,6 +195,20 @@ public final class CommonUtilsTests extends TestCase {
|
|||
assertEquals("https://www.myserver.com/hello/hithere/?custom=custom", constructedUrl);
|
||||
}
|
||||
|
||||
public void testConstructServiceUrlWithNoServiceParametersPassed() {
|
||||
final String CONST_MY_URL = "https://www.myserver.com/hello/hithere/";
|
||||
final MockHttpServletRequest request = new MockHttpServletRequest("GET", "/hello/hithere/");
|
||||
request.setScheme("https");
|
||||
request.setSecure(true);
|
||||
request.setQueryString("TARGET=Test1&service=Test2&custom=custom");
|
||||
|
||||
final MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
final String constructedUrl = CommonUtils.constructServiceUrl(request, response, null, "www.myserver.com",
|
||||
Protocol.SAML11.getArtifactParameterName() , true);
|
||||
|
||||
assertEquals("https://www.myserver.com/hello/hithere/?custom=custom", constructedUrl);
|
||||
}
|
||||
|
||||
public void testConstructServiceUrlWithEncodedParams2Saml() {
|
||||
final String CONST_MY_URL = "https://www.myserver.com/hello/hithere/";
|
||||
final MockHttpServletRequest request = new MockHttpServletRequest("GET", "/hello/hithere/");
|
||||
|
|
|
|||
|
|
@ -54,6 +54,18 @@ public class ReflectUtilsTests extends TestCase {
|
|||
assertTrue(bean.isFlag());
|
||||
}
|
||||
|
||||
public void testGetField() {
|
||||
final TestBean bean = new TestBean();
|
||||
bean.setName("bob");
|
||||
assertEquals(bean.getName(), ReflectUtils.getField("name", bean));
|
||||
}
|
||||
|
||||
public void testGetFieldSuperclass() {
|
||||
final TestSubBean bean = new TestSubBean();
|
||||
bean.setName("bob");
|
||||
assertEquals(bean.getName(), ReflectUtils.getField("name", bean));
|
||||
}
|
||||
|
||||
static class TestBean {
|
||||
private int count;
|
||||
private boolean flag;
|
||||
|
|
@ -102,4 +114,16 @@ public class ReflectUtilsTests extends TestCase {
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
static class TestSubBean extends TestBean {
|
||||
private String state;
|
||||
|
||||
public String getState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
public void setState(String state) {
|
||||
this.state = state;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,334 @@
|
|||
/*
|
||||
* Licensed to Jasig under one or more contributor license
|
||||
* agreements. See the NOTICE file distributed with this work
|
||||
* for additional information regarding copyright ownership.
|
||||
* Jasig licenses this file to you under the Apache License,
|
||||
* Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a
|
||||
* copy of the License at the following location:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
/*
|
||||
|
||||
* Licensed to Jasig under one or more contributor license
|
||||
* agreements. See the NOTICE file distributed with this work
|
||||
* for additional information regarding copyright ownership.
|
||||
* Jasig licenses this file to you under the Apache License,
|
||||
* Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a
|
||||
* copy of the License at the following location:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
|
||||
*/
|
||||
|
||||
package org.jasig.cas.client.util;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* @author Misagh Moayyed
|
||||
*/
|
||||
public class URIBuilderTests {
|
||||
|
||||
@Test
|
||||
public void allPartsUsed() {
|
||||
URIBuilder builder = new URIBuilder()
|
||||
.setScheme("http")
|
||||
.setHost("apache.org")
|
||||
.setPath("/shindig")
|
||||
.setCustomQuery("hello=world")
|
||||
.setFragment("foo");
|
||||
assertEquals("http://apache.org/shindig?hello=world#foo", builder.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void noSchemeUsed() {
|
||||
URIBuilder builder = new URIBuilder()
|
||||
.setHost("apache.org")
|
||||
.setPath("/shindig")
|
||||
.setCustomQuery("hello=world")
|
||||
.setFragment("foo");
|
||||
assertEquals("//apache.org/shindig?hello=world#foo", builder.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void noAuthorityUsed() {
|
||||
URIBuilder builder = new URIBuilder()
|
||||
.setScheme("http")
|
||||
.setPath("/shindig")
|
||||
.setCustomQuery("hello=world")
|
||||
.setFragment("foo");
|
||||
assertEquals("http:/shindig?hello=world#foo", builder.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void noPathUsed() {
|
||||
URIBuilder builder = new URIBuilder()
|
||||
.setScheme("http")
|
||||
.setHost("apache.org")
|
||||
.setCustomQuery("hello=world")
|
||||
.setFragment("foo");
|
||||
assertEquals("http://apache.org?hello=world#foo", builder.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void noQueryUsed() {
|
||||
URIBuilder builder = new URIBuilder()
|
||||
.setScheme("http")
|
||||
.setHost("apache.org")
|
||||
.setPath("/shindig")
|
||||
.setFragment("foo");
|
||||
assertEquals("http://apache.org/shindig#foo", builder.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void noFragmentUsed() {
|
||||
URIBuilder builder = new URIBuilder()
|
||||
.setScheme("http")
|
||||
.setHost("apache.org")
|
||||
.setPath("/shindig")
|
||||
.setCustomQuery("hello=world");
|
||||
assertEquals("http://apache.org/shindig?hello=world", builder.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void hostRelativePaths() {
|
||||
URIBuilder builder = new URIBuilder()
|
||||
.setPath("/shindig")
|
||||
.setCustomQuery("hello=world")
|
||||
.setFragment("foo");
|
||||
assertEquals("/shindig?hello=world#foo", builder.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void relativePaths() {
|
||||
URIBuilder builder = new URIBuilder()
|
||||
.setPath("foo")
|
||||
.setCustomQuery("hello=world")
|
||||
.setFragment("foo");
|
||||
assertEquals("foo?hello=world#foo", builder.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void noPathNoHostNoAuthority() {
|
||||
URIBuilder builder = new URIBuilder()
|
||||
.setCustomQuery("hello=world")
|
||||
.setFragment("foo");
|
||||
assertEquals("?hello=world#foo", builder.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void justSchemeAndAuthority() {
|
||||
URIBuilder builder = new URIBuilder()
|
||||
.setScheme("http")
|
||||
.setHost("apache.org");
|
||||
assertEquals("http://apache.org", builder.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void justPath() {
|
||||
URIBuilder builder = new URIBuilder()
|
||||
.setPath("/shindig");
|
||||
assertEquals("/shindig", builder.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void justAuthorityAndPath() {
|
||||
URIBuilder builder = new URIBuilder()
|
||||
.setHost("apache.org")
|
||||
.setPath("/shindig");
|
||||
assertEquals("//apache.org/shindig", builder.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void justQuery() {
|
||||
URIBuilder builder = new URIBuilder()
|
||||
.setCustomQuery("hello=world");
|
||||
assertEquals("?hello=world", builder.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void justFragment() {
|
||||
URIBuilder builder = new URIBuilder()
|
||||
.setFragment("foo");
|
||||
assertEquals("#foo", builder.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void addSingleQueryParameter() {
|
||||
URIBuilder builder = new URIBuilder()
|
||||
.setScheme("http")
|
||||
.setHost("apache.org")
|
||||
.setPath("/shindig")
|
||||
.addParameter("hello", "world")
|
||||
.setFragment("foo");
|
||||
assertEquals("http://apache.org/shindig?hello=world#foo", builder.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void addTwoQueryParameters() {
|
||||
URIBuilder builder = new URIBuilder()
|
||||
.setScheme("http")
|
||||
.setHost("apache.org")
|
||||
.setPath("/shindig")
|
||||
.addParameter("hello", "world")
|
||||
.addParameter("foo", "bar")
|
||||
.setFragment("foo");
|
||||
assertEquals("http://apache.org/shindig?hello=world&foo=bar#foo", builder.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void iterableQueryParameters() {
|
||||
List<URIBuilder.BasicNameValuePair> list = new ArrayList<URIBuilder.BasicNameValuePair>();
|
||||
list.add(new URIBuilder.BasicNameValuePair("hello", "world"));
|
||||
list.add(new URIBuilder.BasicNameValuePair("hello", "monde"));
|
||||
URIBuilder builder = new URIBuilder()
|
||||
.setScheme("http")
|
||||
.setHost("apache.org")
|
||||
.setPath("/shindig")
|
||||
.addParameters(list)
|
||||
.setFragment("foo");
|
||||
assertEquals("http://apache.org/shindig?hello=world&hello=monde#foo", builder.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void removeQueryParameter() {
|
||||
URIBuilder uri = new URIBuilder("http://www.example.com/foo?bar=baz&quux=baz");
|
||||
uri.removeQuery();
|
||||
assertEquals("http://www.example.com/foo", uri.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void addIdenticalParameters() {
|
||||
URIBuilder builder = new URIBuilder()
|
||||
.setScheme("http")
|
||||
.setHost("apache.org")
|
||||
.setPath("/shindig")
|
||||
.addParameter("hello", "world")
|
||||
.addParameter("hello", "goodbye")
|
||||
.setFragment("foo");
|
||||
assertEquals("http://apache.org/shindig?hello=world&hello=goodbye#foo", builder.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void queryStringIsUnescaped() {
|
||||
URIBuilder builder = new URIBuilder()
|
||||
.setScheme("http")
|
||||
.setHost("apache.org")
|
||||
.setPath("/shindig")
|
||||
.setCustomQuery("hello+world=world%26bar");
|
||||
assertEquals("world&bar", builder.build().getQuery().split("=")[1]);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void queryParamsAreEscaped() {
|
||||
URIBuilder builder = new URIBuilder(true)
|
||||
.setScheme("http")
|
||||
.setHost("apache.org")
|
||||
.setEncodedPath("/shindig")
|
||||
.addParameter("hello world", "foo&bar")
|
||||
.setFragment("foo");
|
||||
assertEquals("http://apache.org/shindig?hello+world=foo%26bar#foo", builder.toString());
|
||||
assertEquals("hello+world=foo&bar", builder.build().getQuery());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void addSingleFragmentParameter() {
|
||||
URIBuilder builder = new URIBuilder()
|
||||
.setScheme("http")
|
||||
.setHost("apache.org")
|
||||
.setPath("/shindig")
|
||||
.setFragment("hello=world")
|
||||
.setCustomQuery("foo");
|
||||
assertEquals("http://apache.org/shindig?foo#hello=world", builder.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void fragmentStringIsUnescaped() {
|
||||
URIBuilder builder = new URIBuilder(true)
|
||||
.setScheme("http")
|
||||
.setHost("apache.org")
|
||||
.setPath("/shindig")
|
||||
.setEncodedFragment("hello+world=world%26bar");
|
||||
|
||||
assertEquals("world&bar", builder.build().getFragment().split("=")[1]);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parse() {
|
||||
URIBuilder builder = new URIBuilder()
|
||||
.digestURI(URI.create("http://apache.org/shindig?foo=bar%26baz&foo=three#blah"));
|
||||
|
||||
assertEquals("http", builder.getScheme());
|
||||
assertEquals("apache.org", builder.getHost());
|
||||
assertEquals("/shindig", builder.getPath());
|
||||
|
||||
List<URIBuilder.BasicNameValuePair> list = builder.getQueryParams();
|
||||
for (URIBuilder.BasicNameValuePair pair : list) {
|
||||
assertEquals(pair.getName(), "foo");
|
||||
assertTrue(pair.getValue().equals("three") || pair.getValue().equals("bar"));
|
||||
}
|
||||
assertEquals(list.size(), 2);
|
||||
assertEquals("blah", builder.getFragment());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void constructFromUriAndBack() {
|
||||
URI uri = URI.create("http://apache.org/foo/bar?foo=bar&a=b&c=d&y=z&foo=zoo#foo");
|
||||
URIBuilder builder = new URIBuilder(uri);
|
||||
|
||||
assertEquals(uri, builder.build());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void constructFromUriAndModify() {
|
||||
URI uri = URI.create("http://apache.org/foo/bar?foo=bar#foo");
|
||||
URIBuilder builder = new URIBuilder(uri);
|
||||
|
||||
builder.setHost("example.org");
|
||||
builder.addParameter("bar", "foo");
|
||||
|
||||
assertEquals("http://example.org/foo/bar?foo=bar&bar=foo#foo", builder.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void equalsAndHashCodeOk() {
|
||||
URIBuilder uri = new URIBuilder().digestURI(URI.create("http://example.org/foo/bar/baz?blah=blah#boo"));
|
||||
URIBuilder uri2 = new URIBuilder(URI.create("http://example.org/foo/bar/baz?blah=blah#boo"));
|
||||
|
||||
assertEquals(uri, uri2);
|
||||
assertEquals(uri2, uri);
|
||||
|
||||
assertEquals(uri, uri);
|
||||
|
||||
assertNotNull(uri);
|
||||
assertNotSame(uri, "http://example.org/foo/bar/baz?blah=blah#boo");
|
||||
assertNotSame(uri, URI.create("http://example.org/foo/bar/baz?blah=blah#boo"));
|
||||
assertEquals(uri.hashCode(), uri2.hashCode());
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -18,6 +18,7 @@
|
|||
*/
|
||||
package org.jasig.cas.client.validation;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import junit.framework.TestCase;
|
||||
|
|
@ -49,6 +50,11 @@ public final class AssertionImplTests extends TestCase {
|
|||
assertNull(assertion.getPrincipal().getProxyTicketFor("test"));
|
||||
}
|
||||
|
||||
public void testAssertionValidity() throws Exception {
|
||||
final Assertion assertion = new AssertionImpl(CONST_PRINCIPAL, new Date(), new Date(), new Date(), CONST_ATTRIBUTES);
|
||||
assertTrue(assertion.isValid());
|
||||
}
|
||||
|
||||
public void testCompleteConstructor() {
|
||||
final Assertion assertion = new AssertionImpl(CONST_PRINCIPAL, CONST_ATTRIBUTES);
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@
|
|||
<artifactId>cas-client</artifactId>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.jasig.cas.client</groupId>
|
||||
<artifactId>cas-client-integration-atlassian</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<name>Jasig CAS Client for Java - Atlassian Integration</name>
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@
|
|||
<artifactId>cas-client</artifactId>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.jasig.cas.client</groupId>
|
||||
<artifactId>cas-client-integration-jboss</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<name>Jasig CAS Client for Java - JBoss Integration</name>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,72 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>cas-client</artifactId>
|
||||
<groupId>org.jasig.cas.client</groupId>
|
||||
<version>3.5.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>cas-client-integration-jetty</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<name>Jasig CAS Client for Java - Jetty Container Integration</name>
|
||||
|
||||
<properties>
|
||||
<!-- Note Jetty 9.2.x is the last version to support Java SE 7 -->
|
||||
<jetty.version>9.2.14.v20151106</jetty.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.jasig.cas.client</groupId>
|
||||
<artifactId>cas-client-core</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-security</artifactId>
|
||||
<version>${jetty.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Test dependencies -->
|
||||
<dependency>
|
||||
<groupId>org.jasig.cas.client</groupId>
|
||||
<artifactId>cas-client-core</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<type>test-jar</type>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-webapp</artifactId>
|
||||
<version>${jetty.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-plus</artifactId>
|
||||
<version>${jetty.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-annotations</artifactId>
|
||||
<version>${jetty.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>apache-jsp</artifactId>
|
||||
<version>${jetty.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.servlet</groupId>
|
||||
<artifactId>javax.servlet-api</artifactId>
|
||||
<version>3.1.0</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
package org.jasig.cas.client.jetty;
|
||||
|
||||
import org.eclipse.jetty.security.UserAuthentication;
|
||||
import org.jasig.cas.client.util.CommonUtils;
|
||||
import org.jasig.cas.client.validation.Assertion;
|
||||
|
||||
/**
|
||||
* CAS-specific user authentication.
|
||||
*
|
||||
* @author Marvin S. Addison
|
||||
*/
|
||||
public class CasAuthentication extends UserAuthentication {
|
||||
|
||||
/** CAS authenticator that produced this authentication. */
|
||||
private final CasAuthenticator authenticator;
|
||||
|
||||
/** CAS ticket that was successfully validated to permit authentication. */
|
||||
private final String ticket;
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new instance.
|
||||
*
|
||||
* @param authenticator The authenticator that produced this authentication.
|
||||
* @param ticket The CAS ticket that was successfully validated to permit authentication.
|
||||
* @param assertion The CAS assertion produced from successful ticket validation.
|
||||
*/
|
||||
public CasAuthentication(final CasAuthenticator authenticator, final String ticket, final Assertion assertion) {
|
||||
super(authenticator.getAuthMethod(), new CasUserIdentity(assertion, authenticator.getRoleAttribute()));
|
||||
CommonUtils.assertNotNull(ticket, "Ticket cannot be null");
|
||||
CommonUtils.assertNotNull(authenticator, "CasAuthenticator cannot be null");
|
||||
this.authenticator = authenticator;
|
||||
this.ticket = ticket;
|
||||
}
|
||||
|
||||
/** @return The CAS ticket that was successfully validated to permit authentication. */
|
||||
public String getTicket() {
|
||||
return ticket;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void logout() {
|
||||
super.logout();
|
||||
this.authenticator.clearCachedAuthentication(ticket);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,248 @@
|
|||
/*
|
||||
* Licensed to Jasig under one or more contributor license
|
||||
* agreements. See the NOTICE file distributed with this work
|
||||
* for additional information regarding copyright ownership.
|
||||
* Jasig licenses this file to you under the Apache License,
|
||||
* Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a
|
||||
* copy of the License at the following location:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.jasig.cas.client.jetty;
|
||||
|
||||
import org.eclipse.jetty.security.Authenticator;
|
||||
import org.eclipse.jetty.security.ServerAuthException;
|
||||
import org.eclipse.jetty.server.Authentication;
|
||||
import org.eclipse.jetty.util.component.AbstractLifeCycle;
|
||||
import org.jasig.cas.client.Protocol;
|
||||
import org.jasig.cas.client.util.CommonUtils;
|
||||
import org.jasig.cas.client.util.ReflectUtils;
|
||||
import org.jasig.cas.client.validation.AbstractCasProtocolUrlBasedTicketValidator;
|
||||
import org.jasig.cas.client.validation.AbstractUrlBasedTicketValidator;
|
||||
import org.jasig.cas.client.validation.Assertion;
|
||||
import org.jasig.cas.client.validation.TicketValidator;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.http.HttpSession;
|
||||
import java.io.IOException;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
|
||||
/**
|
||||
* Jetty authenticator component for container-managed CAS authentication.
|
||||
* <p><em>NOTE:</em> This component does not support CAS gateway mode.</p>
|
||||
*
|
||||
* @author Marvin S. Addison
|
||||
* @since 3.4.2
|
||||
*/
|
||||
public class CasAuthenticator extends AbstractLifeCycle implements Authenticator {
|
||||
|
||||
/** Name of authentication method provided by this authenticator. */
|
||||
public static final String AUTH_METHOD = "CAS";
|
||||
|
||||
/** Session attribute used to cache CAS authentication data. */
|
||||
private static final String CACHED_AUTHN_ATTRIBUTE = "org.jasig.cas.client.jetty.Authentication";
|
||||
|
||||
/** Logger instance. */
|
||||
private final Logger logger = LoggerFactory.getLogger(CasAuthenticator.class);
|
||||
|
||||
/** Map of tickets to sessions. */
|
||||
private final ConcurrentMap<String, WeakReference<HttpSession>> sessionMap =
|
||||
new ConcurrentHashMap<String, WeakReference<HttpSession>>();
|
||||
|
||||
/** CAS ticket validator component. */
|
||||
private TicketValidator ticketValidator;
|
||||
|
||||
/** Space-delimited list of server names. */
|
||||
private String serverNames;
|
||||
|
||||
/** CAS principal attribute containing role data. */
|
||||
private String roleAttribute;
|
||||
|
||||
/** URL to /login URI on CAS server. */
|
||||
private String casServerLoginUrl;
|
||||
|
||||
/** Protocol used by ticket validator. */
|
||||
private Protocol protocol;
|
||||
|
||||
/** CAS renew parameter. */
|
||||
private boolean renew;
|
||||
|
||||
|
||||
/**
|
||||
* Sets the CAS ticket validator component.
|
||||
*
|
||||
* @param ticketValidator Ticket validator, MUST NOT be null.
|
||||
*/
|
||||
public void setTicketValidator(final TicketValidator ticketValidator) {
|
||||
CommonUtils.assertNotNull(ticketValidator, "TicketValidator cannot be null");
|
||||
if (ticketValidator instanceof AbstractUrlBasedTicketValidator) {
|
||||
if (ticketValidator instanceof AbstractCasProtocolUrlBasedTicketValidator) {
|
||||
protocol = Protocol.CAS2;
|
||||
} else {
|
||||
protocol = Protocol.SAML11;
|
||||
}
|
||||
casServerLoginUrl = ReflectUtils.getField("casServerUrlPrefix", ticketValidator) + "/login";
|
||||
renew = (Boolean) ReflectUtils.getField("renew", ticketValidator);
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unsupported ticket validator " + ticketValidator);
|
||||
}
|
||||
this.ticketValidator = ticketValidator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the names of the server host running Jetty.
|
||||
*
|
||||
* @param nameList Space-delimited list of one or more server names, e.g. "www1.example.com www2.example.com".
|
||||
* MUST NOT be blank.
|
||||
*/
|
||||
public void setServerNames(final String nameList) {
|
||||
CommonUtils.isNotBlank(nameList);
|
||||
this.serverNames = nameList;
|
||||
}
|
||||
|
||||
/** @return The name of the CAS principal attribute that contains role data. */
|
||||
public String getRoleAttribute() {
|
||||
return roleAttribute;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the name of the CAS principal attribute that contains role data.
|
||||
*
|
||||
* @param roleAttribute Role attribute name. MUST NOT be blank.
|
||||
*/
|
||||
public void setRoleAttribute(final String roleAttribute) {
|
||||
CommonUtils.isNotBlank(roleAttribute);
|
||||
this.roleAttribute = roleAttribute;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setConfiguration(final AuthConfiguration configuration) {
|
||||
// Nothing to do
|
||||
// All configuration must be via CAS-specific setter methods
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAuthMethod() {
|
||||
return AUTH_METHOD;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void prepareRequest(final ServletRequest request) {
|
||||
// Nothing to do
|
||||
}
|
||||
|
||||
@Override
|
||||
public Authentication validateRequest(
|
||||
final ServletRequest servletRequest, final ServletResponse servletResponse, final boolean mandatory)
|
||||
throws ServerAuthException {
|
||||
|
||||
final HttpServletRequest request = (HttpServletRequest) servletRequest;
|
||||
final HttpServletResponse response = (HttpServletResponse) servletResponse;
|
||||
|
||||
CasAuthentication authentication = fetchCachedAuthentication(request);
|
||||
if (authentication != null) {
|
||||
return authentication;
|
||||
}
|
||||
|
||||
final String ticket = request.getParameter(protocol.getArtifactParameterName());
|
||||
if (ticket != null && mandatory) {
|
||||
try {
|
||||
logger.debug("Attempting to validate {}", ticket);
|
||||
final Assertion assertion = ticketValidator.validate(ticket, serviceUrl(request, response));
|
||||
logger.info("Successfully authenticated {}", assertion.getPrincipal());
|
||||
authentication = new CasAuthentication(this, ticket, assertion);
|
||||
cacheAuthentication(request, authentication);
|
||||
} catch (Exception e) {
|
||||
throw new ServerAuthException("CAS ticket validation failed", e);
|
||||
}
|
||||
}
|
||||
if (authentication != null) {
|
||||
return authentication;
|
||||
} else if (mandatory) {
|
||||
redirectToCas(request, response);
|
||||
return Authentication.SEND_CONTINUE;
|
||||
}
|
||||
return Authentication.UNAUTHENTICATED;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean secureResponse(
|
||||
final ServletRequest request,
|
||||
final ServletResponse response,
|
||||
final boolean mandatory,
|
||||
final Authentication.User user) throws ServerAuthException {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doStart() throws Exception {
|
||||
if (ticketValidator == null) {
|
||||
throw new RuntimeException("TicketValidator cannot be null");
|
||||
}
|
||||
if (serverNames == null) {
|
||||
throw new RuntimeException("ServerNames cannot be null");
|
||||
}
|
||||
}
|
||||
|
||||
protected void clearCachedAuthentication(final String ticket) {
|
||||
final WeakReference<HttpSession> sessionRef = sessionMap.remove(ticket);
|
||||
if (sessionRef != null && sessionRef.get() != null) {
|
||||
sessionRef.get().removeAttribute(CACHED_AUTHN_ATTRIBUTE);
|
||||
}
|
||||
}
|
||||
|
||||
private void cacheAuthentication(final HttpServletRequest request, final CasAuthentication authentication) {
|
||||
final HttpSession session = request.getSession(true);
|
||||
if (session != null) {
|
||||
session.setAttribute(CACHED_AUTHN_ATTRIBUTE, authentication);
|
||||
sessionMap.put(authentication.getTicket(), new WeakReference<HttpSession>(session));
|
||||
}
|
||||
}
|
||||
|
||||
private CasAuthentication fetchCachedAuthentication(final HttpServletRequest request) {
|
||||
final HttpSession session = request.getSession(false);
|
||||
if (session != null) {
|
||||
return (CasAuthentication) session.getAttribute(CACHED_AUTHN_ATTRIBUTE);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private String serviceUrl(final HttpServletRequest request, final HttpServletResponse response) {
|
||||
return CommonUtils.constructServiceUrl(
|
||||
request,
|
||||
response,
|
||||
null,
|
||||
serverNames,
|
||||
protocol.getServiceParameterName(),
|
||||
protocol.getArtifactParameterName(),
|
||||
true);
|
||||
}
|
||||
|
||||
private void redirectToCas(
|
||||
final HttpServletRequest request, final HttpServletResponse response) throws ServerAuthException {
|
||||
try {
|
||||
final String redirectUrl = CommonUtils.constructRedirectUrl(
|
||||
casServerLoginUrl, protocol.getServiceParameterName(), serviceUrl(request, response), renew, false);
|
||||
logger.debug("Redirecting to {}", redirectUrl);
|
||||
response.sendRedirect(redirectUrl);
|
||||
} catch (IOException e) {
|
||||
logger.debug("Redirect to CAS failed with error: {}", e);
|
||||
throw new ServerAuthException("Redirect to CAS failed", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
package org.jasig.cas.client.jetty;
|
||||
|
||||
import org.eclipse.jetty.server.UserIdentity;
|
||||
import org.jasig.cas.client.authentication.AttributePrincipal;
|
||||
import org.jasig.cas.client.util.CommonUtils;
|
||||
import org.jasig.cas.client.validation.Assertion;
|
||||
|
||||
import javax.security.auth.Subject;
|
||||
import java.security.Principal;
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* CAS user identity backed by assertion data.
|
||||
*
|
||||
* @author Marvin S. Addison
|
||||
*/
|
||||
public class CasUserIdentity implements UserIdentity {
|
||||
|
||||
/** CAS principal. */
|
||||
private AttributePrincipal principal;
|
||||
|
||||
/** Assertion attribute containing role data. */
|
||||
private String roleAttribute;
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new instance from a CAS assertion containing principal information.
|
||||
*
|
||||
* @param assertion CAS assertion resulting from successful ticket validation.
|
||||
* @param roleAttribute Principal attribute containing role data.
|
||||
*/
|
||||
public CasUserIdentity(final Assertion assertion, final String roleAttribute) {
|
||||
CommonUtils.assertNotNull(assertion, "Assertion cannot be null");
|
||||
this.principal = assertion.getPrincipal();
|
||||
this.roleAttribute = roleAttribute;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Subject getSubject() {
|
||||
final Subject subject = new Subject();
|
||||
subject.getPrincipals().add(principal);
|
||||
return subject;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Principal getUserPrincipal() {
|
||||
return principal;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isUserInRole(final String role, final Scope scope) {
|
||||
if (roleAttribute != null) {
|
||||
final Object value = principal.getAttributes().get(roleAttribute);
|
||||
if (value instanceof Collection) {
|
||||
return ((Collection) value).contains(role);
|
||||
} else if (value instanceof String) {
|
||||
return value.equals(role);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return principal.getName();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,210 @@
|
|||
package org.jasig.cas.client.jetty;
|
||||
|
||||
import org.apache.tomcat.InstanceManager;
|
||||
import org.apache.tomcat.SimpleInstanceManager;
|
||||
import org.eclipse.jetty.annotations.ServletContainerInitializersStarter;
|
||||
import org.eclipse.jetty.apache.jsp.JettyJasperInitializer;
|
||||
import org.eclipse.jetty.jsp.JettyJspServlet;
|
||||
import org.eclipse.jetty.plus.annotation.ContainerInitializer;
|
||||
import org.eclipse.jetty.security.ConstraintMapping;
|
||||
import org.eclipse.jetty.security.ConstraintSecurityHandler;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.servlet.ServletHolder;
|
||||
import org.eclipse.jetty.util.security.Constraint;
|
||||
import org.eclipse.jetty.webapp.WebAppContext;
|
||||
import org.jasig.cas.client.PublicTestHttpServer;
|
||||
import org.jasig.cas.client.validation.Cas20ServiceTicketValidator;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.*;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.nio.CharBuffer;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* Unit test for {@link CasAuthenticator}.
|
||||
*
|
||||
* @author Marvin S. Addison
|
||||
*/
|
||||
public class CasAuthenticatorTest {
|
||||
|
||||
private static final Server server = new Server(8080);
|
||||
private static final CasAuthenticator authenticator = new CasAuthenticator();
|
||||
|
||||
@BeforeClass
|
||||
public static void beforeClass() throws Exception {
|
||||
final WebAppContext context = new WebAppContext();
|
||||
context.setContextPath("/webapp");
|
||||
String workingDir = new File(".").getAbsolutePath();
|
||||
workingDir = workingDir.substring(0, workingDir.length() - 2);
|
||||
final String webappDir;
|
||||
if (workingDir.endsWith("/cas-client-integration-jetty")) {
|
||||
webappDir = workingDir + "/src/test/webapp";
|
||||
} else {
|
||||
webappDir = workingDir + "/cas-client-integration-jetty/src/test/webapp";
|
||||
}
|
||||
context.setWar(webappDir);
|
||||
|
||||
|
||||
// JSP config from https://github.com/jetty-project/embedded-jetty-jsp/
|
||||
System.setProperty("org.apache.jasper.compiler.disablejsr199", "false");
|
||||
context.setAttribute("javax.servlet.context.tempdir", getScratchDir());
|
||||
context.setAttribute("org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern",
|
||||
".*/[^/]*servlet-api-[^/]*\\.jar$|.*/javax.servlet.jsp.jstl-.*\\.jar$|.*/.*taglibs.*\\.jar$");
|
||||
context.setAttribute("org.eclipse.jetty.containerInitializers", jspInitializers());
|
||||
context.setAttribute(InstanceManager.class.getName(), new SimpleInstanceManager());
|
||||
context.addBean(new ServletContainerInitializersStarter(context), true);
|
||||
context.addServlet(jspServletHolder(), "*.jsp");
|
||||
|
||||
// Wire up CAS authentication
|
||||
authenticator.setServerNames("localhost:8080");
|
||||
authenticator.setTicketValidator(new Cas20ServiceTicketValidator("http://localhost:8081/cas"));
|
||||
|
||||
// Configure security handling for webapp context
|
||||
final ConstraintSecurityHandler securityHandler = new ConstraintSecurityHandler();
|
||||
final Constraint constraint = new Constraint("CasRealm", Constraint.ANY_AUTH);
|
||||
constraint.setAuthenticate(true);
|
||||
final ConstraintMapping secureMapping = new ConstraintMapping();
|
||||
secureMapping.setPathSpec("/secure.jsp");
|
||||
secureMapping.setConstraint(constraint);
|
||||
securityHandler.addConstraintMapping(secureMapping);
|
||||
securityHandler.setAuthenticator(authenticator);
|
||||
context.setSecurityHandler(securityHandler);
|
||||
|
||||
// Add webapp context and start the server
|
||||
server.setHandler(context);
|
||||
server.start();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValidateRequestPublicPageNoTicket() throws Exception {
|
||||
final HttpURLConnection uc = openConnection("http://localhost:8080/webapp/");
|
||||
try {
|
||||
assertEquals(200, uc.getResponseCode());
|
||||
assertTrue(readOutput(uc).contains("Welcome everyone"));
|
||||
} finally {
|
||||
uc.disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValidateRequestPublicPageWithTicket() throws Exception {
|
||||
final HttpURLConnection uc = openConnection("http://localhost:8080/webapp/?ticket=ST-12345");
|
||||
try {
|
||||
assertEquals(200, uc.getResponseCode());
|
||||
assertTrue(readOutput(uc).contains("Welcome everyone"));
|
||||
} finally {
|
||||
uc.disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValidateRequestSecurePageNoTicket() throws Exception {
|
||||
final HttpURLConnection uc = openConnection("http://localhost:8080/webapp/secure.jsp");
|
||||
try {
|
||||
assertEquals(302, uc.getResponseCode());
|
||||
assertEquals(
|
||||
"http://localhost:8081/cas/login?service=http%3A%2F%2Flocalhost%3A8080%2Fwebapp%2Fsecure.jsp",
|
||||
uc.getHeaderField("Location"));
|
||||
} finally {
|
||||
uc.disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValidateRequestSecurePageWithTicket() throws Exception {
|
||||
final String successResponse = "<cas:serviceResponse xmlns:cas='http://www.yale.edu/tp/cas'>" +
|
||||
"<cas:authenticationSuccess>" +
|
||||
"<cas:user>bob</cas:user>" +
|
||||
"</cas:authenticationSuccess>" +
|
||||
"</cas:serviceResponse>";
|
||||
final PublicTestHttpServer server = PublicTestHttpServer.instance(8081);
|
||||
server.content = successResponse.getBytes(StandardCharsets.UTF_8);
|
||||
final HttpURLConnection uc = openConnection("http://localhost:8080/webapp/secure.jsp?ticket=ST-12345");
|
||||
try {
|
||||
assertEquals(200, uc.getResponseCode());
|
||||
assertTrue(readOutput(uc).contains("Hello bob"));
|
||||
} finally {
|
||||
uc.disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void afterClass() throws Exception {
|
||||
server.stop();
|
||||
}
|
||||
|
||||
private String readOutput(final URLConnection connection) throws IOException {
|
||||
final InputStreamReader reader = new InputStreamReader(connection.getInputStream());
|
||||
final StringBuilder builder = new StringBuilder();
|
||||
final CharBuffer buffer = CharBuffer.allocate(1024);
|
||||
try {
|
||||
while (reader.read(buffer) > 0) {
|
||||
builder.append(buffer.flip());
|
||||
buffer.clear();
|
||||
}
|
||||
} finally {
|
||||
reader.close();
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
private static File getScratchDir() throws IOException
|
||||
{
|
||||
final File tempDir = new File(System.getProperty("java.io.tmpdir"));
|
||||
final File scratchDir = new File(tempDir.toString(), "embedded-jetty-jsp");
|
||||
|
||||
if (!scratchDir.exists())
|
||||
{
|
||||
if (!scratchDir.mkdirs())
|
||||
{
|
||||
throw new IOException("Unable to create scratch directory: " + scratchDir);
|
||||
}
|
||||
}
|
||||
return scratchDir;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure the jsp engine is initialized correctly
|
||||
*/
|
||||
private static List<ContainerInitializer> jspInitializers()
|
||||
{
|
||||
return Collections.singletonList(new ContainerInitializer(new JettyJasperInitializer(), null));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create JSP Servlet (must be named "jsp")
|
||||
*/
|
||||
private static ServletHolder jspServletHolder()
|
||||
{
|
||||
final ServletHolder holderJsp = new ServletHolder("jsp", JettyJspServlet.class);
|
||||
holderJsp.setInitOrder(0);
|
||||
holderJsp.setInitParameter("logVerbosityLevel", "DEBUG");
|
||||
holderJsp.setInitParameter("fork", "false");
|
||||
holderJsp.setInitParameter("xpoweredBy", "false");
|
||||
holderJsp.setInitParameter("compilerTargetVM", "1.7");
|
||||
holderJsp.setInitParameter("compilerSourceVM", "1.7");
|
||||
holderJsp.setInitParameter("keepgenerated", "true");
|
||||
return holderJsp;
|
||||
}
|
||||
|
||||
private static HttpURLConnection openConnection(final String url) throws IOException {
|
||||
final HttpURLConnection uc;
|
||||
try {
|
||||
uc = (HttpURLConnection) new URL(url).openConnection();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("Invalid URL: " + url, e);
|
||||
}
|
||||
uc.setInstanceFollowRedirects(false);
|
||||
uc.connect();
|
||||
return uc;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure.dtd">
|
||||
|
||||
<Configure class="org.eclipse.jetty.webapp.WebAppContext">
|
||||
<Set name="contextPath">/</Set>
|
||||
<Set name="war"><SystemProperty name="jetty.base"/>/webapps/yourapp</Set>
|
||||
<Get name="securityHandler">
|
||||
<Set name="authenticator">
|
||||
<New class="org.jasig.cas.client.jetty.CasAuthenticator">
|
||||
<Set name="serverNames">app.example.com</Set>
|
||||
<Set name="ticketValidator">
|
||||
<New class="org.jasig.cas.client.validation.Cas20ServiceTicketValidator">
|
||||
<Arg>https://cas.example.com/cas</Arg>
|
||||
<!--<Set name="renew">true</Set>-->
|
||||
</New>
|
||||
</Set>
|
||||
</New>
|
||||
</Set>
|
||||
</Get>
|
||||
</Configure>
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure.dtd">
|
||||
|
||||
<Configure class="org.eclipse.jetty.webapp.WebAppContext">
|
||||
<Set name="contextPath">/</Set>
|
||||
<Set name="war"><SystemProperty name="jetty.base"/>/webapps/yourapp</Set>
|
||||
<Get name="securityHandler">
|
||||
<Set name="authenticator">
|
||||
<New class="org.jasig.cas.client.jetty.CasAuthenticator">
|
||||
<Set name="serverNames">app.example.com</Set>
|
||||
<Set name="roleAttribute">memberOf</Set>
|
||||
<Set name="ticketValidator">
|
||||
<New class="org.jasig.cas.client.validation.Saml11TicketValidator">
|
||||
<Arg>https://cas.example.com/cas</Arg>
|
||||
<!--<Set name="renew">true</Set>-->
|
||||
</New>
|
||||
</Set>
|
||||
</New>
|
||||
</Set>
|
||||
</Get>
|
||||
</Configure>
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Welcome Page</title>
|
||||
</head>
|
||||
<body><h1>Welcome everyone</h1></body>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Secure Page</title>
|
||||
</head>
|
||||
<body><h1>Hello <%=request.getUserPrincipal()%></h1></body>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -7,7 +7,6 @@
|
|||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>org.jasig.cas.client</groupId>
|
||||
<artifactId>cas-client-integration-tomcat-common</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<name>Jasig CAS Client for Java - Common Tomcat Integration Support</name>
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@
|
|||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>org.jasig.cas.client</groupId>
|
||||
<artifactId>cas-client-integration-tomcat-v6</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<name>Jasig CAS Client for Java - Tomcat 6.x Integration</name>
|
||||
|
|
|
|||
|
|
@ -51,11 +51,7 @@ public class SingleSignOutValve extends AbstractLifecycleValve implements Sessio
|
|||
public void setLogoutParameterName(final String name) {
|
||||
this.handler.setLogoutParameterName(name);
|
||||
}
|
||||
|
||||
public void setFrontLogoutParameterName(final String name) {
|
||||
this.handler.setFrontLogoutParameterName(name);
|
||||
}
|
||||
|
||||
|
||||
public void setRelayStateParameterName(final String name) {
|
||||
this.handler.setRelayStateParameterName(name);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@
|
|||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>org.jasig.cas.client</groupId>
|
||||
<artifactId>cas-client-integration-tomcat-v7</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<name>Jasig CAS Client for Java - Tomcat 7.x Integration</name>
|
||||
|
|
|
|||
|
|
@ -55,11 +55,7 @@ public class SingleSignOutValve extends ValveBase implements SessionListener {
|
|||
public void setLogoutParameterName(final String name) {
|
||||
this.handler.setLogoutParameterName(name);
|
||||
}
|
||||
|
||||
public void setFrontLogoutParameterName(final String name) {
|
||||
this.handler.setFrontLogoutParameterName(name);
|
||||
}
|
||||
|
||||
|
||||
public void setRelayStateParameterName(final String name) {
|
||||
this.handler.setRelayStateParameterName(name);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,30 @@
|
|||
Licensed to Apereo under one or more contributor license
|
||||
agreements. See the NOTICE file distributed with this work
|
||||
for additional information regarding copyright ownership.
|
||||
Apereo licenses this file to you under the Apache License,
|
||||
Version 2.0 (the "License"); you may not use this file
|
||||
except in compliance with the License. You may obtain a
|
||||
copy of the License at the following location:
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
|
||||
This project includes:
|
||||
Jasig CAS Client for Java - Common Tomcat Integration Support under Apache License Version 2.0
|
||||
Jasig CAS Client for Java - Core under Apache License Version 2.0
|
||||
Jasig CAS Client for Java - SAML Protocol Support under Apache License Version 2.0
|
||||
Jasig CAS Client for Java - Tomcat 8.x Integration under Apache License Version 2.0
|
||||
Java Servlet API under CDDL + GPLv2 with classpath exception
|
||||
JCL 1.1.1 implemented over SLF4J under MIT License
|
||||
Joda-Time under Apache 2
|
||||
JUnit under Common Public License Version 1.0
|
||||
SLF4J API Module under MIT License
|
||||
SLF4J Simple Binding under MIT License
|
||||
tomcat-catalina under Apache License, Version 2.0
|
||||
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>cas-client</artifactId>
|
||||
<groupId>org.jasig.cas.client</groupId>
|
||||
<version>3.5.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>cas-client-integration-tomcat-v8</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<name>Jasig CAS Client for Java - Tomcat 8.x Integration</name>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.jasig.cas.client</groupId>
|
||||
<artifactId>cas-client-integration-tomcat-common</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<type>jar</type>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jasig.cas.client</groupId>
|
||||
<artifactId>cas-client-support-saml</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<type>jar</type>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.tomcat</groupId>
|
||||
<artifactId>tomcat-catalina</artifactId>
|
||||
<version>8.0.1</version>
|
||||
<type>jar</type>
|
||||
<scope>provided</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.apache.tomcat</groupId>
|
||||
<artifactId>tomcat-servlet-api</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>org.apache.tomcat</groupId>
|
||||
<artifactId>tomcat-juli</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>org.apache.tomcat</groupId>
|
||||
<artifactId>tomcat-annotations-api</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>org.apache.tomcat</groupId>
|
||||
<artifactId>tomcat-api</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>org.apache.tomcat</groupId>
|
||||
<artifactId>tomcat-util</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.jasig.cas.client</groupId>
|
||||
<artifactId>cas-client-core</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<type>jar</type>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
|
|
@ -0,0 +1,198 @@
|
|||
/*
|
||||
* Licensed to Jasig under one or more contributor license
|
||||
* agreements. See the NOTICE file distributed with this work
|
||||
* for additional information regarding copyright ownership.
|
||||
* Jasig licenses this file to you under the Apache License,
|
||||
* Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a
|
||||
* copy of the License at the following location:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.jasig.cas.client.tomcat.v8;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.security.Principal;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.apache.catalina.*;
|
||||
import org.apache.catalina.authenticator.AuthenticatorBase;
|
||||
import org.apache.catalina.connector.Request;
|
||||
import org.jasig.cas.client.tomcat.AuthenticatorDelegate;
|
||||
import org.jasig.cas.client.tomcat.CasRealm;
|
||||
import org.jasig.cas.client.util.CommonUtils;
|
||||
import org.jasig.cas.client.validation.TicketValidator;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Base authenticator for all authentication protocols supported by CAS.
|
||||
*
|
||||
* @author Scott Battaglia
|
||||
* @version $Revision$ $Date$
|
||||
* @since 3.1.12
|
||||
*/
|
||||
public abstract class AbstractAuthenticator extends AuthenticatorBase implements LifecycleListener {
|
||||
|
||||
protected final Logger logger = LoggerFactory.getLogger(getClass());
|
||||
|
||||
private final AuthenticatorDelegate delegate = new AuthenticatorDelegate();
|
||||
|
||||
private String casServerUrlPrefix;
|
||||
|
||||
private String encoding;
|
||||
|
||||
private boolean encode;
|
||||
|
||||
private boolean renew;
|
||||
|
||||
protected abstract String getAuthenticationMethod();
|
||||
|
||||
/**
|
||||
* Provided for Tomcat 7.0.8 support.
|
||||
*
|
||||
* @return the authentication method.
|
||||
*/
|
||||
protected String getAuthMethod() {
|
||||
return getAuthenticationMethod();
|
||||
}
|
||||
|
||||
/**
|
||||
* Abstract method that subclasses should use to provide the name of the artifact parameter (i.e. ticket)
|
||||
*
|
||||
* @return the artifact parameter name. CANNOT be NULL.
|
||||
*/
|
||||
protected abstract String getArtifactParameterName();
|
||||
|
||||
/**
|
||||
* Abstract method that subclasses should use to provide the name of the service parameter (i.e. service)
|
||||
*
|
||||
* @return the service parameter name. CANNOT be NULL.
|
||||
*/
|
||||
protected abstract String getServiceParameterName();
|
||||
|
||||
/**
|
||||
* Returns the single instance of the ticket validator to use to validate tickets. Sub classes should include
|
||||
* the one appropriate for the
|
||||
*
|
||||
* @return a fully configured ticket validator. CANNOT be NULL.
|
||||
*/
|
||||
protected abstract TicketValidator getTicketValidator();
|
||||
|
||||
protected void startInternal() throws LifecycleException {
|
||||
super.startInternal();
|
||||
logger.debug("{} starting.", getName());
|
||||
final Realm realm = this.context.getRealm();
|
||||
try {
|
||||
CommonUtils.assertTrue(realm instanceof CasRealm, "Expected CasRealm but got " + realm.getClass());
|
||||
CommonUtils.assertNotNull(this.casServerUrlPrefix, "casServerUrlPrefix cannot be null.");
|
||||
CommonUtils.assertNotNull(this.delegate.getCasServerLoginUrl(), "casServerLoginUrl cannot be null.");
|
||||
CommonUtils.assertTrue(this.delegate.getServerName() != null || this.delegate.getServiceUrl() != null,
|
||||
"either serverName or serviceUrl must be set.");
|
||||
this.delegate.setRealm((CasRealm) realm);
|
||||
} catch (final Exception e) {
|
||||
throw new LifecycleException(e);
|
||||
}
|
||||
// Complete delegate initialization after the component is started.
|
||||
// See #lifecycleEvent() method.
|
||||
addLifecycleListener(this);
|
||||
}
|
||||
|
||||
protected final String getCasServerUrlPrefix() {
|
||||
return this.casServerUrlPrefix;
|
||||
}
|
||||
|
||||
public final void setCasServerUrlPrefix(final String casServerUrlPrefix) {
|
||||
this.casServerUrlPrefix = casServerUrlPrefix;
|
||||
}
|
||||
|
||||
public final void setCasServerLoginUrl(final String casServerLoginUrl) {
|
||||
this.delegate.setCasServerLoginUrl(casServerLoginUrl);
|
||||
}
|
||||
|
||||
public final boolean isEncode() {
|
||||
return this.encode;
|
||||
}
|
||||
|
||||
public final void setEncode(final boolean encode) {
|
||||
this.encode = encode;
|
||||
}
|
||||
|
||||
protected final boolean isRenew() {
|
||||
return this.renew;
|
||||
}
|
||||
|
||||
public void setRenew(final boolean renew) {
|
||||
this.renew = renew;
|
||||
}
|
||||
|
||||
public final void setServerName(final String serverName) {
|
||||
this.delegate.setServerName(serverName);
|
||||
}
|
||||
|
||||
public final void setServiceUrl(final String serviceUrl) {
|
||||
this.delegate.setServiceUrl(serviceUrl);
|
||||
}
|
||||
|
||||
protected final String getEncoding() {
|
||||
return this.encoding;
|
||||
}
|
||||
|
||||
public final void setEncoding(final String encoding) {
|
||||
this.encoding = encoding;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public final boolean authenticate(final Request request, final HttpServletResponse response) throws IOException {
|
||||
Principal principal = request.getUserPrincipal();
|
||||
boolean result = false;
|
||||
if (principal == null) {
|
||||
// Authentication sets the response headers for status and redirect if needed
|
||||
principal = this.delegate.authenticate(request.getRequest(), response);
|
||||
if (principal != null) {
|
||||
register(request, response, principal, getAuthenticationMethod(), null, null);
|
||||
result = true;
|
||||
}
|
||||
} else {
|
||||
result = true;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public void lifecycleEvent(final LifecycleEvent event) {
|
||||
if (AFTER_START_EVENT.equals(event.getType())) {
|
||||
logger.debug("{} processing lifecycle event {}", getName(), AFTER_START_EVENT);
|
||||
this.delegate.setTicketValidator(getTicketValidator());
|
||||
this.delegate.setArtifactParameterName(getArtifactParameterName());
|
||||
this.delegate.setServiceParameterName(getServiceParameterName());
|
||||
}
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public String getInfo() {
|
||||
return getName() + "/1.0";
|
||||
}
|
||||
|
||||
/** {@inheritDoc}
|
||||
* @throws LifecycleException */
|
||||
protected synchronized void setState(LifecycleState state, Object data) throws LifecycleException {
|
||||
super.setState(state, data);
|
||||
if (LifecycleState.STARTED.equals(state)) {
|
||||
logger.info("{} started.", getName());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Authenticator descriptive name.
|
||||
*/
|
||||
protected abstract String getName();
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* Licensed to Jasig under one or more contributor license
|
||||
* agreements. See the NOTICE file distributed with this work
|
||||
* for additional information regarding copyright ownership.
|
||||
* Jasig licenses this file to you under the Apache License,
|
||||
* Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a
|
||||
* copy of the License at the following location:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.jasig.cas.client.tomcat.v8;
|
||||
|
||||
/**
|
||||
* Base class for all CAS protocol authenticators.
|
||||
*
|
||||
* @author Scott Battaglia
|
||||
* @version $Revision$ $Date$
|
||||
* @since 3.1.12
|
||||
*/
|
||||
public abstract class AbstractCasAuthenticator extends AbstractAuthenticator {
|
||||
|
||||
private String proxyCallbackUrl;
|
||||
|
||||
protected final String getProxyCallbackUrl() {
|
||||
return this.proxyCallbackUrl;
|
||||
}
|
||||
|
||||
public final void setProxyCallbackUrl(final String proxyCallbackUrl) {
|
||||
this.proxyCallbackUrl = proxyCallbackUrl;
|
||||
}
|
||||
|
||||
protected final String getArtifactParameterName() {
|
||||
return "ticket";
|
||||
}
|
||||
|
||||
protected final String getServiceParameterName() {
|
||||
return "service";
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,85 @@
|
|||
/*
|
||||
* Licensed to Jasig under one or more contributor license
|
||||
* agreements. See the NOTICE file distributed with this work
|
||||
* for additional information regarding copyright ownership.
|
||||
* Jasig licenses this file to you under the Apache License,
|
||||
* Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a
|
||||
* copy of the License at the following location:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.jasig.cas.client.tomcat.v8;
|
||||
|
||||
import java.security.Principal;
|
||||
import org.apache.catalina.Wrapper;
|
||||
import org.apache.catalina.realm.RealmBase;
|
||||
import org.jasig.cas.client.tomcat.CasRealm;
|
||||
|
||||
/**
|
||||
* Base <code>Realm</code> implementation for all CAS realms.
|
||||
*
|
||||
* @author Marvin S. Addison
|
||||
* @version $Revision$
|
||||
*
|
||||
*/
|
||||
public abstract class AbstractCasRealm extends RealmBase implements CasRealm {
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public Principal authenticate(final Principal p) {
|
||||
return getDelegate().authenticate(p);
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public String[] getRoles(final Principal p) {
|
||||
return getDelegate().getRoles(p);
|
||||
}
|
||||
|
||||
public boolean hasRole(final Principal principal, final String role) {
|
||||
return getDelegate().hasRole(principal, role);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tomcat 7.0.8 changed their APIs so {@link #hasRole(java.security.Principal, String)} is only valid for 7.0.7 and below.
|
||||
*/
|
||||
public boolean hasRole(final Wrapper wrapper, final Principal principal, final String role) {
|
||||
return hasRole(principal, role);
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public String toString() {
|
||||
return getName();
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public String getInfo() {
|
||||
return getClass().getName() + "/1.0";
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
protected String getName() {
|
||||
return getClass().getSimpleName();
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
protected String getPassword(final String userName) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
protected Principal getPrincipal(final String userName) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Delegate that all {@link CasRealm} operations are delegated to.
|
||||
*/
|
||||
protected abstract CasRealm getDelegate();
|
||||
}
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* Licensed to Jasig under one or more contributor license
|
||||
* agreements. See the NOTICE file distributed with this work
|
||||
* for additional information regarding copyright ownership.
|
||||
* Jasig licenses this file to you under the Apache License,
|
||||
* Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a
|
||||
* copy of the License at the following location:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.jasig.cas.client.tomcat.v8;
|
||||
|
||||
import java.io.IOException;
|
||||
import javax.servlet.ServletException;
|
||||
import org.apache.catalina.connector.Request;
|
||||
import org.apache.catalina.connector.Response;
|
||||
import org.apache.catalina.valves.ValveBase;
|
||||
import org.jasig.cas.client.tomcat.LogoutHandler;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Abstract base class for Container-managed log out. Removes the attributes
|
||||
* from the session.
|
||||
*
|
||||
* @author Scott Battaglia
|
||||
* @author Marvin S. Addison
|
||||
* @version $Revision$ $Date$
|
||||
* @since 3.1.12
|
||||
*/
|
||||
public abstract class AbstractLogoutValve extends ValveBase {
|
||||
|
||||
protected final Logger logger = LoggerFactory.getLogger(getClass());
|
||||
|
||||
public final void invoke(final Request request, final Response response) throws IOException, ServletException {
|
||||
if (getLogoutHandler().isLogoutRequest(request)) {
|
||||
getLogoutHandler().logout(request, response);
|
||||
// Do not proceed up valve chain
|
||||
return;
|
||||
}
|
||||
|
||||
logger.debug("URI is not a logout request: {}", request.getRequestURI());
|
||||
getNext().invoke(request, response);
|
||||
}
|
||||
|
||||
protected abstract LogoutHandler getLogoutHandler();
|
||||
}
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* Licensed to Jasig under one or more contributor license
|
||||
* agreements. See the NOTICE file distributed with this work
|
||||
* for additional information regarding copyright ownership.
|
||||
* Jasig licenses this file to you under the Apache License,
|
||||
* Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a
|
||||
* copy of the License at the following location:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.jasig.cas.client.tomcat.v8;
|
||||
|
||||
import org.jasig.cas.client.tomcat.AssertionCasRealmDelegate;
|
||||
import org.jasig.cas.client.tomcat.CasRealm;
|
||||
|
||||
/**
|
||||
* Tomcat <code>Realm</code> that implements {@link CasRealm} for principal and
|
||||
* role data backed by the CAS {@link org.jasig.cas.client.validation.Assertion}.
|
||||
* <p>
|
||||
* Authentication always succeeds and simply returns the given principal.
|
||||
*
|
||||
* @author Marvin S. Addison
|
||||
* @version $Revision$
|
||||
*
|
||||
*/
|
||||
public class AssertionCasRealm extends AbstractCasRealm {
|
||||
|
||||
private final AssertionCasRealmDelegate delegate = new AssertionCasRealmDelegate();
|
||||
|
||||
/**
|
||||
* @param name Name of the attribute in the principal that contains role data.
|
||||
*/
|
||||
public void setRoleAttributeName(final String name) {
|
||||
delegate.setRoleAttributeName(name);
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
protected CasRealm getDelegate() {
|
||||
return delegate;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* Licensed to Jasig under one or more contributor license
|
||||
* agreements. See the NOTICE file distributed with this work
|
||||
* for additional information regarding copyright ownership.
|
||||
* Jasig licenses this file to you under the Apache License,
|
||||
* Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a
|
||||
* copy of the License at the following location:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.jasig.cas.client.tomcat.v8;
|
||||
|
||||
import org.apache.catalina.LifecycleException;
|
||||
import org.jasig.cas.client.validation.Cas10TicketValidator;
|
||||
import org.jasig.cas.client.validation.TicketValidator;
|
||||
|
||||
/**
|
||||
* Authenticator that handles CAS 1.0 protocol.
|
||||
*
|
||||
* @author Scott Battaglia
|
||||
* @version $Revision$ $Date$
|
||||
* @since 3.1.12
|
||||
*/
|
||||
public final class Cas10CasAuthenticator extends AbstractCasAuthenticator {
|
||||
|
||||
public static final String AUTH_METHOD = "CAS10";
|
||||
|
||||
private static final String NAME = Cas10CasAuthenticator.class.getName();
|
||||
|
||||
private Cas10TicketValidator ticketValidator;
|
||||
|
||||
protected TicketValidator getTicketValidator() {
|
||||
return this.ticketValidator;
|
||||
}
|
||||
|
||||
protected String getAuthenticationMethod() {
|
||||
return AUTH_METHOD;
|
||||
}
|
||||
|
||||
protected String getName() {
|
||||
return NAME;
|
||||
}
|
||||
|
||||
protected void startInternal() throws LifecycleException {
|
||||
super.startInternal();
|
||||
this.ticketValidator = new Cas10TicketValidator(getCasServerUrlPrefix());
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* Licensed to Jasig under one or more contributor license
|
||||
* agreements. See the NOTICE file distributed with this work
|
||||
* for additional information regarding copyright ownership.
|
||||
* Jasig licenses this file to you under the Apache License,
|
||||
* Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a
|
||||
* copy of the License at the following location:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.jasig.cas.client.tomcat.v8;
|
||||
|
||||
import org.apache.catalina.LifecycleException;
|
||||
import org.jasig.cas.client.validation.Cas20ServiceTicketValidator;
|
||||
import org.jasig.cas.client.validation.TicketValidator;
|
||||
|
||||
/**
|
||||
* Authenticator that handles the CAS 2.0 protocol.
|
||||
*
|
||||
* @author Scott Battaglia
|
||||
* @version $Revision$ $Date$
|
||||
* @since 3.1.12
|
||||
*/
|
||||
public final class Cas20CasAuthenticator extends AbstractCasAuthenticator {
|
||||
|
||||
public static final String AUTH_METHOD = "CAS20";
|
||||
|
||||
private static final String NAME = Cas20CasAuthenticator.class.getName();
|
||||
|
||||
private Cas20ServiceTicketValidator ticketValidator;
|
||||
|
||||
protected TicketValidator getTicketValidator() {
|
||||
return this.ticketValidator;
|
||||
}
|
||||
|
||||
protected String getAuthenticationMethod() {
|
||||
return AUTH_METHOD;
|
||||
}
|
||||
|
||||
protected String getName() {
|
||||
return NAME;
|
||||
}
|
||||
|
||||
protected void startInternal() throws LifecycleException {
|
||||
super.startInternal();
|
||||
this.ticketValidator = new Cas20ServiceTicketValidator(getCasServerUrlPrefix());
|
||||
if (getEncoding() != null) {
|
||||
this.ticketValidator.setEncoding(getEncoding());
|
||||
}
|
||||
this.ticketValidator.setProxyCallbackUrl(getProxyCallbackUrl());
|
||||
this.ticketValidator.setProxyGrantingTicketStorage(ProxyCallbackValve.getProxyGrantingTicketStorage());
|
||||
this.ticketValidator.setRenew(isRenew());
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,77 @@
|
|||
/*
|
||||
* Licensed to Jasig under one or more contributor license
|
||||
* agreements. See the NOTICE file distributed with this work
|
||||
* for additional information regarding copyright ownership.
|
||||
* Jasig licenses this file to you under the Apache License,
|
||||
* Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a
|
||||
* copy of the License at the following location:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.jasig.cas.client.tomcat.v8;
|
||||
|
||||
import org.apache.catalina.LifecycleException;
|
||||
import org.jasig.cas.client.util.CommonUtils;
|
||||
import org.jasig.cas.client.validation.Cas20ProxyTicketValidator;
|
||||
import org.jasig.cas.client.validation.TicketValidator;
|
||||
|
||||
/**
|
||||
* Authenticator that handles the CAS 2.0 protocol with proxying support.
|
||||
*
|
||||
* @author Scott Battaglia
|
||||
* @version $Revision$ $Date$
|
||||
* @since 3.1.12
|
||||
*/
|
||||
public final class Cas20ProxyCasAuthenticator extends AbstractCasAuthenticator {
|
||||
|
||||
public static final String AUTH_METHOD = "CAS20-PROXY";
|
||||
|
||||
private static final String NAME = Cas20ProxyCasAuthenticator.class.getName();
|
||||
|
||||
private Cas20ProxyTicketValidator ticketValidator;
|
||||
|
||||
private boolean acceptAnyProxy;
|
||||
|
||||
private String allowedProxyChains;
|
||||
|
||||
public void setAcceptAnyProxy(final boolean acceptAnyProxy) {
|
||||
this.acceptAnyProxy = acceptAnyProxy;
|
||||
}
|
||||
|
||||
public void setAllowedProxyChains(final String allowedProxyChains) {
|
||||
this.allowedProxyChains = allowedProxyChains;
|
||||
}
|
||||
|
||||
protected TicketValidator getTicketValidator() {
|
||||
return this.ticketValidator;
|
||||
}
|
||||
|
||||
protected String getAuthenticationMethod() {
|
||||
return AUTH_METHOD;
|
||||
}
|
||||
|
||||
protected String getName() {
|
||||
return NAME;
|
||||
}
|
||||
|
||||
protected void startInternal() throws LifecycleException {
|
||||
super.startInternal();
|
||||
this.ticketValidator = new Cas20ProxyTicketValidator(getCasServerUrlPrefix());
|
||||
this.ticketValidator.setRenew(isRenew());
|
||||
this.ticketValidator.setProxyCallbackUrl(getProxyCallbackUrl());
|
||||
this.ticketValidator.setProxyGrantingTicketStorage(ProxyCallbackValve.getProxyGrantingTicketStorage());
|
||||
this.ticketValidator.setAcceptAnyProxy(this.acceptAnyProxy);
|
||||
this.ticketValidator.setAllowedProxyChains(CommonUtils.createProxyList(this.allowedProxyChains));
|
||||
if (getEncoding() != null) {
|
||||
this.ticketValidator.setEncoding(getEncoding());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
* Licensed to Jasig under one or more contributor license
|
||||
* agreements. See the NOTICE file distributed with this work
|
||||
* for additional information regarding copyright ownership.
|
||||
* Jasig licenses this file to you under the Apache License,
|
||||
* Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a
|
||||
* copy of the License at the following location:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.jasig.cas.client.tomcat.v8;
|
||||
|
||||
import org.apache.catalina.LifecycleException;
|
||||
import org.jasig.cas.client.tomcat.CasRealm;
|
||||
import org.jasig.cas.client.tomcat.PropertiesCasRealmDelegate;
|
||||
|
||||
/**
|
||||
* Tomcat <code>Realm</code> that implements {@link CasRealm} backed by properties file
|
||||
* containing usernames/and roles of the following format:
|
||||
* <pre>
|
||||
* username1=role1,role2,role3
|
||||
* username2=role1
|
||||
* username3=role2,role3
|
||||
* </pre>
|
||||
* User authentication succeeds if the name of the given principal exists as
|
||||
* a username in the properties file.
|
||||
*
|
||||
* @author Marvin S. Addison
|
||||
* @version $Revision$
|
||||
* @since 3.1.12
|
||||
*
|
||||
*/
|
||||
public class PropertiesCasRealm extends AbstractCasRealm {
|
||||
|
||||
private final PropertiesCasRealmDelegate delegate = new PropertiesCasRealmDelegate();
|
||||
|
||||
/**
|
||||
* @param path Path to properties file container username/role data.
|
||||
*/
|
||||
public void setPropertiesFilePath(final String path) {
|
||||
this.delegate.setPropertiesFilePath(path);
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
protected void startInternal() throws LifecycleException {
|
||||
super.startInternal();
|
||||
this.delegate.readProperties();
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
protected CasRealm getDelegate() {
|
||||
return this.delegate;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,90 @@
|
|||
/*
|
||||
* Licensed to Jasig under one or more contributor license
|
||||
* agreements. See the NOTICE file distributed with this work
|
||||
* for additional information regarding copyright ownership.
|
||||
* Jasig licenses this file to you under the Apache License,
|
||||
* Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a
|
||||
* copy of the License at the following location:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.jasig.cas.client.tomcat.v8;
|
||||
|
||||
import java.io.IOException;
|
||||
import javax.servlet.ServletException;
|
||||
import org.apache.catalina.LifecycleException;
|
||||
import org.apache.catalina.connector.Request;
|
||||
import org.apache.catalina.connector.Response;
|
||||
import org.apache.catalina.valves.ValveBase;
|
||||
import org.jasig.cas.client.proxy.ProxyGrantingTicketStorage;
|
||||
import org.jasig.cas.client.util.CommonUtils;
|
||||
import org.jasig.cas.client.util.ReflectUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Handles watching a url for the proxy callback.
|
||||
* <p>
|
||||
* Because its tough to share state between valves, we expose the storage mechanism via a static variable.
|
||||
* <p>
|
||||
* This valve should be ordered before the authentication valves.
|
||||
*
|
||||
* @author Scott Battaglia
|
||||
* @version $Revision$ $Date$
|
||||
* @since 3.1.12
|
||||
*/
|
||||
public final class ProxyCallbackValve extends ValveBase {
|
||||
|
||||
private static ProxyGrantingTicketStorage PROXY_GRANTING_TICKET_STORAGE;
|
||||
|
||||
/** Logger instance */
|
||||
private final Logger logger = LoggerFactory.getLogger(getClass());
|
||||
|
||||
private String proxyGrantingTicketStorageClass;
|
||||
|
||||
private String proxyCallbackUrl;
|
||||
|
||||
public static ProxyGrantingTicketStorage getProxyGrantingTicketStorage() {
|
||||
return PROXY_GRANTING_TICKET_STORAGE;
|
||||
}
|
||||
|
||||
public void setProxyGrantingTicketStorageClass(final String proxyGrantingTicketStorageClass) {
|
||||
this.proxyGrantingTicketStorageClass = proxyGrantingTicketStorageClass;
|
||||
}
|
||||
|
||||
public void setProxyCallbackUrl(final String proxyCallbackUrl) {
|
||||
this.proxyCallbackUrl = proxyCallbackUrl;
|
||||
}
|
||||
|
||||
protected void startInternal() throws LifecycleException {
|
||||
super.startInternal();
|
||||
|
||||
try {
|
||||
CommonUtils.assertNotNull(this.proxyCallbackUrl, "the proxy callback url cannot be null");
|
||||
CommonUtils.assertTrue(this.proxyCallbackUrl.startsWith("/"), "proxy callback url must start with \"/\"");
|
||||
|
||||
PROXY_GRANTING_TICKET_STORAGE = ReflectUtils.newInstance(proxyGrantingTicketStorageClass);
|
||||
} catch (final Exception e) {
|
||||
throw new LifecycleException(e);
|
||||
}
|
||||
logger.info("Startup completed.");
|
||||
}
|
||||
|
||||
public void invoke(final Request request, final Response response) throws IOException, ServletException {
|
||||
if (this.proxyCallbackUrl.equals(request.getRequestURI())) {
|
||||
logger.debug("Processing proxy callback request.");
|
||||
CommonUtils.readAndRespondToProxyReceptorRequest(request, response, PROXY_GRANTING_TICKET_STORAGE);
|
||||
return;
|
||||
}
|
||||
|
||||
getNext().invoke(request, response);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* Licensed to Jasig under one or more contributor license
|
||||
* agreements. See the NOTICE file distributed with this work
|
||||
* for additional information regarding copyright ownership.
|
||||
* Jasig licenses this file to you under the Apache License,
|
||||
* Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a
|
||||
* copy of the License at the following location:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.jasig.cas.client.tomcat.v8;
|
||||
|
||||
import org.apache.catalina.LifecycleException;
|
||||
import org.jasig.cas.client.tomcat.LogoutHandler;
|
||||
import org.jasig.cas.client.tomcat.RegexUriLogoutHandler;
|
||||
|
||||
/**
|
||||
* Performs CAS logout when the request URI matches a regular expression.
|
||||
*
|
||||
* @author Scott Battaglia
|
||||
* @author Marvin S. Addison
|
||||
* @version $Revision$ $Date$
|
||||
* @since 3.1.12
|
||||
*/
|
||||
public final class RegexUriLogoutValve extends AbstractLogoutValve {
|
||||
|
||||
private RegexUriLogoutHandler logoutHandler = new RegexUriLogoutHandler();
|
||||
|
||||
public void setRedirectUrl(final String redirectUrl) {
|
||||
this.logoutHandler.setRedirectUrl(redirectUrl);
|
||||
}
|
||||
|
||||
public void setLogoutUriRegex(final String regex) {
|
||||
this.logoutHandler.setLogoutUriRegex(regex);
|
||||
}
|
||||
|
||||
protected void startInternal() throws LifecycleException {
|
||||
super.startInternal();
|
||||
this.logoutHandler.init();
|
||||
logger.info("Startup completed.");
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
protected LogoutHandler getLogoutHandler() {
|
||||
return this.logoutHandler;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,84 @@
|
|||
/*
|
||||
* Licensed to Jasig under one or more contributor license
|
||||
* agreements. See the NOTICE file distributed with this work
|
||||
* for additional information regarding copyright ownership.
|
||||
* Jasig licenses this file to you under the Apache License,
|
||||
* Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a
|
||||
* copy of the License at the following location:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.jasig.cas.client.tomcat.v8;
|
||||
|
||||
import org.apache.catalina.LifecycleException;
|
||||
import org.jasig.cas.client.validation.Saml11TicketValidator;
|
||||
import org.jasig.cas.client.validation.TicketValidator;
|
||||
|
||||
/**
|
||||
* CAS authenticator that uses the SAML 1.1 protocol.
|
||||
*
|
||||
* @author Marvin S. Addison
|
||||
* @version $Revision$
|
||||
* @since 3.1.12
|
||||
*
|
||||
*/
|
||||
public final class Saml11Authenticator extends AbstractAuthenticator {
|
||||
|
||||
public static final String AUTH_METHOD = "SAML11";
|
||||
|
||||
private static final String NAME = Saml11Authenticator.class.getName();
|
||||
|
||||
private Saml11TicketValidator ticketValidator;
|
||||
|
||||
/** SAML protocol clock drift tolerance in ms */
|
||||
private int tolerance = -1;
|
||||
|
||||
/**
|
||||
* @param ms SAML clock drift tolerance in milliseconds.
|
||||
*/
|
||||
public void setTolerance(final int ms) {
|
||||
this.tolerance = ms;
|
||||
}
|
||||
|
||||
protected void startInternal() throws LifecycleException {
|
||||
super.startInternal();
|
||||
this.ticketValidator = new Saml11TicketValidator(getCasServerUrlPrefix());
|
||||
if (this.tolerance > -1) {
|
||||
this.ticketValidator.setTolerance(this.tolerance);
|
||||
}
|
||||
if (getEncoding() != null) {
|
||||
this.ticketValidator.setEncoding(getEncoding());
|
||||
}
|
||||
this.ticketValidator.setRenew(isRenew());
|
||||
}
|
||||
|
||||
protected TicketValidator getTicketValidator() {
|
||||
return this.ticketValidator;
|
||||
}
|
||||
|
||||
protected String getAuthenticationMethod() {
|
||||
return AUTH_METHOD;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
protected String getArtifactParameterName() {
|
||||
return "SAMLart";
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
protected String getServiceParameterName() {
|
||||
return "TARGET";
|
||||
}
|
||||
|
||||
protected String getName() {
|
||||
return NAME;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,93 @@
|
|||
/*
|
||||
* Licensed to Jasig under one or more contributor license
|
||||
* agreements. See the NOTICE file distributed with this work
|
||||
* for additional information regarding copyright ownership.
|
||||
* Jasig licenses this file to you under the Apache License,
|
||||
* Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a
|
||||
* copy of the License at the following location:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.jasig.cas.client.tomcat.v8;
|
||||
|
||||
import java.io.IOException;
|
||||
import javax.servlet.ServletException;
|
||||
import org.apache.catalina.LifecycleException;
|
||||
import org.apache.catalina.Session;
|
||||
import org.apache.catalina.SessionEvent;
|
||||
import org.apache.catalina.SessionListener;
|
||||
import org.apache.catalina.connector.Request;
|
||||
import org.apache.catalina.connector.Response;
|
||||
import org.apache.catalina.valves.ValveBase;
|
||||
import org.jasig.cas.client.session.SessionMappingStorage;
|
||||
import org.jasig.cas.client.session.SingleSignOutHandler;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Handles logout request messages sent from the CAS server by ending the current
|
||||
* HTTP session.
|
||||
*
|
||||
* @author Marvin S. Addison
|
||||
* @version $Revision$ $Date$
|
||||
* @since 3.1.12
|
||||
*
|
||||
*/
|
||||
public class SingleSignOutValve extends ValveBase implements SessionListener {
|
||||
|
||||
/** Logger instance */
|
||||
private final Logger logger = LoggerFactory.getLogger(getClass());
|
||||
|
||||
private final SingleSignOutHandler handler = new SingleSignOutHandler();
|
||||
|
||||
public void setArtifactParameterName(final String name) {
|
||||
this.handler.setArtifactParameterName(name);
|
||||
}
|
||||
|
||||
public void setLogoutParameterName(final String name) {
|
||||
this.handler.setLogoutParameterName(name);
|
||||
}
|
||||
|
||||
public void setRelayStateParameterName(final String name) {
|
||||
this.handler.setRelayStateParameterName(name);
|
||||
}
|
||||
|
||||
public void setCasServerUrlPrefix(final String casServerUrlPrefix) {
|
||||
this.handler.setCasServerUrlPrefix(casServerUrlPrefix);
|
||||
}
|
||||
|
||||
public void setSessionMappingStorage(final SessionMappingStorage storage) {
|
||||
this.handler.setSessionMappingStorage(storage);
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public void invoke(final Request request, final Response response) throws IOException, ServletException {
|
||||
if (this.handler.process(request, response)) {
|
||||
getNext().invoke(request, response);
|
||||
}
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public void sessionEvent(final SessionEvent event) {
|
||||
if (Session.SESSION_DESTROYED_EVENT.equals(event.getType())) {
|
||||
logger.debug("Cleaning up SessionMappingStorage on destroySession event");
|
||||
this.handler.getSessionMappingStorage().removeBySessionById(event.getSession().getId());
|
||||
}
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
protected void startInternal() throws LifecycleException {
|
||||
super.startInternal();
|
||||
logger.info("Starting...");
|
||||
this.handler.init();
|
||||
logger.info("Startup completed.");
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* Licensed to Jasig under one or more contributor license
|
||||
* agreements. See the NOTICE file distributed with this work
|
||||
* for additional information regarding copyright ownership.
|
||||
* Jasig licenses this file to you under the Apache License,
|
||||
* Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a
|
||||
* copy of the License at the following location:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.jasig.cas.client.tomcat.v8;
|
||||
|
||||
import org.apache.catalina.LifecycleException;
|
||||
import org.jasig.cas.client.tomcat.LogoutHandler;
|
||||
import org.jasig.cas.client.tomcat.StaticUriLogoutHandler;
|
||||
|
||||
/**
|
||||
* Monitors a specific request URI for logout requests.
|
||||
*
|
||||
* @author Scott Battaglia
|
||||
* @author Marvin S. Addison
|
||||
* @version $Revision$ $Date$
|
||||
* @since 3.1.12
|
||||
*/
|
||||
public final class StaticUriLogoutValve extends AbstractLogoutValve {
|
||||
|
||||
private StaticUriLogoutHandler logoutHandler = new StaticUriLogoutHandler();
|
||||
|
||||
public void setRedirectUrl(final String redirectUrl) {
|
||||
this.logoutHandler.setRedirectUrl(redirectUrl);
|
||||
}
|
||||
|
||||
public void setLogoutUri(final String logoutUri) {
|
||||
this.logoutHandler.setLogoutUri(logoutUri);
|
||||
}
|
||||
|
||||
protected void startInternal() throws LifecycleException {
|
||||
super.startInternal();
|
||||
this.logoutHandler.init();
|
||||
logger.info("Startup completed.");
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
protected LogoutHandler getLogoutHandler() {
|
||||
return this.logoutHandler;
|
||||
}
|
||||
}
|
||||
|
|
@ -7,7 +7,6 @@
|
|||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>org.jasig.cas.client</groupId>
|
||||
<packaging>jar</packaging>
|
||||
<artifactId>cas-client-support-distributed-memcached</artifactId>
|
||||
<name>Jasig CAS Client for Java - Distributed Proxy Storage Support:
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@
|
|||
<artifactId>cas-client</artifactId>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.jasig.cas.client</groupId>
|
||||
<artifactId>cas-client-support-saml</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<name>Jasig CAS Client for Java - SAML Protocol Support</name>
|
||||
|
|
|
|||
|
|
@ -198,7 +198,6 @@ public final class Saml11TicketValidator extends AbstractUrlBasedTicketValidator
|
|||
conn = this.getURLConnectionFactory().buildHttpURLConnection(validationUrl.openConnection());
|
||||
conn.setRequestMethod("POST");
|
||||
conn.setRequestProperty("Content-Type", "text/xml");
|
||||
conn.setRequestProperty("Content-Length", Integer.toString(request.length()));
|
||||
conn.setRequestProperty("SOAPAction", "http://www.oasis-open.org/committees/security");
|
||||
conn.setUseCaches(false);
|
||||
conn.setDoInput(true);
|
||||
|
|
@ -208,8 +207,6 @@ public final class Saml11TicketValidator extends AbstractUrlBasedTicketValidator
|
|||
final Charset charset = CommonUtils.isNotBlank(getEncoding()) ?
|
||||
Charset.forName(getEncoding()) : IOUtils.UTF8;
|
||||
conn.getOutputStream().write(request.getBytes(charset));
|
||||
conn.getOutputStream().flush();
|
||||
|
||||
return IOUtils.readString(conn.getInputStream(), charset);
|
||||
} catch (final IOException e) {
|
||||
throw new RuntimeException("IO error sending HTTP request to /samlValidate", e);
|
||||
|
|
|
|||
2
pom.xml
2
pom.xml
|
|
@ -252,6 +252,8 @@
|
|||
<module>cas-client-integration-tomcat-common</module>
|
||||
<module>cas-client-integration-tomcat-v6</module>
|
||||
<module>cas-client-integration-tomcat-v7</module>
|
||||
<module>cas-client-integration-tomcat-v8</module>
|
||||
<module>cas-client-integration-jetty</module>
|
||||
</modules>
|
||||
|
||||
<properties>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,23 @@
|
|||
#!/bin/bash
|
||||
#
|
||||
# Licensed to Jasig under one or more contributor license
|
||||
# agreements. See the NOTICE file distributed with this work
|
||||
# for additional information regarding copyright ownership.
|
||||
# Jasig licenses this file to you under the Apache License,
|
||||
# Version 2.0 (the "License"); you may not use this file
|
||||
# except in compliance with the License. You may obtain a
|
||||
# copy of the License at the following location:
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
#
|
||||
|
||||
|
||||
# Only invoke the deployment to Sonatype when it's not a PR and only for master
|
||||
if [ "$TRAVIS_PULL_REQUEST" == "false" ] && [ "$TRAVIS_BRANCH" == "master" ]; then
|
||||
|
|
|
|||
|
|
@ -1,3 +1,23 @@
|
|||
<!--
|
||||
|
||||
Licensed to Jasig under one or more contributor license
|
||||
agreements. See the NOTICE file distributed with this work
|
||||
for additional information regarding copyright ownership.
|
||||
Jasig licenses this file to you under the Apache License,
|
||||
Version 2.0 (the "License"); you may not use this file
|
||||
except in compliance with the License. You may obtain a
|
||||
copy of the License at the following location:
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
|
||||
-->
|
||||
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0
|
||||
|
|
|
|||
Loading…
Reference in New Issue