casc-210: Merge branch 'master' of https://github.com/jasig/java-cas-client into CASC-210
Resolved Conflicts: cas-client-core/src/main/java/org/jasig/cas/client/validation/ProxyList.java
This commit is contained in:
commit
f98e776869
|
|
@ -0,0 +1,24 @@
|
|||
#
|
||||
# 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.
|
||||
#
|
||||
|
||||
before_install:
|
||||
- mvn -v
|
||||
- java -version
|
||||
script: mvn install
|
||||
language: java
|
||||
10
NOTICE
10
NOTICE
|
|
@ -16,21 +16,22 @@ specific language governing permissions and limitations
|
|||
under the License.
|
||||
|
||||
This project includes:
|
||||
"Java Concurrency in Practice" book annotations under Creative Commons Attribution License
|
||||
AOP alliance under Public Domain
|
||||
Apache Log4j under The Apache Software License, Version 2.0
|
||||
Apache Santuario under The Apache Software License, Version 2.0
|
||||
Apache Velocity under The Apache Software License, Version 2.0
|
||||
Apache XML Security under The Apache Software License, Version 2.0
|
||||
Atlassian JIRA - Code - Core under Atlassian End User License
|
||||
Atlassian Seraph under BSD License
|
||||
atlassian-osuser under BSD License
|
||||
Bouncy Castle Provider under Bouncy Castle Licence
|
||||
catalina under Apache License, Version 2.0
|
||||
Codec under The Apache Software License, Version 2.0
|
||||
com.atlassian.confluence:confluence under Atlassian End User License
|
||||
com.atlassian.event:atlassian-event under Atlassian End User License
|
||||
com.atlassian.jira:jira-core under Atlassian End User License
|
||||
com.atlassian.osuser:atlassian-osuser under Atlassian End User License
|
||||
com.atlassian.seraph:atlassian-seraph under Atlassian End User License
|
||||
Commons Codec under The Apache Software License, Version 2.0
|
||||
commons-collections under Apache License, Version 2.0
|
||||
Confluence Core under Atlassian End User License
|
||||
Ehcache Core under The Apache Software License, Version 2.0
|
||||
ESAPI 2.0 under BSD or Creative Commons 3.0 BY-SA
|
||||
Google Collections Library under The Apache Software License, Version 2.0
|
||||
|
|
@ -49,7 +50,6 @@ This project includes:
|
|||
JavaBeans Activation Framework (JAF) under Common Development and Distribution License (CDDL) v1.0
|
||||
JavaMail API under Common Development and Distribution License (CDDL) v1.0
|
||||
JBoss Application Server Tomcat under lgpl
|
||||
jcip-annotations under Creative Commons Attribution License
|
||||
JCL 1.1.1 implemented over SLF4J under MIT License
|
||||
Joda time under Apache 2
|
||||
JUL to SLF4J bridge under MIT License
|
||||
|
|
|
|||
|
|
@ -1,6 +0,0 @@
|
|||
BUILDING THE CAS CLIENT FOR JAVA
|
||||
|
||||
Please note that to be deployed in Maven Central, we mark a number of JARs as provided (related to JBoss and Memcache
|
||||
Clients). In order to build the clients, you must enable the commented out repositories in the appropriate pom.xml
|
||||
files in the modules (cas-client-integration-jboss and cas-client-support-distributed-memcached) or follow the
|
||||
instructions on how to install the file manually.
|
||||
|
|
@ -16,6 +16,7 @@ specific language governing permissions and limitations
|
|||
under the License.
|
||||
|
||||
This project includes:
|
||||
"Java Concurrency in Practice" book annotations under Creative Commons Attribution License
|
||||
AOP alliance under Public Domain
|
||||
Apache Log4j under The Apache Software License, Version 2.0
|
||||
Apache Santuario under The Apache Software License, Version 2.0
|
||||
|
|
@ -30,7 +31,6 @@ This project includes:
|
|||
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
|
||||
jcip-annotations under Creative Commons Attribution License
|
||||
JCL 1.1.1 implemented over SLF4J under MIT License
|
||||
Joda time under Apache 2
|
||||
JUL to SLF4J bridge under MIT License
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<parent>
|
||||
<groupId>org.jasig.cas.client</groupId>
|
||||
<version>3.3.2-SNAPSHOT</version>
|
||||
<version>3.4.0-SNAPSHOT</version>
|
||||
<artifactId>cas-client</artifactId>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
|
@ -10,7 +10,30 @@
|
|||
<packaging>jar</packaging>
|
||||
<name>Jasig CAS Client for Java - Core</name>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<version>2.6</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>test-jar</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
<version>3.4</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>xml-security</groupId>
|
||||
<artifactId>xmlsec</artifactId>
|
||||
|
|
@ -19,20 +42,6 @@
|
|||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.opensaml</groupId>
|
||||
<artifactId>opensaml</artifactId>
|
||||
<version>${opensaml.version}</version>
|
||||
<type>jar</type>
|
||||
<scope>compile</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>jcl-over-slf4j</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>commons-codec</groupId>
|
||||
<artifactId>commons-codec</artifactId>
|
||||
|
|
@ -51,27 +60,18 @@
|
|||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-test</artifactId>
|
||||
<version>${spring.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-core</artifactId>
|
||||
<version>${spring.version}</version>
|
||||
<scope>test</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<artifactId>commons-logging</artifactId>
|
||||
<groupId>commons-logging</groupId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-context</artifactId>
|
||||
<version>${spring.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
|
|
@ -97,8 +97,4 @@
|
|||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<properties>
|
||||
<spring.version>3.1.3.RELEASE</spring.version>
|
||||
<opensaml.version>2.5.1-1</opensaml.version>
|
||||
</properties>
|
||||
</project>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* Simple enumeration to hold/capture some of the standard request parameters used by the various protocols.
|
||||
*
|
||||
* @author Scott Battaglia
|
||||
* @since 3.4.0
|
||||
*/
|
||||
public enum Protocol {
|
||||
|
||||
CAS1("ticket", "service"), CAS2(CAS1), CAS3(CAS2), SAML11("SAMLart", "TARGET");
|
||||
|
||||
private final String artifactParameterName;
|
||||
|
||||
private final String serviceParameterName;
|
||||
|
||||
private Protocol(final String artifactParameterName, final String serviceParameterName) {
|
||||
this.artifactParameterName = artifactParameterName;
|
||||
this.serviceParameterName = serviceParameterName;
|
||||
}
|
||||
|
||||
private Protocol(final Protocol protocol) {
|
||||
this(protocol.getArtifactParameterName(), protocol.getServiceParameterName());
|
||||
}
|
||||
|
||||
public String getArtifactParameterName() {
|
||||
return this.artifactParameterName;
|
||||
}
|
||||
|
||||
public String getServiceParameterName() {
|
||||
return this.serviceParameterName;
|
||||
}
|
||||
}
|
||||
|
|
@ -27,6 +27,8 @@ import javax.servlet.http.HttpServletRequest;
|
|||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.http.HttpSession;
|
||||
|
||||
import org.jasig.cas.client.Protocol;
|
||||
import org.jasig.cas.client.configuration.ConfigurationKeys;
|
||||
import org.jasig.cas.client.util.AbstractCasFilter;
|
||||
import org.jasig.cas.client.util.CommonUtils;
|
||||
import org.jasig.cas.client.util.ReflectUtils;
|
||||
|
|
@ -79,22 +81,24 @@ public class AuthenticationFilter extends AbstractCasFilter {
|
|||
PATTERN_MATCHER_TYPES.put("REGEX", RegexUrlPatternMatcherStrategy.class);
|
||||
PATTERN_MATCHER_TYPES.put("EXACT", ExactUrlPatternMatcherStrategy.class);
|
||||
}
|
||||
|
||||
public AuthenticationFilter() {
|
||||
this(Protocol.CAS2);
|
||||
}
|
||||
|
||||
protected AuthenticationFilter(final Protocol protocol) {
|
||||
super(protocol);
|
||||
}
|
||||
|
||||
protected void initInternal(final FilterConfig filterConfig) throws ServletException {
|
||||
if (!isIgnoreInitConfiguration()) {
|
||||
super.initInternal(filterConfig);
|
||||
setCasServerLoginUrl(getPropertyFromInitParams(filterConfig, "casServerLoginUrl", null));
|
||||
logger.trace("Loaded CasServerLoginUrl parameter: {}", this.casServerLoginUrl);
|
||||
setRenew(parseBoolean(getPropertyFromInitParams(filterConfig, "renew", "false")));
|
||||
logger.trace("Loaded renew parameter: {}", this.renew);
|
||||
setGateway(parseBoolean(getPropertyFromInitParams(filterConfig, "gateway", "false")));
|
||||
logger.trace("Loaded gateway parameter: {}", this.gateway);
|
||||
setCasServerLoginUrl(getString(ConfigurationKeys.CAS_SERVER_LOGIN_URL));
|
||||
setRenew(getBoolean(ConfigurationKeys.RENEW));
|
||||
setGateway(getBoolean(ConfigurationKeys.GATEWAY));
|
||||
|
||||
final String ignorePattern = getPropertyFromInitParams(filterConfig, "ignorePattern", null);
|
||||
logger.trace("Loaded ignorePattern parameter: {}", ignorePattern);
|
||||
|
||||
final String ignoreUrlPatternType = getPropertyFromInitParams(filterConfig, "ignoreUrlPatternType", "REGEX");
|
||||
logger.trace("Loaded ignoreUrlPatternType parameter: {}", ignoreUrlPatternType);
|
||||
final String ignorePattern = getString(ConfigurationKeys.IGNORE_PATTERN);
|
||||
final String ignoreUrlPatternType = getString(ConfigurationKeys.IGNORE_URL_PATTERN_TYPE);
|
||||
|
||||
if (ignorePattern != null) {
|
||||
final Class<? extends UrlPatternMatcherStrategy> ignoreUrlMatcherClass = PATTERN_MATCHER_TYPES.get(ignoreUrlPatternType);
|
||||
|
|
@ -113,14 +117,13 @@ public class AuthenticationFilter extends AbstractCasFilter {
|
|||
}
|
||||
}
|
||||
|
||||
final String gatewayStorageClass = getPropertyFromInitParams(filterConfig, "gatewayStorageClass", null);
|
||||
final Class<? extends GatewayResolver> gatewayStorageClass = getClass(ConfigurationKeys.GATEWAY_STORAGE_CLASS);
|
||||
|
||||
if (gatewayStorageClass != null) {
|
||||
this.gatewayStorage = ReflectUtils.newInstance(gatewayStorageClass);
|
||||
setGatewayStorage(ReflectUtils.newInstance(gatewayStorageClass));
|
||||
}
|
||||
|
||||
final String authenticationRedirectStrategyClass = getPropertyFromInitParams(filterConfig,
|
||||
"authenticationRedirectStrategyClass", null);
|
||||
final Class<? extends AuthenticationRedirectStrategy> authenticationRedirectStrategyClass = getClass(ConfigurationKeys.AUTHENTICATION_REDIRECT_STRATEGY_CLASS);
|
||||
|
||||
if (authenticationRedirectStrategyClass != null) {
|
||||
this.authenticationRedirectStrategy = ReflectUtils.newInstance(authenticationRedirectStrategyClass);
|
||||
|
|
@ -175,7 +178,7 @@ public class AuthenticationFilter extends AbstractCasFilter {
|
|||
logger.debug("Constructed service url: {}", modifiedServiceUrl);
|
||||
|
||||
final String urlToRedirectTo = CommonUtils.constructRedirectUrl(this.casServerLoginUrl,
|
||||
getServiceParameterName(), modifiedServiceUrl, this.renew, this.gateway);
|
||||
getProtocol().getServiceParameterName(), modifiedServiceUrl, this.renew, this.gateway);
|
||||
|
||||
logger.debug("redirecting to \"{}\"", urlToRedirectTo);
|
||||
this.authenticationRedirectStrategy.redirect(request, response, urlToRedirectTo);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,113 @@
|
|||
/*
|
||||
* 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.configuration;
|
||||
|
||||
import org.apache.commons.lang3.BooleanUtils;
|
||||
import org.apache.commons.lang3.math.NumberUtils;
|
||||
import org.jasig.cas.client.util.CommonUtils;
|
||||
import org.jasig.cas.client.util.ReflectUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Base class to provide most of the boiler-plate code (i.e. checking for proper values, returning defaults, etc.
|
||||
*
|
||||
* @author Scott Battaglia
|
||||
* @since 3.4.0
|
||||
*/
|
||||
public abstract class BaseConfigurationStrategy implements ConfigurationStrategy {
|
||||
|
||||
protected final Logger logger = LoggerFactory.getLogger(getClass());
|
||||
|
||||
public final boolean getBoolean(final ConfigurationKey<Boolean> configurationKey) {
|
||||
return getValue(configurationKey, new Parser<Boolean>() {
|
||||
public Boolean parse(final String value) {
|
||||
return BooleanUtils.toBoolean(value);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public final long getLong(final ConfigurationKey<Long> configurationKey) {
|
||||
return getValue(configurationKey, new Parser<Long>() {
|
||||
public Long parse(final String value) {
|
||||
return NumberUtils.toLong(value, configurationKey.getDefaultValue());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public final int getInt(final ConfigurationKey<Integer> configurationKey) {
|
||||
return getValue(configurationKey, new Parser<Integer>() {
|
||||
public Integer parse(final String value) {
|
||||
return NumberUtils.toInt(value, configurationKey.getDefaultValue());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public final String getString(final ConfigurationKey<String> configurationKey) {
|
||||
return getValue(configurationKey, new Parser<String>() {
|
||||
public String parse(final String value) {
|
||||
return value;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public <T> Class<? extends T> getClass(final ConfigurationKey<Class<? extends T>> configurationKey) {
|
||||
return getValue(configurationKey, new Parser<Class<? extends T>>() {
|
||||
public Class<? extends T> parse(final String value) {
|
||||
try {
|
||||
return ReflectUtils.loadClass(value);
|
||||
} catch (final IllegalArgumentException e) {
|
||||
return configurationKey.getDefaultValue();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private <T> T getValue(final ConfigurationKey<T> configurationKey, final Parser<T> parser) {
|
||||
final String value = getWithCheck(configurationKey);
|
||||
|
||||
if (CommonUtils.isBlank(value)) {
|
||||
logger.trace("No value found for property {}, returning default {}", configurationKey.getName(), configurationKey.getDefaultValue());
|
||||
return configurationKey.getDefaultValue();
|
||||
} else {
|
||||
logger.trace("Loaded property {} with value {}", configurationKey.getName(), configurationKey.getDefaultValue());
|
||||
}
|
||||
|
||||
return parser.parse(value);
|
||||
}
|
||||
|
||||
private String getWithCheck(final ConfigurationKey configurationKey) {
|
||||
CommonUtils.assertNotNull(configurationKey, "configurationKey cannot be null");
|
||||
|
||||
return get(configurationKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the String value for this key. Returns null if there is no value.
|
||||
*
|
||||
* @param configurationKey the key to retrieve. MUST NOT BE NULL.
|
||||
* @return the String if its found, null otherwise.
|
||||
*/
|
||||
protected abstract String get(ConfigurationKey configurationKey);
|
||||
|
||||
private interface Parser<T> {
|
||||
|
||||
T parse(String value);
|
||||
}
|
||||
}
|
||||
|
|
@ -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.configuration;
|
||||
|
||||
import org.jasig.cas.client.util.CommonUtils;
|
||||
|
||||
/**
|
||||
* Holder class to represent a particular configuration key and its optional default value.
|
||||
*
|
||||
* @author Scott Battaglia
|
||||
* @since 3.4.0
|
||||
*/
|
||||
public final class ConfigurationKey<E> {
|
||||
|
||||
private final String name;
|
||||
|
||||
private final E defaultValue;
|
||||
|
||||
public ConfigurationKey(final String name) {
|
||||
this(name, null);
|
||||
}
|
||||
|
||||
public ConfigurationKey(final String name, final E defaultValue) {
|
||||
CommonUtils.assertNotNull(name, "name must not be null.");
|
||||
this.name = name;
|
||||
this.defaultValue = defaultValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* The referencing name of the configuration key (i.e. what you would use to look it up in your configuration strategy)
|
||||
*
|
||||
* @return the name. MUST NOT BE NULL.
|
||||
*/
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The (optional) default value to use when this configuration key is not set. If a value is provided it should be used. A <code>null</code> value indicates that there is no default.
|
||||
*
|
||||
* @return the default value or null.
|
||||
*/
|
||||
public E getDefaultValue() {
|
||||
return this.defaultValue;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,82 @@
|
|||
/*
|
||||
* 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.configuration;
|
||||
|
||||
import org.jasig.cas.client.Protocol;
|
||||
import org.jasig.cas.client.authentication.AuthenticationRedirectStrategy;
|
||||
import org.jasig.cas.client.authentication.DefaultGatewayResolverImpl;
|
||||
import org.jasig.cas.client.authentication.GatewayResolver;
|
||||
import org.jasig.cas.client.proxy.ProxyGrantingTicketStorage;
|
||||
import org.jasig.cas.client.proxy.ProxyGrantingTicketStorageImpl;
|
||||
import org.jasig.cas.client.validation.Cas20ServiceTicketValidator;
|
||||
|
||||
import javax.net.ssl.HostnameVerifier;
|
||||
|
||||
/**
|
||||
* Holder interface for all known configuration keys.
|
||||
*
|
||||
* @author Scott Battaglia
|
||||
* @since 3.4.0
|
||||
*/
|
||||
public interface ConfigurationKeys {
|
||||
|
||||
ConfigurationKey<String> ARTIFACT_PARAMETER_NAME = new ConfigurationKey<String>("artifactParameterName", Protocol.CAS2.getArtifactParameterName());
|
||||
ConfigurationKey<String> SERVER_NAME = new ConfigurationKey<String>("serverName", null);
|
||||
ConfigurationKey<String> SERVICE = new ConfigurationKey<String>("service");
|
||||
ConfigurationKey<Boolean> RENEW = new ConfigurationKey<Boolean>("renew", Boolean.FALSE);
|
||||
ConfigurationKey<String> LOGOUT_PARAMETER_NAME = new ConfigurationKey<String>("logoutParameterName", "logoutRequest");
|
||||
ConfigurationKey<Boolean> ARTIFACT_PARAMETER_OVER_POST = new ConfigurationKey<Boolean>("artifactParameterOverPost", Boolean.FALSE);
|
||||
ConfigurationKey<Boolean> EAGERLY_CREATE_SESSIONS = new ConfigurationKey<Boolean>("eagerlyCreateSessions", Boolean.TRUE);
|
||||
ConfigurationKey<Boolean> ENCODE_SERVICE_URL = new ConfigurationKey<Boolean>("encodeServiceUrl", Boolean.TRUE);
|
||||
ConfigurationKey<String> SSL_CONFIG_FILE = new ConfigurationKey<String>("sslConfigFile", null);
|
||||
ConfigurationKey<String> ROLE_ATTRIBUTE = new ConfigurationKey<String>("roleAttribute", null);
|
||||
ConfigurationKey<Boolean> IGNORE_CASE = new ConfigurationKey<Boolean>("ignoreCase", Boolean.FALSE);
|
||||
ConfigurationKey<String> CAS_SERVER_LOGIN_URL = new ConfigurationKey<String>("casServerLoginUrl", null);
|
||||
ConfigurationKey<Boolean> GATEWAY = new ConfigurationKey<Boolean>("gateway", Boolean.FALSE);
|
||||
ConfigurationKey<Class<? extends AuthenticationRedirectStrategy>> AUTHENTICATION_REDIRECT_STRATEGY_CLASS = new ConfigurationKey<Class<? extends AuthenticationRedirectStrategy>>("authenticationRedirectStrategyClass", null);
|
||||
ConfigurationKey<Class<? extends GatewayResolver>> GATEWAY_STORAGE_CLASS = new ConfigurationKey<Class<? extends GatewayResolver>>("gatewayStorageClass", DefaultGatewayResolverImpl.class);
|
||||
ConfigurationKey<String> CAS_SERVER_URL_PREFIX = new ConfigurationKey<String>("casServerUrlPrefix", null);
|
||||
ConfigurationKey<String> ENCODING = new ConfigurationKey<String>("encoding", null);
|
||||
ConfigurationKey<Long> TOLERANCE = new ConfigurationKey<Long>("tolerance", 1000L);
|
||||
|
||||
/**
|
||||
* @deprecated As of 3.4. This constant is not used by the client and will
|
||||
* be removed in future versions.
|
||||
*/
|
||||
@Deprecated
|
||||
ConfigurationKey<Boolean> DISABLE_XML_SCHEMA_VALIDATION = new ConfigurationKey<Boolean>("disableXmlSchemaValidation", Boolean.FALSE);
|
||||
ConfigurationKey<String> IGNORE_PATTERN = new ConfigurationKey<String>("ignorePattern", null);
|
||||
ConfigurationKey<String> IGNORE_URL_PATTERN_TYPE = new ConfigurationKey<String>("ignoreUrlPatternType", "REGEX");
|
||||
ConfigurationKey<Class<? extends HostnameVerifier>> HOSTNAME_VERIFIER = new ConfigurationKey<Class<? extends HostnameVerifier>>("hostnameVerifier", null);
|
||||
ConfigurationKey<String> HOSTNAME_VERIFIER_CONFIG = new ConfigurationKey<String>("hostnameVerifierConfig", null);
|
||||
ConfigurationKey<Boolean> EXCEPTION_ON_VALIDATION_FAILURE = new ConfigurationKey<Boolean>("exceptionOnValidationFailure", Boolean.TRUE);
|
||||
ConfigurationKey<Boolean> REDIRECT_AFTER_VALIDATION = new ConfigurationKey<Boolean>("redirectAfterValidation", Boolean.TRUE);
|
||||
ConfigurationKey<Boolean> USE_SESSION = new ConfigurationKey<Boolean>("useSession", Boolean.TRUE);
|
||||
ConfigurationKey<String> SECRET_KEY = new ConfigurationKey<String>("secretKey", null);
|
||||
ConfigurationKey<String> CIPHER_ALGORITHM = new ConfigurationKey<String>("cipherAlgorithm", "DESede");
|
||||
ConfigurationKey<String> PROXY_RECEPTOR_URL = new ConfigurationKey<String>("proxyReceptorUrl", null);
|
||||
ConfigurationKey<Class<? extends ProxyGrantingTicketStorage>> PROXY_GRANTING_TICKET_STORAGE_CLASS = new ConfigurationKey<Class<? extends ProxyGrantingTicketStorage>>("proxyGrantingTicketStorageClass", ProxyGrantingTicketStorageImpl.class);
|
||||
ConfigurationKey<Integer> MILLIS_BETWEEN_CLEAN_UPS = new ConfigurationKey<Integer>("millisBetweenCleanUps", 60000);
|
||||
ConfigurationKey<Boolean> ACCEPT_ANY_PROXY = new ConfigurationKey<Boolean>("acceptAnyProxy", Boolean.FALSE);
|
||||
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");
|
||||
}
|
||||
|
|
@ -0,0 +1,79 @@
|
|||
/*
|
||||
* 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.configuration;
|
||||
|
||||
import javax.servlet.Filter;
|
||||
import javax.servlet.FilterConfig;
|
||||
|
||||
/**
|
||||
* Abstraction to allow for pluggable methods for retrieving filter configuration.
|
||||
*
|
||||
* @author Scott Battaglia
|
||||
* @since 3.4.0
|
||||
*/
|
||||
public interface ConfigurationStrategy {
|
||||
|
||||
/**
|
||||
* Retrieves the value for the provided {@param configurationKey}, falling back to the {@param configurationKey}'s {@link ConfigurationKey#getDefaultValue()} if nothing can be found.
|
||||
*
|
||||
* @param configurationKey the configuration key. MUST NOT BE NULL.
|
||||
* @return the configured value, or the default value.
|
||||
*/
|
||||
boolean getBoolean(ConfigurationKey<Boolean> configurationKey);
|
||||
|
||||
/**
|
||||
* Retrieves the value for the provided {@param configurationKey}, falling back to the {@param configurationKey}'s {@link ConfigurationKey#getDefaultValue()} if nothing can be found.
|
||||
*
|
||||
* @param configurationKey the configuration key. MUST NOT BE NULL.
|
||||
* @return the configured value, or the default value.
|
||||
*/
|
||||
String getString(ConfigurationKey<String> configurationKey);
|
||||
|
||||
/**
|
||||
* Retrieves the value for the provided {@param configurationKey}, falling back to the {@param configurationKey}'s {@link ConfigurationKey#getDefaultValue()} if nothing can be found.
|
||||
*
|
||||
* @param configurationKey the configuration key. MUST NOT BE NULL.
|
||||
* @return the configured value, or the default value.
|
||||
*/
|
||||
long getLong(ConfigurationKey<Long> configurationKey);
|
||||
|
||||
/**
|
||||
* Retrieves the value for the provided {@param configurationKey}, falling back to the {@param configurationKey}'s {@link ConfigurationKey#getDefaultValue()} if nothing can be found.
|
||||
*
|
||||
* @param configurationKey the configuration key. MUST NOT BE NULL.
|
||||
* @return the configured value, or the default value.
|
||||
*/
|
||||
int getInt(ConfigurationKey<Integer> configurationKey);
|
||||
|
||||
/**
|
||||
* Retrieves the value for the provided {@param configurationKey}, falling back to the {@param configurationKey}'s {@link ConfigurationKey#getDefaultValue()} if nothing can be found.
|
||||
*
|
||||
* @param configurationKey the configuration key. MUST NOT BE NULL.
|
||||
* @return the configured value, or the default value.
|
||||
*/
|
||||
<T> Class<? extends T> getClass(ConfigurationKey<Class<? extends T>> configurationKey);
|
||||
|
||||
/**
|
||||
* Initializes the strategy. This must be called before calling any of the "get" methods.
|
||||
*
|
||||
* @param filterConfig the filter configuration object.
|
||||
* @param filterClazz the filter
|
||||
*/
|
||||
void init(FilterConfig filterConfig, Class<? extends Filter> filterClazz);
|
||||
}
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
/*
|
||||
* 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.configuration;
|
||||
|
||||
import org.jasig.cas.client.util.CommonUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Enumeration to map simple names to the underlying classes so that deployers can reference the simple name in the
|
||||
* <code>web.xml</code> instead of the fully qualified class name.
|
||||
*
|
||||
* @author Scott Battaglia
|
||||
* @since 3.4.0
|
||||
*/
|
||||
public enum ConfigurationStrategyName {
|
||||
|
||||
DEFAULT(LegacyConfigurationStrategyImpl.class), JNDI(JndiConfigurationStrategyImpl.class), WEB_XML(WebXmlConfigurationStrategyImpl.class),
|
||||
PROPERTY_FILE(PropertiesConfigurationStrategyImpl.class), SYSTEM_PROPERTIES(SystemPropertiesConfigurationStrategyImpl.class);
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(ConfigurationStrategyName.class);
|
||||
|
||||
private final Class<? extends ConfigurationStrategy> configurationStrategyClass;
|
||||
|
||||
private ConfigurationStrategyName(final Class<? extends ConfigurationStrategy> configurationStrategyClass) {
|
||||
this.configurationStrategyClass = configurationStrategyClass;
|
||||
}
|
||||
|
||||
/**
|
||||
* Static helper method that will resolve a simple string to either an enum value or a {@link org.jasig.cas.client.configuration.ConfigurationStrategy} class.
|
||||
*
|
||||
* @param value the value to attempt to resolve.
|
||||
* @return the underlying class that this maps to (either via simple name or fully qualified class name).
|
||||
*/
|
||||
public static Class<? extends ConfigurationStrategy> resolveToConfigurationStrategy(final String value) {
|
||||
if (CommonUtils.isBlank(value)) {
|
||||
return DEFAULT.configurationStrategyClass;
|
||||
}
|
||||
|
||||
for (final ConfigurationStrategyName csn : values()) {
|
||||
if (csn.name().equalsIgnoreCase(value)) {
|
||||
return csn.configurationStrategyClass;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
final Class<?> clazz = Class.forName(value);
|
||||
|
||||
if (clazz.isAssignableFrom(ConfigurationStrategy.class)) {
|
||||
return (Class<? extends ConfigurationStrategy>) clazz;
|
||||
}
|
||||
} catch (final ClassNotFoundException e) {
|
||||
LOGGER.error("Unable to locate strategy {} by name or class name. Using default strategy instead.", value, e);
|
||||
}
|
||||
|
||||
return DEFAULT.configurationStrategyClass;
|
||||
}
|
||||
}
|
||||
|
|
@ -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.configuration;
|
||||
|
||||
import org.jasig.cas.client.util.CommonUtils;
|
||||
|
||||
import javax.naming.InitialContext;
|
||||
import javax.naming.NamingException;
|
||||
import javax.servlet.Filter;
|
||||
import javax.servlet.FilterConfig;
|
||||
|
||||
/**
|
||||
* Loads configuration information from JNDI, using the <code>defaultValue</code> if it can't.
|
||||
*
|
||||
* @author Scott Battaglia
|
||||
* @since 3.4.0
|
||||
*/
|
||||
public class JndiConfigurationStrategyImpl extends BaseConfigurationStrategy {
|
||||
|
||||
private static final String ENVIRONMENT_PREFIX = "java:comp/env/cas/";
|
||||
|
||||
private final String environmentPrefix;
|
||||
|
||||
private InitialContext context;
|
||||
|
||||
private String simpleFilterName;
|
||||
|
||||
public JndiConfigurationStrategyImpl() {
|
||||
this(ENVIRONMENT_PREFIX);
|
||||
}
|
||||
|
||||
public JndiConfigurationStrategyImpl(final String environmentPrefix) {
|
||||
this.environmentPrefix = environmentPrefix;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected final String get(final ConfigurationKey configurationKey) {
|
||||
if (context == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final String propertyName = configurationKey.getName();
|
||||
final String filterValue = loadFromContext(context, this.environmentPrefix + this.simpleFilterName + "/" + propertyName);
|
||||
|
||||
if (CommonUtils.isNotBlank(filterValue)) {
|
||||
logger.info("Property [{}] loaded from JNDI Filter Specific Property with value [{}]", propertyName, filterValue);
|
||||
return filterValue;
|
||||
}
|
||||
|
||||
final String rootValue = loadFromContext(context, this.environmentPrefix + propertyName);
|
||||
|
||||
if (CommonUtils.isNotBlank(rootValue)) {
|
||||
logger.info("Property [{}] loaded from JNDI with value [{}]", propertyName, rootValue);
|
||||
return rootValue;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private String loadFromContext(final InitialContext context, final String path) {
|
||||
try {
|
||||
return (String) context.lookup(path);
|
||||
} catch (final NamingException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public final void init(final FilterConfig filterConfig, final Class<? extends Filter> clazz) {
|
||||
this.simpleFilterName = clazz.getSimpleName();
|
||||
try {
|
||||
this.context = new InitialContext();
|
||||
} catch (final NamingException e) {
|
||||
logger.error("Unable to create InitialContext. No properties can be loaded via JNDI.", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* 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.configuration;
|
||||
|
||||
import org.jasig.cas.client.util.CommonUtils;
|
||||
|
||||
import javax.servlet.Filter;
|
||||
import javax.servlet.FilterConfig;
|
||||
|
||||
/**
|
||||
* Replicates the original behavior by checking the {@link org.jasig.cas.client.configuration.WebXmlConfigurationStrategyImpl} first, and then
|
||||
* the {@link org.jasig.cas.client.configuration.JndiConfigurationStrategyImpl} before using the <code>defaultValue</code>.
|
||||
*
|
||||
* @author Scott Battaglia
|
||||
* @since 3.4.0
|
||||
*/
|
||||
public final class LegacyConfigurationStrategyImpl extends BaseConfigurationStrategy {
|
||||
|
||||
private final WebXmlConfigurationStrategyImpl webXmlConfigurationStrategy = new WebXmlConfigurationStrategyImpl();
|
||||
|
||||
private final JndiConfigurationStrategyImpl jndiConfigurationStrategy = new JndiConfigurationStrategyImpl();
|
||||
|
||||
public void init(FilterConfig filterConfig, Class<? extends Filter> filterClazz) {
|
||||
this.webXmlConfigurationStrategy.init(filterConfig, filterClazz);
|
||||
this.jndiConfigurationStrategy.init(filterConfig, filterClazz);
|
||||
}
|
||||
|
||||
protected String get(final ConfigurationKey key) {
|
||||
final String value1 = this.webXmlConfigurationStrategy.get(key);
|
||||
|
||||
if (CommonUtils.isNotBlank(value1)) {
|
||||
return value1;
|
||||
}
|
||||
|
||||
return this.jndiConfigurationStrategy.get(key);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,101 @@
|
|||
/*
|
||||
* 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.configuration;
|
||||
|
||||
import org.jasig.cas.client.util.CommonUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.servlet.Filter;
|
||||
import javax.servlet.FilterConfig;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* @author Scott Battaglia
|
||||
* @since 3.4.0
|
||||
*/
|
||||
public final class PropertiesConfigurationStrategyImpl extends BaseConfigurationStrategy {
|
||||
|
||||
/**
|
||||
* Property name we'll use in the {@link javax.servlet.FilterConfig} and {@link javax.servlet.ServletConfig} to try and find where
|
||||
* you stored the configuration file.
|
||||
*/
|
||||
private static final String CONFIGURATION_FILE_LOCATION = "configFileLocation";
|
||||
|
||||
/**
|
||||
* Default location of the configuration file. Mostly for testing/demo. You will most likely want to configure an alternative location.
|
||||
*/
|
||||
private static final String DEFAULT_CONFIGURATION_FILE_LOCATION = "/etc/java-cas-client.properties";
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(PropertiesConfigurationStrategyImpl.class);
|
||||
|
||||
private String simpleFilterName;
|
||||
|
||||
private Properties properties = new Properties();
|
||||
|
||||
@Override
|
||||
protected String get(final ConfigurationKey configurationKey) {
|
||||
final String property = configurationKey.getName();
|
||||
final String filterSpecificProperty = this.simpleFilterName + "." + property;
|
||||
|
||||
final String filterSpecificValue = this.properties.getProperty(filterSpecificProperty);
|
||||
|
||||
if (CommonUtils.isNotEmpty(filterSpecificValue)) {
|
||||
return filterSpecificValue;
|
||||
}
|
||||
|
||||
return this.properties.getProperty(property);
|
||||
}
|
||||
|
||||
public void init(final FilterConfig filterConfig, final Class<? extends Filter> filterClazz) {
|
||||
this.simpleFilterName = filterClazz.getSimpleName();
|
||||
final String fileLocationFromFilterConfig = filterConfig.getInitParameter(CONFIGURATION_FILE_LOCATION);
|
||||
final boolean filterConfigFileLoad = loadPropertiesFromFile(fileLocationFromFilterConfig);
|
||||
|
||||
if (!filterConfigFileLoad) {
|
||||
final String fileLocationFromServletConfig = filterConfig.getServletContext().getInitParameter(CONFIGURATION_FILE_LOCATION);
|
||||
final boolean servletContextFileLoad = loadPropertiesFromFile(fileLocationFromServletConfig);
|
||||
|
||||
if (!servletContextFileLoad) {
|
||||
final boolean defaultConfigFileLoaded = loadPropertiesFromFile(DEFAULT_CONFIGURATION_FILE_LOCATION);
|
||||
CommonUtils.assertTrue(defaultConfigFileLoaded, "unable to load properties to configure CAS client");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean loadPropertiesFromFile(final String file) {
|
||||
if (CommonUtils.isEmpty(file)) {
|
||||
return false;
|
||||
}
|
||||
FileInputStream fis = null;
|
||||
try {
|
||||
fis = new FileInputStream(file);
|
||||
this.properties.load(fis);
|
||||
return true;
|
||||
} catch (final IOException e) {
|
||||
LOGGER.warn("Unable to load properties for file {}", file, e);
|
||||
return false;
|
||||
} finally {
|
||||
CommonUtils.closeQuietly(fis);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* 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.configuration;
|
||||
|
||||
import javax.servlet.Filter;
|
||||
import javax.servlet.FilterConfig;
|
||||
|
||||
/**
|
||||
* Load all configuration from system properties.
|
||||
*
|
||||
* @author Jerome Leleu
|
||||
* @since 3.4.0
|
||||
*/
|
||||
public class SystemPropertiesConfigurationStrategyImpl extends BaseConfigurationStrategy {
|
||||
|
||||
public void init(FilterConfig filterConfig, Class<? extends Filter> filterClazz) {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String get(ConfigurationKey configurationKey) {
|
||||
return System.getProperty(configurationKey.getName());
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* 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.configuration;
|
||||
|
||||
import org.jasig.cas.client.util.CommonUtils;
|
||||
|
||||
import javax.servlet.Filter;
|
||||
import javax.servlet.FilterConfig;
|
||||
|
||||
/**
|
||||
* Implementation of the {@link org.jasig.cas.client.configuration.ConfigurationStrategy} that first checks the {@link javax.servlet.FilterConfig} and
|
||||
* then checks the {@link javax.servlet.ServletContext}, ultimately falling back to the <code>defaultValue</code>.
|
||||
*
|
||||
* @author Scott Battaglia
|
||||
* @since 3.4.0
|
||||
*/
|
||||
public final class WebXmlConfigurationStrategyImpl extends BaseConfigurationStrategy {
|
||||
|
||||
private FilterConfig filterConfig;
|
||||
|
||||
protected String get(final ConfigurationKey configurationKey) {
|
||||
final String value = this.filterConfig.getInitParameter(configurationKey.getName());
|
||||
|
||||
if (CommonUtils.isNotBlank(value)) {
|
||||
CommonUtils.assertFalse(ConfigurationKeys.RENEW.equals(configurationKey), "Renew MUST be specified via context parameter or JNDI environment to avoid misconfiguration.");
|
||||
logger.info("Property [{}] loaded from FilterConfig.getInitParameter with value [{}]", configurationKey, value);
|
||||
return value;
|
||||
}
|
||||
|
||||
final String value2 = filterConfig.getServletContext().getInitParameter(configurationKey.getName());
|
||||
|
||||
if (CommonUtils.isNotBlank(value2)) {
|
||||
logger.info("Property [{}] loaded from ServletContext.getInitParameter with value [{}]", configurationKey,
|
||||
value2);
|
||||
return value2;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public void init(final FilterConfig filterConfig, final Class<? extends Filter> clazz) {
|
||||
this.filterConfig = filterConfig;
|
||||
}
|
||||
}
|
||||
|
|
@ -29,6 +29,7 @@ import javax.servlet.http.HttpServletRequest;
|
|||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.http.HttpSession;
|
||||
|
||||
import org.jasig.cas.client.Protocol;
|
||||
import org.jasig.cas.client.util.AbstractCasFilter;
|
||||
import org.jasig.cas.client.util.CommonUtils;
|
||||
|
||||
|
|
@ -50,12 +51,16 @@ import org.jasig.cas.client.util.CommonUtils;
|
|||
*/
|
||||
public final class Servlet3AuthenticationFilter extends AbstractCasFilter {
|
||||
|
||||
public Servlet3AuthenticationFilter() {
|
||||
super(Protocol.CAS2);
|
||||
}
|
||||
|
||||
public void doFilter(final ServletRequest servletRequest, final ServletResponse servletResponse,
|
||||
final FilterChain chain) throws IOException, ServletException {
|
||||
final HttpServletRequest request = (HttpServletRequest) servletRequest;
|
||||
final HttpServletResponse response = (HttpServletResponse) servletResponse;
|
||||
final HttpSession session = request.getSession();
|
||||
final String ticket = CommonUtils.safeGetParameter(request, getArtifactParameterName());
|
||||
final String ticket = CommonUtils.safeGetParameter(request, getProtocol().getArtifactParameterName());
|
||||
|
||||
if (session != null && session.getAttribute(CONST_CAS_ASSERTION) == null && ticket != null) {
|
||||
try {
|
||||
|
|
|
|||
|
|
@ -18,6 +18,8 @@
|
|||
*/
|
||||
package org.jasig.cas.client.proxy;
|
||||
|
||||
import org.jasig.cas.client.configuration.ConfigurationKeys;
|
||||
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.Key;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
|
|
@ -36,11 +38,9 @@ import javax.crypto.spec.DESedeKeySpec;
|
|||
*/
|
||||
public abstract class AbstractEncryptedProxyGrantingTicketStorageImpl implements ProxyGrantingTicketStorage {
|
||||
|
||||
public static final String DEFAULT_ENCRYPTION_ALGORITHM = "DESede";
|
||||
|
||||
private Key key;
|
||||
|
||||
private String cipherAlgorithm = DEFAULT_ENCRYPTION_ALGORITHM;
|
||||
private String cipherAlgorithm = ConfigurationKeys.CIPHER_ALGORITHM.getDefaultValue();
|
||||
|
||||
public final void setSecretKey(final String key) throws NoSuchAlgorithmException, InvalidKeyException,
|
||||
InvalidKeySpecException {
|
||||
|
|
|
|||
|
|
@ -55,6 +55,11 @@ public final class Cas20ProxyRetriever implements ProxyRetriever {
|
|||
/** Url connection factory to use when communicating with the server **/
|
||||
private final HttpURLConnectionFactory urlConnectionFactory;
|
||||
|
||||
@Deprecated
|
||||
public Cas20ProxyRetriever(final String casServerUrl, final String encoding) {
|
||||
this(casServerUrl, encoding, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Main Constructor.
|
||||
*
|
||||
|
|
@ -75,7 +80,13 @@ public final class Cas20ProxyRetriever implements ProxyRetriever {
|
|||
CommonUtils.assertNotNull(targetService, "targetService cannot be null.");
|
||||
|
||||
final URL url = constructUrl(proxyGrantingTicketId, targetService);
|
||||
final String response = CommonUtils.getResponseFromServer(url, this.urlConnectionFactory, this.encoding);
|
||||
final String response;
|
||||
|
||||
if (this.urlConnectionFactory != null) {
|
||||
response = CommonUtils.getResponseFromServer(url, this.urlConnectionFactory, this.encoding);
|
||||
} else {
|
||||
response = CommonUtils.getResponseFromServer(url, this.encoding);
|
||||
}
|
||||
final String error = XmlUtils.getTextForElement(response, "proxyFailure");
|
||||
|
||||
if (CommonUtils.isNotEmpty(error)) {
|
||||
|
|
|
|||
|
|
@ -19,10 +19,13 @@
|
|||
package org.jasig.cas.client.session;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import javax.servlet.*;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.jasig.cas.client.configuration.ConfigurationKeys;
|
||||
import org.jasig.cas.client.util.AbstractConfigurationFilter;
|
||||
|
||||
/**
|
||||
|
|
@ -34,49 +37,47 @@ import org.jasig.cas.client.util.AbstractConfigurationFilter;
|
|||
*/
|
||||
public final class SingleSignOutFilter extends AbstractConfigurationFilter {
|
||||
|
||||
private static final SingleSignOutHandler handler = new SingleSignOutHandler();
|
||||
private static final SingleSignOutHandler HANDLER = new SingleSignOutHandler();
|
||||
|
||||
private AtomicBoolean handlerInitialized = new AtomicBoolean(false);
|
||||
|
||||
public void init(final FilterConfig filterConfig) throws ServletException {
|
||||
super.init(filterConfig);
|
||||
if (!isIgnoreInitConfiguration()) {
|
||||
handler.setArtifactParameterName(getPropertyFromInitParams(filterConfig, "artifactParameterName",
|
||||
SingleSignOutHandler.DEFAULT_ARTIFACT_PARAMETER_NAME));
|
||||
handler.setLogoutParameterName(getPropertyFromInitParams(filterConfig, "logoutParameterName",
|
||||
SingleSignOutHandler.DEFAULT_LOGOUT_PARAMETER_NAME));
|
||||
handler.setFrontLogoutParameterName(getPropertyFromInitParams(filterConfig, "frontLogoutParameterName",
|
||||
SingleSignOutHandler.DEFAULT_FRONT_LOGOUT_PARAMETER_NAME));
|
||||
handler.setRelayStateParameterName(getPropertyFromInitParams(filterConfig, "relayStateParameterName",
|
||||
SingleSignOutHandler.DEFAULT_RELAY_STATE_PARAMETER_NAME));
|
||||
handler.setCasServerUrlPrefix(getPropertyFromInitParams(filterConfig, "casServerUrlPrefix", null));
|
||||
handler.setArtifactParameterOverPost(parseBoolean(getPropertyFromInitParams(filterConfig,
|
||||
"artifactParameterOverPost", "false")));
|
||||
handler.setEagerlyCreateSessions(parseBoolean(getPropertyFromInitParams(filterConfig,
|
||||
"eagerlyCreateSessions", "true")));
|
||||
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));
|
||||
HANDLER.setEagerlyCreateSessions(getBoolean(ConfigurationKeys.EAGERLY_CREATE_SESSIONS));
|
||||
}
|
||||
handler.init();
|
||||
HANDLER.init();
|
||||
handlerInitialized.set(true);
|
||||
}
|
||||
|
||||
public void setArtifactParameterName(final String name) {
|
||||
handler.setArtifactParameterName(name);
|
||||
HANDLER.setArtifactParameterName(name);
|
||||
}
|
||||
|
||||
public void setLogoutParameterName(final String name) {
|
||||
handler.setLogoutParameterName(name);
|
||||
HANDLER.setLogoutParameterName(name);
|
||||
}
|
||||
|
||||
public void setFrontLogoutParameterName(final String name) {
|
||||
handler.setFrontLogoutParameterName(name);
|
||||
HANDLER.setFrontLogoutParameterName(name);
|
||||
}
|
||||
|
||||
public void setRelayStateParameterName(final String name) {
|
||||
handler.setRelayStateParameterName(name);
|
||||
HANDLER.setRelayStateParameterName(name);
|
||||
}
|
||||
|
||||
public void setCasServerUrlPrefix(final String casServerUrlPrefix) {
|
||||
handler.setCasServerUrlPrefix(casServerUrlPrefix);
|
||||
HANDLER.setCasServerUrlPrefix(casServerUrlPrefix);
|
||||
}
|
||||
|
||||
public void setSessionMappingStorage(final SessionMappingStorage storage) {
|
||||
handler.setSessionMappingStorage(storage);
|
||||
HANDLER.setSessionMappingStorage(storage);
|
||||
}
|
||||
|
||||
public void doFilter(final ServletRequest servletRequest, final ServletResponse servletResponse,
|
||||
|
|
@ -84,7 +85,15 @@ public final class SingleSignOutFilter extends AbstractConfigurationFilter {
|
|||
final HttpServletRequest request = (HttpServletRequest) servletRequest;
|
||||
final HttpServletResponse response = (HttpServletResponse) servletResponse;
|
||||
|
||||
if (handler.process(request, response)) {
|
||||
/**
|
||||
* <p>Workaround for now for the fact that Spring Security will fail since it doesn't call {@link #init(javax.servlet.FilterConfig)}.</p>
|
||||
* <p>Ultimately we need to allow deployers to actually inject their fully-initialized {@link org.jasig.cas.client.session.SingleSignOutHandler}.</p>
|
||||
*/
|
||||
if (!this.handlerInitialized.getAndSet(true)) {
|
||||
HANDLER.init();
|
||||
}
|
||||
|
||||
if (HANDLER.process(request, response)) {
|
||||
filterChain.doFilter(servletRequest, servletResponse);
|
||||
}
|
||||
}
|
||||
|
|
@ -94,6 +103,6 @@ public final class SingleSignOutFilter extends AbstractConfigurationFilter {
|
|||
}
|
||||
|
||||
protected static SingleSignOutHandler getSingleSignOutHandler() {
|
||||
return handler;
|
||||
return HANDLER;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,7 +28,9 @@ import javax.servlet.http.HttpServletResponse;
|
|||
import javax.servlet.http.HttpSession;
|
||||
|
||||
import org.apache.commons.codec.binary.Base64;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.jasig.cas.client.Protocol;
|
||||
import org.jasig.cas.client.configuration.ConfigurationKeys;
|
||||
import org.jasig.cas.client.util.CommonUtils;
|
||||
import org.jasig.cas.client.util.XmlUtils;
|
||||
import org.slf4j.Logger;
|
||||
|
|
@ -44,11 +46,6 @@ import org.slf4j.LoggerFactory;
|
|||
*/
|
||||
public final class SingleSignOutHandler {
|
||||
|
||||
public final static String DEFAULT_ARTIFACT_PARAMETER_NAME = "ticket";
|
||||
public final static String DEFAULT_LOGOUT_PARAMETER_NAME = "logoutRequest";
|
||||
public final static String DEFAULT_FRONT_LOGOUT_PARAMETER_NAME = "SAMLRequest";
|
||||
public final static String DEFAULT_RELAY_STATE_PARAMETER_NAME = "RelayState";
|
||||
|
||||
private final static int DECOMPRESSION_FACTOR = 10;
|
||||
|
||||
/** Logger instance */
|
||||
|
|
@ -58,19 +55,19 @@ public final class SingleSignOutHandler {
|
|||
private SessionMappingStorage sessionMappingStorage = new HashMapBackedSessionMappingStorage();
|
||||
|
||||
/** The name of the artifact parameter. This is used to capture the session identifier. */
|
||||
private String artifactParameterName = DEFAULT_ARTIFACT_PARAMETER_NAME;
|
||||
private String artifactParameterName = Protocol.CAS2.getArtifactParameterName();
|
||||
|
||||
/** Parameter name that stores logout request for back channel SLO */
|
||||
private String logoutParameterName = DEFAULT_LOGOUT_PARAMETER_NAME;
|
||||
private String logoutParameterName = ConfigurationKeys.LOGOUT_PARAMETER_NAME.getDefaultValue();
|
||||
|
||||
/** Parameter name that stores logout request for front channel SLO */
|
||||
private String frontLogoutParameterName = DEFAULT_FRONT_LOGOUT_PARAMETER_NAME;
|
||||
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 = DEFAULT_RELAY_STATE_PARAMETER_NAME;
|
||||
private String relayStateParameterName = ConfigurationKeys.RELAY_STATE_PARAMETER_NAME.getDefaultValue();
|
||||
|
||||
/** The prefix url of the CAS server */
|
||||
private String casServerUrlPrefix;
|
||||
private String casServerUrlPrefix = "";
|
||||
|
||||
private boolean artifactParameterOverPost = false;
|
||||
|
||||
|
|
@ -78,6 +75,8 @@ public final class SingleSignOutHandler {
|
|||
|
||||
private List<String> safeParameters;
|
||||
|
||||
private LogoutStrategy logoutStrategy = isServlet30() ? new Servlet30LogoutStrategy() : new Servlet25LogoutStrategy();
|
||||
|
||||
public void setSessionMappingStorage(final SessionMappingStorage storage) {
|
||||
this.sessionMappingStorage = storage;
|
||||
}
|
||||
|
|
@ -132,18 +131,24 @@ public final class SingleSignOutHandler {
|
|||
/**
|
||||
* Initializes the component for use.
|
||||
*/
|
||||
public void init() {
|
||||
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.");
|
||||
public synchronized void init() {
|
||||
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.");
|
||||
|
||||
if (this.artifactParameterOverPost) {
|
||||
this.safeParameters = Arrays.asList(this.logoutParameterName, this.artifactParameterName);
|
||||
} else {
|
||||
this.safeParameters = Arrays.asList(this.logoutParameterName);
|
||||
if (CommonUtils.isBlank(this.casServerUrlPrefix)) {
|
||||
logger.warn("Front Channel single sign out redirects are disabled when the 'casServerUrlPrefix' value is not set.");
|
||||
}
|
||||
|
||||
if (this.artifactParameterOverPost) {
|
||||
this.safeParameters = Arrays.asList(this.logoutParameterName, this.artifactParameterName);
|
||||
} else {
|
||||
this.safeParameters = Arrays.asList(this.logoutParameterName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -174,14 +179,15 @@ public final class SingleSignOutHandler {
|
|||
}
|
||||
|
||||
/**
|
||||
* Determines whether the given request is a CAS front channel logout request.
|
||||
* 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())
|
||||
return "GET".equals(request.getMethod()) && CommonUtils.isNotBlank(this.casServerUrlPrefix)
|
||||
&& CommonUtils.isNotBlank(CommonUtils.safeGetParameter(request, this.frontLogoutParameterName));
|
||||
}
|
||||
|
||||
|
|
@ -304,11 +310,7 @@ public final class SingleSignOutHandler {
|
|||
} catch (final IllegalStateException e) {
|
||||
logger.debug("Error invalidating session.", e);
|
||||
}
|
||||
try {
|
||||
request.logout();
|
||||
} catch (final ServletException e) {
|
||||
logger.debug("Error performing request.logout.");
|
||||
}
|
||||
this.logoutStrategy.logout(request);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -343,4 +345,39 @@ public final class SingleSignOutHandler {
|
|||
private boolean isMultipartRequest(final HttpServletRequest request) {
|
||||
return request.getContentType() != null && request.getContentType().toLowerCase().startsWith("multipart");
|
||||
}
|
||||
|
||||
private static boolean isServlet30() {
|
||||
try {
|
||||
return HttpServletRequest.class.getMethod("logout") != null;
|
||||
} catch (final NoSuchMethodException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Abstracts the ways we can force logout with the Servlet spec.
|
||||
*/
|
||||
private interface LogoutStrategy {
|
||||
|
||||
void logout(HttpServletRequest request);
|
||||
}
|
||||
|
||||
private class Servlet25LogoutStrategy implements LogoutStrategy {
|
||||
|
||||
public void logout(final HttpServletRequest request) {
|
||||
// nothing additional to do here
|
||||
}
|
||||
}
|
||||
|
||||
private class Servlet30LogoutStrategy implements LogoutStrategy {
|
||||
|
||||
public void logout(final HttpServletRequest request) {
|
||||
try {
|
||||
request.logout();
|
||||
} catch (final ServletException e) {
|
||||
logger.debug("Error performing request.logout.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
*/
|
||||
package org.jasig.cas.client.ssl;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
|
|
@ -28,7 +29,7 @@ import java.net.URLConnection;
|
|||
* @author Misagh Moayyed
|
||||
* @since 3.3
|
||||
*/
|
||||
public interface HttpURLConnectionFactory {
|
||||
public interface HttpURLConnectionFactory extends Serializable {
|
||||
|
||||
/**
|
||||
* Receives a {@link URLConnection} instance typically as a result of a {@link URL}
|
||||
|
|
|
|||
|
|
@ -18,8 +18,7 @@
|
|||
*/
|
||||
package org.jasig.cas.client.ssl;
|
||||
|
||||
import java.io.FileInputStream;
|
||||
import java.io.InputStream;
|
||||
import java.io.*;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URLConnection;
|
||||
import java.security.KeyStore;
|
||||
|
|
@ -41,6 +40,8 @@ import org.slf4j.LoggerFactory;
|
|||
*/
|
||||
public final class HttpsURLConnectionFactory implements HttpURLConnectionFactory {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(HttpsURLConnectionFactory.class);
|
||||
|
||||
/**
|
||||
|
|
@ -146,4 +147,45 @@ public final class HttpsURLConnectionFactory implements HttpURLConnectionFactory
|
|||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
final HttpsURLConnectionFactory that = (HttpsURLConnectionFactory) o;
|
||||
|
||||
if (!hostnameVerifier.equals(that.hostnameVerifier)) return false;
|
||||
if (!sslConfiguration.equals(that.sslConfiguration)) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = hostnameVerifier.hashCode();
|
||||
result = 31 * result + sslConfiguration.hashCode();
|
||||
return result;
|
||||
}
|
||||
|
||||
private void writeObject(final ObjectOutputStream out) throws IOException {
|
||||
if (this.hostnameVerifier == HttpsURLConnection.getDefaultHostnameVerifier()) {
|
||||
out.writeObject(null);
|
||||
} else {
|
||||
out.writeObject(this.hostnameVerifier);
|
||||
}
|
||||
|
||||
out.writeObject(this.sslConfiguration);
|
||||
|
||||
}
|
||||
|
||||
private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException {
|
||||
final Object internalHostNameVerifier = in.readObject();
|
||||
if (internalHostNameVerifier == null) {
|
||||
this.hostnameVerifier = HttpsURLConnection.getDefaultHostnameVerifier();
|
||||
} else {
|
||||
this.hostnameVerifier = (HostnameVerifier) internalHostNameVerifier;
|
||||
}
|
||||
|
||||
this.sslConfiguration = (Properties) in.readObject();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@
|
|||
|
||||
package org.jasig.cas.client.ssl;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.regex.Pattern;
|
||||
import javax.net.ssl.HostnameVerifier;
|
||||
import javax.net.ssl.SSLSession;
|
||||
|
|
@ -32,7 +33,9 @@ import javax.net.ssl.SSLSession;
|
|||
* @since 3.1.10
|
||||
*
|
||||
*/
|
||||
public final class RegexHostnameVerifier implements HostnameVerifier {
|
||||
public final class RegexHostnameVerifier implements HostnameVerifier, Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/** Allowed hostname pattern */
|
||||
private Pattern pattern;
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ package org.jasig.cas.client.ssl;
|
|||
|
||||
import javax.net.ssl.HostnameVerifier;
|
||||
import javax.net.ssl.SSLSession;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* Verifies a SSL peer host name based on an explicit whitelist of allowed hosts.
|
||||
|
|
@ -29,7 +30,9 @@ import javax.net.ssl.SSLSession;
|
|||
* @since 3.1.10
|
||||
*
|
||||
*/
|
||||
public final class WhitelistHostnameVerifier implements HostnameVerifier {
|
||||
public final class WhitelistHostnameVerifier implements HostnameVerifier, Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/** Allowed hosts */
|
||||
private String[] allowedHosts;
|
||||
|
|
|
|||
|
|
@ -18,6 +18,9 @@
|
|||
*/
|
||||
package org.jasig.cas.client.util;
|
||||
|
||||
import org.jasig.cas.client.Protocol;
|
||||
import org.jasig.cas.client.configuration.ConfigurationKeys;
|
||||
|
||||
import javax.servlet.FilterConfig;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
|
@ -42,12 +45,8 @@ public abstract class AbstractCasFilter extends AbstractConfigurationFilter {
|
|||
/** Represents the constant for where the assertion will be located in memory. */
|
||||
public static final String CONST_CAS_ASSERTION = "_const_cas_assertion_";
|
||||
|
||||
/** Defines the parameter to look for for the artifact. */
|
||||
private String artifactParameterName = "ticket";
|
||||
private Protocol protocol;
|
||||
|
||||
/** Defines the parameter to look for for the service. */
|
||||
private String serviceParameterName = "service";
|
||||
|
||||
/** Sets where response.encodeUrl should be called on service urls when constructed. */
|
||||
private boolean encodeServiceUrl = true;
|
||||
|
||||
|
|
@ -59,18 +58,16 @@ public abstract class AbstractCasFilter extends AbstractConfigurationFilter {
|
|||
/** The exact url of the service. */
|
||||
private String service;
|
||||
|
||||
protected AbstractCasFilter(final Protocol protocol) {
|
||||
this.protocol = protocol;
|
||||
}
|
||||
|
||||
public final void init(final FilterConfig filterConfig) throws ServletException {
|
||||
super.init(filterConfig);
|
||||
if (!isIgnoreInitConfiguration()) {
|
||||
setServerName(getPropertyFromInitParams(filterConfig, "serverName", null));
|
||||
logger.trace("Loading serverName property: {}", this.serverName);
|
||||
setService(getPropertyFromInitParams(filterConfig, "service", null));
|
||||
logger.trace("Loading service property: {}", this.service);
|
||||
setArtifactParameterName(getPropertyFromInitParams(filterConfig, "artifactParameterName", "ticket"));
|
||||
logger.trace("Loading artifact parameter name property: {}", this.artifactParameterName);
|
||||
setServiceParameterName(getPropertyFromInitParams(filterConfig, "serviceParameterName", "service"));
|
||||
logger.trace("Loading serviceParameterName property: {} ", this.serviceParameterName);
|
||||
setEncodeServiceUrl(parseBoolean(getPropertyFromInitParams(filterConfig, "encodeServiceUrl", "true")));
|
||||
logger.trace("Loading encodeServiceUrl property: {}", this.encodeServiceUrl);
|
||||
setServerName(getString(ConfigurationKeys.SERVER_NAME));
|
||||
setService(getString(ConfigurationKeys.SERVICE));
|
||||
setEncodeServiceUrl(getBoolean(ConfigurationKeys.ENCODE_SERVICE_URL));
|
||||
|
||||
initInternal(filterConfig);
|
||||
}
|
||||
|
|
@ -92,8 +89,6 @@ public abstract class AbstractCasFilter extends AbstractConfigurationFilter {
|
|||
* afterPropertiesSet();
|
||||
*/
|
||||
public void init() {
|
||||
CommonUtils.assertNotNull(this.artifactParameterName, "artifactParameterName cannot be null.");
|
||||
CommonUtils.assertNotNull(this.serviceParameterName, "serviceParameterName cannot be null.");
|
||||
CommonUtils.assertTrue(CommonUtils.isNotEmpty(this.serverName) || CommonUtils.isNotEmpty(this.service),
|
||||
"serverName or service must be set.");
|
||||
CommonUtils.assertTrue(CommonUtils.isBlank(this.serverName) || CommonUtils.isBlank(this.service),
|
||||
|
|
@ -107,7 +102,7 @@ public abstract class AbstractCasFilter extends AbstractConfigurationFilter {
|
|||
|
||||
protected final String constructServiceUrl(final HttpServletRequest request, final HttpServletResponse response) {
|
||||
return CommonUtils.constructServiceUrl(request, response, this.service, this.serverName,
|
||||
this.artifactParameterName, this.encodeServiceUrl);
|
||||
this.protocol.getArtifactParameterName(), this.encodeServiceUrl);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -129,26 +124,14 @@ public abstract class AbstractCasFilter extends AbstractConfigurationFilter {
|
|||
this.service = service;
|
||||
}
|
||||
|
||||
public final void setArtifactParameterName(final String artifactParameterName) {
|
||||
this.artifactParameterName = artifactParameterName;
|
||||
}
|
||||
|
||||
public final void setServiceParameterName(final String serviceParameterName) {
|
||||
this.serviceParameterName = serviceParameterName;
|
||||
}
|
||||
|
||||
public final void setEncodeServiceUrl(final boolean encodeServiceUrl) {
|
||||
this.encodeServiceUrl = encodeServiceUrl;
|
||||
}
|
||||
|
||||
public final String getArtifactParameterName() {
|
||||
return this.artifactParameterName;
|
||||
protected Protocol getProtocol() {
|
||||
return this.protocol;
|
||||
}
|
||||
|
||||
public final String getServiceParameterName() {
|
||||
return this.serviceParameterName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Template method to allow you to change how you retrieve the ticket.
|
||||
*
|
||||
|
|
@ -156,6 +139,6 @@ public abstract class AbstractCasFilter extends AbstractConfigurationFilter {
|
|||
* @return the ticket if its found, null otherwise.
|
||||
*/
|
||||
protected String retrieveTicketFromRequest(final HttpServletRequest request) {
|
||||
return CommonUtils.safeGetParameter(request, getArtifactParameterName());
|
||||
return CommonUtils.safeGetParameter(request, this.protocol.getArtifactParameterName());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,10 +18,13 @@
|
|||
*/
|
||||
package org.jasig.cas.client.util;
|
||||
|
||||
import javax.naming.InitialContext;
|
||||
import javax.naming.NamingException;
|
||||
import javax.servlet.Filter;
|
||||
import javax.servlet.FilterConfig;
|
||||
import javax.servlet.ServletException;
|
||||
|
||||
import org.jasig.cas.client.configuration.ConfigurationKey;
|
||||
import org.jasig.cas.client.configuration.ConfigurationStrategy;
|
||||
import org.jasig.cas.client.configuration.ConfigurationStrategyName;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
|
@ -34,94 +37,41 @@ import org.slf4j.LoggerFactory;
|
|||
*/
|
||||
public abstract class AbstractConfigurationFilter implements Filter {
|
||||
|
||||
private static final String CONFIGURATION_STRATEGY_KEY = "configurationStrategy";
|
||||
|
||||
protected final Logger logger = LoggerFactory.getLogger(getClass());
|
||||
|
||||
private boolean ignoreInitConfiguration = false;
|
||||
|
||||
/**
|
||||
* Retrieves the property from the FilterConfig. First it checks the FilterConfig's initParameters to see if it
|
||||
* has a value.
|
||||
* If it does, it returns that, otherwise it retrieves the ServletContext's initParameters and returns that value if any.
|
||||
* <p>
|
||||
* Finally, it will check JNDI if all other methods fail. All the JNDI properties should be stored under either java:comp/env/cas/SHORTFILTERNAME/{propertyName}
|
||||
* or java:comp/env/cas/{propertyName}
|
||||
* <p>
|
||||
* Essentially the documented order is:
|
||||
* <ol>
|
||||
* <li>FilterConfig.getInitParameter</li>
|
||||
* <li>ServletContext.getInitParameter</li>
|
||||
* <li>java:comp/env/cas/SHORTFILTERNAME/{propertyName}</li>
|
||||
* <li>java:comp/env/cas/{propertyName}</li>
|
||||
* <li>Default Value</li>
|
||||
* </ol>
|
||||
*
|
||||
*
|
||||
* @param filterConfig the Filter Configuration.
|
||||
* @param propertyName the property to retrieve.
|
||||
* @param defaultValue the default value if the property is not found.
|
||||
* @return the property value, following the above conventions. It will always return the more specific value (i.e.
|
||||
* filter vs. context).
|
||||
*/
|
||||
protected final String getPropertyFromInitParams(final FilterConfig filterConfig, final String propertyName,
|
||||
final String defaultValue) {
|
||||
final String value = filterConfig.getInitParameter(propertyName);
|
||||
private ConfigurationStrategy configurationStrategy;
|
||||
|
||||
if (CommonUtils.isNotBlank(value)) {
|
||||
if ("renew".equals(propertyName)) {
|
||||
throw new IllegalArgumentException(
|
||||
"Renew MUST be specified via context parameter or JNDI environment to avoid misconfiguration.");
|
||||
}
|
||||
logger.info("Property [{}] loaded from FilterConfig.getInitParameter with value [{}]", propertyName, value);
|
||||
return value;
|
||||
}
|
||||
|
||||
final String value2 = filterConfig.getServletContext().getInitParameter(propertyName);
|
||||
|
||||
if (CommonUtils.isNotBlank(value2)) {
|
||||
logger.info("Property [{}] loaded from ServletContext.getInitParameter with value [{}]", propertyName,
|
||||
value2);
|
||||
return value2;
|
||||
}
|
||||
InitialContext context;
|
||||
try {
|
||||
context = new InitialContext();
|
||||
} catch (final NamingException e) {
|
||||
logger.warn(e.getMessage(), e);
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
final String shortName = this.getClass().getName().substring(this.getClass().getName().lastIndexOf(".") + 1);
|
||||
final String value3 = loadFromContext(context, "java:comp/env/cas/" + shortName + "/" + propertyName);
|
||||
|
||||
if (CommonUtils.isNotBlank(value3)) {
|
||||
logger.info("Property [{}] loaded from JNDI Filter Specific Property with value [{}]", propertyName, value3);
|
||||
return value3;
|
||||
}
|
||||
|
||||
final String value4 = loadFromContext(context, "java:comp/env/cas/" + propertyName);
|
||||
|
||||
if (CommonUtils.isNotBlank(value4)) {
|
||||
logger.info("Property [{}] loaded from JNDI with value [{}]", propertyName, value4);
|
||||
return value4;
|
||||
}
|
||||
|
||||
logger.info("Property [{}] not found. Using default value [{}]", propertyName, defaultValue);
|
||||
return defaultValue;
|
||||
public void init(FilterConfig filterConfig) throws ServletException {
|
||||
final String configurationStrategyName = filterConfig.getServletContext().getInitParameter(CONFIGURATION_STRATEGY_KEY);
|
||||
this.configurationStrategy = ReflectUtils.newInstance(ConfigurationStrategyName.resolveToConfigurationStrategy(configurationStrategyName));
|
||||
this.configurationStrategy.init(filterConfig, getClass());
|
||||
}
|
||||
|
||||
protected final boolean parseBoolean(final String value) {
|
||||
return ((value != null) && value.equalsIgnoreCase("true"));
|
||||
protected final boolean getBoolean(final ConfigurationKey<Boolean> configurationKey) {
|
||||
return this.configurationStrategy.getBoolean(configurationKey);
|
||||
}
|
||||
|
||||
protected final String loadFromContext(final InitialContext context, final String path) {
|
||||
try {
|
||||
return (String) context.lookup(path);
|
||||
} catch (final NamingException e) {
|
||||
return null;
|
||||
}
|
||||
protected final String getString(final ConfigurationKey<String> configurationKey) {
|
||||
return this.configurationStrategy.getString(configurationKey);
|
||||
}
|
||||
|
||||
public final void setIgnoreInitConfiguration(boolean ignoreInitConfiguration) {
|
||||
protected final long getLong(final ConfigurationKey<Long> configurationKey) {
|
||||
return this.configurationStrategy.getLong(configurationKey);
|
||||
}
|
||||
|
||||
protected final int getInt(final ConfigurationKey<Integer> configurationKey) {
|
||||
return this.configurationStrategy.getInt(configurationKey);
|
||||
}
|
||||
|
||||
protected final <T> Class<? extends T> getClass(final ConfigurationKey<Class<? extends T>> configurationKey) {
|
||||
return this.configurationStrategy.getClass(configurationKey);
|
||||
}
|
||||
|
||||
public final void setIgnoreInitConfiguration(final boolean ignoreInitConfiguration) {
|
||||
this.ignoreInitConfiguration = ignoreInitConfiguration;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -22,13 +22,12 @@ import java.io.*;
|
|||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.net.URLEncoder;
|
||||
import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.*;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import org.jasig.cas.client.proxy.ProxyGrantingTicketStorage;
|
||||
import org.jasig.cas.client.ssl.HttpURLConnectionFactory;
|
||||
import org.jasig.cas.client.ssl.HttpsURLConnectionFactory;
|
||||
import org.jasig.cas.client.validation.ProxyList;
|
||||
import org.jasig.cas.client.validation.ProxyListEditor;
|
||||
import org.slf4j.Logger;
|
||||
|
|
@ -55,16 +54,12 @@ public final class CommonUtils {
|
|||
*/
|
||||
private static final String PARAM_PROXY_GRANTING_TICKET = "pgtId";
|
||||
|
||||
private static final HttpURLConnectionFactory DEFAULT_URL_CONNECTION_FACTORY = new HttpsURLConnectionFactory();
|
||||
|
||||
private CommonUtils() {
|
||||
// nothing to do
|
||||
}
|
||||
|
||||
public static String formatForUtcTime(final Date date) {
|
||||
final DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
|
||||
dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
|
||||
return dateFormat.format(date);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the object is null or not. If it is, throw an exception and
|
||||
* display the message.
|
||||
|
|
@ -96,7 +91,7 @@ public final class CommonUtils {
|
|||
* Assert that the statement is true, otherwise throw an exception with the
|
||||
* provided message.
|
||||
*
|
||||
* @param cond the codition to assert is true.
|
||||
* @param cond the condition to assert is true.
|
||||
* @param message the message to display if the condition is not true.
|
||||
*/
|
||||
public static void assertTrue(final boolean cond, final String message) {
|
||||
|
|
@ -105,6 +100,20 @@ public final class CommonUtils {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Assert that the statement is true, otherwise throw an exception with the
|
||||
* provided message.
|
||||
*
|
||||
* @param cond the condition to assert is false.
|
||||
* @param message the message to display if the condition is not false.
|
||||
*/
|
||||
public static void assertFalse(final boolean cond, final String message) {
|
||||
if (cond) {
|
||||
throw new IllegalArgumentException(message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether the String is null or of length 0.
|
||||
*
|
||||
|
|
@ -348,6 +357,28 @@ public final class CommonUtils {
|
|||
return safeGetParameter(request, parameter, Arrays.asList("logoutRequest"));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Contacts the remote URL and returns the response.
|
||||
*
|
||||
* @param constructedUrl the url to contact.
|
||||
* @param encoding the encoding to use.
|
||||
* @return the response.
|
||||
*/
|
||||
@Deprecated
|
||||
public static String getResponseFromServer(final String constructedUrl, final String encoding) {
|
||||
try {
|
||||
return getResponseFromServer(new URL(constructedUrl), DEFAULT_URL_CONNECTION_FACTORY, encoding);
|
||||
} catch (final Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public static String getResponseFromServer(final URL constructedUrl, final String encoding) {
|
||||
return getResponseFromServer(constructedUrl, DEFAULT_URL_CONNECTION_FACTORY, encoding);
|
||||
}
|
||||
|
||||
/**
|
||||
* Contacts the remote URL and returns the response.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -24,22 +24,22 @@ import java.util.Enumeration;
|
|||
import java.util.List;
|
||||
import javax.servlet.*;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Filters that redirects to the supplied url based on an exception. Exceptions and the urls are configured via
|
||||
* init filter name/param values.
|
||||
* <p>
|
||||
* <p/>
|
||||
* If there is an exact match the filter uses that value. If there's a non-exact match (i.e. inheritance), then the filter
|
||||
* uses the last value that matched.
|
||||
* <p>
|
||||
* <p/>
|
||||
* If there is no match it will redirect to a default error page. The default exception is configured via the "defaultErrorRedirectPage" property.
|
||||
*
|
||||
*
|
||||
* @author Scott Battaglia
|
||||
* @version $Revision$ $Date$
|
||||
* @since 3.1.4
|
||||
*
|
||||
*/
|
||||
public final class ErrorRedirectFilter implements Filter {
|
||||
|
||||
|
|
@ -58,8 +58,8 @@ public final class ErrorRedirectFilter implements Filter {
|
|||
final HttpServletResponse httpResponse = (HttpServletResponse) response;
|
||||
try {
|
||||
filterChain.doFilter(request, response);
|
||||
} catch (final ServletException e) {
|
||||
final Throwable t = e.getCause();
|
||||
} catch (final Exception e) {
|
||||
final Throwable t = extractErrorToCompare(e);
|
||||
ErrorHolder currentMatch = null;
|
||||
for (final ErrorHolder errorHolder : this.errors) {
|
||||
if (errorHolder.exactMatch(t)) {
|
||||
|
|
@ -78,6 +78,22 @@ public final class ErrorRedirectFilter implements Filter {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine which error to use for comparison. If there is an {@link Throwable#getCause()} then that will be used. Otherwise, the original throwable is used.
|
||||
*
|
||||
* @param throwable the throwable to look for a root cause.
|
||||
* @return the throwable to use for comparison. MUST NOT BE NULL.
|
||||
*/
|
||||
private Throwable extractErrorToCompare(final Throwable throwable) {
|
||||
final Throwable cause = throwable.getCause();
|
||||
|
||||
if (cause != null) {
|
||||
return cause;
|
||||
}
|
||||
|
||||
return throwable;
|
||||
}
|
||||
|
||||
public void init(final FilterConfig filterConfig) throws ServletException {
|
||||
this.defaultErrorRedirectPage = filterConfig.getInitParameter("defaultErrorRedirectPage");
|
||||
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ import javax.servlet.http.HttpServletRequest;
|
|||
import javax.servlet.http.HttpServletRequestWrapper;
|
||||
import javax.servlet.http.HttpSession;
|
||||
import org.jasig.cas.client.authentication.AttributePrincipal;
|
||||
import org.jasig.cas.client.configuration.ConfigurationKeys;
|
||||
import org.jasig.cas.client.validation.Assertion;
|
||||
|
||||
/**
|
||||
|
|
@ -82,8 +83,9 @@ public final class HttpServletRequestWrapperFilter extends AbstractConfiguration
|
|||
}
|
||||
|
||||
public void init(final FilterConfig filterConfig) throws ServletException {
|
||||
this.roleAttribute = getPropertyFromInitParams(filterConfig, "roleAttribute", null);
|
||||
this.ignoreCase = Boolean.parseBoolean(getPropertyFromInitParams(filterConfig, "ignoreCase", "false"));
|
||||
super.init(filterConfig);
|
||||
this.roleAttribute = getString(ConfigurationKeys.ROLE_ATTRIBUTE);
|
||||
this.ignoreCase = getBoolean(ConfigurationKeys.IGNORE_CASE);
|
||||
}
|
||||
|
||||
final class CasHttpServletRequestWrapper extends HttpServletRequestWrapper {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,74 @@
|
|||
package org.jasig.cas.client.util;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.CharBuffer;
|
||||
import java.nio.charset.Charset;
|
||||
|
||||
/**
|
||||
* IO utility class.
|
||||
*
|
||||
* @author Marvin S. Addison
|
||||
* @since 3.4
|
||||
*/
|
||||
public final class IOUtils {
|
||||
|
||||
/** UTF-8 character set. */
|
||||
public static final Charset UTF8 = Charset.forName("UTF-8");
|
||||
|
||||
|
||||
private IOUtils() { /** Utility class pattern. */ }
|
||||
|
||||
/**
|
||||
* Reads all data from the given stream as UTF-8 character data and closes it on completion or errors.
|
||||
*
|
||||
* @param in Input stream containing character data.
|
||||
*
|
||||
* @return String of all data in stream.
|
||||
*
|
||||
* @throws IOException On IO errors.
|
||||
*/
|
||||
public static String readString(final InputStream in) throws IOException {
|
||||
return readString(in, UTF8);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads all data from the given stream as character data in the given character set and closes it on completion
|
||||
* or errors.
|
||||
*
|
||||
* @param in Input stream containing character data.
|
||||
* @param charset Character set of data in stream.
|
||||
*
|
||||
* @return String of all data in stream.
|
||||
*
|
||||
* @throws IOException On IO errors.
|
||||
*/
|
||||
public static String readString(final InputStream in, final Charset charset) throws IOException {
|
||||
final Reader reader = new InputStreamReader(in, charset);
|
||||
final StringBuilder builder = new StringBuilder();
|
||||
final CharBuffer buffer = CharBuffer.allocate(2048);
|
||||
try {
|
||||
while (reader.read(buffer) > -1) {
|
||||
buffer.flip();
|
||||
builder.append(buffer);
|
||||
}
|
||||
} finally {
|
||||
closeQuietly(reader);
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Unconditionally close a {@link Closeable} resource. Errors on close are ignored.
|
||||
*
|
||||
* @param resource Resource to close.
|
||||
*/
|
||||
public static void closeQuietly(final Closeable resource) {
|
||||
try {
|
||||
if (resource != null) {
|
||||
resource.close();
|
||||
}
|
||||
} catch (final IOException e) {
|
||||
//ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
package org.jasig.cas.client.util;
|
||||
|
||||
import javax.xml.namespace.NamespaceContext;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Namespace context implementation backed by a map of XML prefixes to namespace URIs.
|
||||
*
|
||||
* @author Marvin S. Addison
|
||||
* @since 3.4
|
||||
*/
|
||||
public class MapNamespaceContext implements NamespaceContext {
|
||||
|
||||
private final Map<String, String> namespaceMap;
|
||||
|
||||
/**
|
||||
* Creates a new instance from an array of namespace delcarations.
|
||||
*
|
||||
* @param namespaceDeclarations An array of namespace declarations of the form prefix->uri.
|
||||
*/
|
||||
public MapNamespaceContext(final String ... namespaceDeclarations) {
|
||||
namespaceMap = new HashMap<String, String>();
|
||||
int index;
|
||||
String key;
|
||||
String value;
|
||||
for (final String decl : namespaceDeclarations) {
|
||||
index = decl.indexOf('-');
|
||||
key = decl.substring(0, index);
|
||||
value = decl.substring(index + 2);
|
||||
namespaceMap.put(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance from a map.
|
||||
*
|
||||
* @param namespaceMap Map of XML namespace prefixes (keys) to URIs (values).
|
||||
*/
|
||||
public MapNamespaceContext(final Map<String, String> namespaceMap) {
|
||||
this.namespaceMap = namespaceMap;
|
||||
}
|
||||
|
||||
public String getNamespaceURI(final String prefix) {
|
||||
return namespaceMap.get(prefix);
|
||||
}
|
||||
|
||||
public String getPrefix(final String namespaceURI) {
|
||||
for (final Map.Entry<String, String> entry : namespaceMap.entrySet()) {
|
||||
if (entry.getValue().equalsIgnoreCase(namespaceURI)) {
|
||||
return entry.getKey();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public Iterator getPrefixes(final String namespaceURI) {
|
||||
return Collections.singleton(getPrefix(namespaceURI)).iterator();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,87 @@
|
|||
package org.jasig.cas.client.util;
|
||||
|
||||
import org.w3c.dom.NodeList;
|
||||
import org.xml.sax.InputSource;
|
||||
|
||||
import javax.xml.namespace.NamespaceContext;
|
||||
import javax.xml.namespace.QName;
|
||||
import javax.xml.xpath.*;
|
||||
|
||||
/**
|
||||
* Thread local XPath expression.
|
||||
*
|
||||
* @author Marvin S. Addison
|
||||
* @since 3.4
|
||||
*/
|
||||
public class ThreadLocalXPathExpression extends ThreadLocal<XPathExpression> implements XPathExpression {
|
||||
|
||||
/** XPath expression */
|
||||
private final String expression;
|
||||
|
||||
/** Namespace context. */
|
||||
private final NamespaceContext context;
|
||||
|
||||
/**
|
||||
* Creates a new instance from an XPath expression and namespace context.
|
||||
*
|
||||
* @param xPath XPath expression.
|
||||
* @param context Namespace context for handling namespace prefix to URI mappings.
|
||||
*/
|
||||
public ThreadLocalXPathExpression(final String xPath, final NamespaceContext context) {
|
||||
this.expression = xPath;
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
public Object evaluate(final Object o, final QName qName) throws XPathExpressionException {
|
||||
return get().evaluate(o, qName);
|
||||
}
|
||||
|
||||
public String evaluate(final Object o) throws XPathExpressionException {
|
||||
return get().evaluate(o);
|
||||
}
|
||||
|
||||
public Object evaluate(final InputSource inputSource, final QName qName) throws XPathExpressionException {
|
||||
return get().evaluate(inputSource, qName);
|
||||
}
|
||||
|
||||
public String evaluate(final InputSource inputSource) throws XPathExpressionException {
|
||||
return get().evaluate(inputSource);
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluates the XPath expression and returns the result coerced to a string.
|
||||
*
|
||||
* @param o Object on which to evaluate the expression; typically a DOM node.
|
||||
*
|
||||
* @return Evaluation result as a string.
|
||||
*
|
||||
* @throws XPathExpressionException On XPath evaluation errors.
|
||||
*/
|
||||
public String evaluateAsString(final Object o) throws XPathExpressionException {
|
||||
return (String) evaluate(o, XPathConstants.STRING);
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluates the XPath expression and returns the result coerced to a node list.
|
||||
*
|
||||
* @param o Object on which to evaluate the expression; typically a DOM node.
|
||||
*
|
||||
* @return Evaluation result as a node list.
|
||||
*
|
||||
* @throws XPathExpressionException On XPath evaluation errors.
|
||||
*/
|
||||
public NodeList evaluateAsNodeList(final Object o) throws XPathExpressionException {
|
||||
return (NodeList) evaluate(o, XPathConstants.NODESET);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected XPathExpression initialValue() {
|
||||
try {
|
||||
final XPath xPath = XPathFactory.newInstance().newXPath();
|
||||
xPath.setNamespaceContext(context);
|
||||
return xPath.compile(expression);
|
||||
} catch (XPathExpressionException e) {
|
||||
throw new IllegalArgumentException("Invalid XPath expression");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -19,16 +19,20 @@
|
|||
package org.jasig.cas.client.util;
|
||||
|
||||
import java.io.StringReader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.*;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.w3c.dom.Document;
|
||||
import org.xml.sax.Attributes;
|
||||
import org.xml.sax.InputSource;
|
||||
import org.xml.sax.SAXException;
|
||||
import org.xml.sax.XMLReader;
|
||||
import org.xml.sax.helpers.DefaultHandler;
|
||||
|
||||
import javax.xml.XMLConstants;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import javax.xml.parsers.SAXParserFactory;
|
||||
|
||||
/**
|
||||
|
|
@ -45,6 +49,34 @@ public final class XmlUtils {
|
|||
*/
|
||||
private final static Logger LOGGER = LoggerFactory.getLogger(XmlUtils.class);
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new namespace-aware DOM document object by parsing the given XML.
|
||||
*
|
||||
* @param xml XML content.
|
||||
*
|
||||
* @return DOM document.
|
||||
*/
|
||||
public static Document newDocument(final String xml) {
|
||||
final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
|
||||
final Map<String, Boolean> features = new HashMap<String, Boolean>();
|
||||
features.put(XMLConstants.FEATURE_SECURE_PROCESSING, true);
|
||||
features.put("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
|
||||
for (final Map.Entry<String, Boolean> entry : features.entrySet()) {
|
||||
try {
|
||||
factory.setFeature(entry.getKey(), entry.getValue());
|
||||
} catch (ParserConfigurationException e) {
|
||||
LOGGER.warn("Failed setting XML feature {}: {}", entry.getKey(), e);
|
||||
}
|
||||
}
|
||||
factory.setNamespaceAware(true);
|
||||
try {
|
||||
return factory.newDocumentBuilder().parse(new InputSource(new StringReader(xml)));
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("XML parsing error: " + e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an instance of an XML reader from the XMLReaderFactory.
|
||||
*
|
||||
|
|
@ -62,6 +94,7 @@ public final class XmlUtils {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Retrieve the text for a group of elements. Each text element is an entry
|
||||
* in a list.
|
||||
|
|
|
|||
|
|
@ -34,10 +34,6 @@ public abstract class AbstractCasProtocolUrlBasedTicketValidator extends Abstrac
|
|||
super(casServerUrlPrefix);
|
||||
}
|
||||
|
||||
protected final void setDisableXmlSchemaValidation(final boolean disable) {
|
||||
// nothing to do
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the response from the server by opening a connection and merely reading the response.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -25,6 +25,9 @@ import javax.net.ssl.HostnameVerifier;
|
|||
import javax.servlet.*;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.jasig.cas.client.Protocol;
|
||||
import org.jasig.cas.client.configuration.ConfigurationKeys;
|
||||
import org.jasig.cas.client.util.AbstractCasFilter;
|
||||
import org.jasig.cas.client.util.CommonUtils;
|
||||
import org.jasig.cas.client.util.ReflectUtils;
|
||||
|
|
@ -68,6 +71,10 @@ public abstract class AbstractTicketValidationFilter extends AbstractCasFilter {
|
|||
*/
|
||||
private boolean useSession = true;
|
||||
|
||||
protected AbstractTicketValidationFilter(final Protocol protocol) {
|
||||
super(protocol);
|
||||
}
|
||||
|
||||
/**
|
||||
* Template method to return the appropriate validator.
|
||||
*
|
||||
|
|
@ -81,12 +88,11 @@ public abstract class AbstractTicketValidationFilter extends AbstractCasFilter {
|
|||
/**
|
||||
* Gets the ssl config to use for HTTPS connections
|
||||
* if one is configured for this filter.
|
||||
* @param filterConfig Servlet filter configuration.
|
||||
* @return Properties that can contains key/trust info for Client Side Certificates
|
||||
*/
|
||||
protected Properties getSSLConfig(final FilterConfig filterConfig) {
|
||||
protected Properties getSSLConfig() {
|
||||
final Properties properties = new Properties();
|
||||
final String fileName = getPropertyFromInitParams(filterConfig, "sslConfigFile", null);
|
||||
final String fileName = getString(ConfigurationKeys.SSL_CONFIG_FILE);
|
||||
|
||||
if (fileName != null) {
|
||||
FileInputStream fis = null;
|
||||
|
|
@ -106,14 +112,11 @@ public abstract class AbstractTicketValidationFilter extends AbstractCasFilter {
|
|||
/**
|
||||
* Gets the configured {@link HostnameVerifier} to use for HTTPS connections
|
||||
* if one is configured for this filter.
|
||||
* @param filterConfig Servlet filter configuration.
|
||||
* @return Instance of specified host name verifier or null if none specified.
|
||||
*/
|
||||
protected HostnameVerifier getHostnameVerifier(final FilterConfig filterConfig) {
|
||||
final String className = getPropertyFromInitParams(filterConfig, "hostnameVerifier", null);
|
||||
logger.trace("Using hostnameVerifier parameter: {}", className);
|
||||
final String config = getPropertyFromInitParams(filterConfig, "hostnameVerifierConfig", null);
|
||||
logger.trace("Using hostnameVerifierConfig parameter: {}", config);
|
||||
protected HostnameVerifier getHostnameVerifier() {
|
||||
final Class<? extends HostnameVerifier> className = getClass(ConfigurationKeys.HOSTNAME_VERIFIER);
|
||||
final String config = getString(ConfigurationKeys.HOSTNAME_VERIFIER_CONFIG);
|
||||
if (className != null) {
|
||||
if (config != null) {
|
||||
return ReflectUtils.newInstance(className, config);
|
||||
|
|
@ -125,14 +128,9 @@ public abstract class AbstractTicketValidationFilter extends AbstractCasFilter {
|
|||
}
|
||||
|
||||
protected void initInternal(final FilterConfig filterConfig) throws ServletException {
|
||||
setExceptionOnValidationFailure(parseBoolean(getPropertyFromInitParams(filterConfig,
|
||||
"exceptionOnValidationFailure", "false")));
|
||||
logger.trace("Setting exceptionOnValidationFailure parameter: {}", this.exceptionOnValidationFailure);
|
||||
setRedirectAfterValidation(parseBoolean(getPropertyFromInitParams(filterConfig, "redirectAfterValidation",
|
||||
"true")));
|
||||
logger.trace("Setting redirectAfterValidation parameter: {}", this.redirectAfterValidation);
|
||||
setUseSession(parseBoolean(getPropertyFromInitParams(filterConfig, "useSession", "true")));
|
||||
logger.trace("Setting useSession parameter: {}", this.useSession);
|
||||
setExceptionOnValidationFailure(getBoolean(ConfigurationKeys.EXCEPTION_ON_VALIDATION_FAILURE));
|
||||
setRedirectAfterValidation(getBoolean(ConfigurationKeys.REDIRECT_AFTER_VALIDATION));
|
||||
setUseSession(getBoolean(ConfigurationKeys.USE_SESSION));
|
||||
|
||||
if (!this.useSession && this.redirectAfterValidation) {
|
||||
logger.warn("redirectAfterValidation parameter may not be true when useSession parameter is false. Resetting it to false in order to prevent infinite redirects.");
|
||||
|
|
|
|||
|
|
@ -90,13 +90,6 @@ public abstract class AbstractUrlBasedTicketValidator implements TicketValidator
|
|||
*/
|
||||
protected abstract String getUrlSuffix();
|
||||
|
||||
/**
|
||||
* Disable XML Schema validation. Note, setting this to true may not be reversable. Defaults to false. Setting it to false
|
||||
* after setting it to true may not have any affect.
|
||||
*
|
||||
* @param disabled whether to disable or not.
|
||||
*/
|
||||
protected abstract void setDisableXmlSchemaValidation(boolean disabled);
|
||||
|
||||
/**
|
||||
* Constructs the URL to send the validation request to.
|
||||
|
|
@ -110,7 +103,7 @@ public abstract class AbstractUrlBasedTicketValidator implements TicketValidator
|
|||
|
||||
logger.debug("Placing URL parameters in map.");
|
||||
urlParameters.put("ticket", ticket);
|
||||
urlParameters.put("service", encodeUrl(serviceUrl));
|
||||
urlParameters.put("service", serviceUrl);
|
||||
|
||||
if (this.renew) {
|
||||
urlParameters.put("renew", "true");
|
||||
|
|
@ -144,7 +137,8 @@ public abstract class AbstractUrlBasedTicketValidator implements TicketValidator
|
|||
buffer.append(i++ == 0 ? "?" : "&");
|
||||
buffer.append(key);
|
||||
buffer.append("=");
|
||||
buffer.append(value);
|
||||
final String encodedValue = encodeUrl(value);
|
||||
buffer.append(encodedValue);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -19,29 +19,36 @@
|
|||
package org.jasig.cas.client.validation;
|
||||
|
||||
import javax.servlet.FilterConfig;
|
||||
|
||||
import org.jasig.cas.client.Protocol;
|
||||
import org.jasig.cas.client.configuration.ConfigurationKeys;
|
||||
import org.jasig.cas.client.ssl.HttpURLConnectionFactory;
|
||||
import org.jasig.cas.client.ssl.HttpsURLConnectionFactory;
|
||||
|
||||
/**
|
||||
* Implementation of AbstractTicketValidatorFilter that instanciates a Cas10TicketValidator.
|
||||
* Implementation of AbstractTicketValidatorFilter that creates a Cas10TicketValidator.
|
||||
* <p>Deployers can provide the "casServerPrefix" and the "renew" attributes via the standard context or filter init
|
||||
* parameters.
|
||||
*
|
||||
*
|
||||
* @author Scott Battaglia
|
||||
* @version $Revision$ $Date$
|
||||
* @since 3.1
|
||||
*/
|
||||
public class Cas10TicketValidationFilter extends AbstractTicketValidationFilter {
|
||||
|
||||
protected final TicketValidator getTicketValidator(final FilterConfig filterConfig) {
|
||||
final String casServerUrlPrefix = getPropertyFromInitParams(filterConfig, "casServerUrlPrefix", null);
|
||||
final Cas10TicketValidator validator = new Cas10TicketValidator(casServerUrlPrefix);
|
||||
validator.setRenew(parseBoolean(getPropertyFromInitParams(filterConfig, "renew", "false")));
|
||||
public Cas10TicketValidationFilter() {
|
||||
super(Protocol.CAS1);
|
||||
}
|
||||
|
||||
final HttpURLConnectionFactory factory = new HttpsURLConnectionFactory(getHostnameVerifier(filterConfig),
|
||||
getSSLConfig(filterConfig));
|
||||
protected final TicketValidator getTicketValidator(final FilterConfig filterConfig) {
|
||||
final String casServerUrlPrefix = getString(ConfigurationKeys.CAS_SERVER_URL_PREFIX);
|
||||
final Cas10TicketValidator validator = new Cas10TicketValidator(casServerUrlPrefix);
|
||||
validator.setRenew(getBoolean(ConfigurationKeys.RENEW));
|
||||
|
||||
final HttpURLConnectionFactory factory = new HttpsURLConnectionFactory(getHostnameVerifier(),
|
||||
getSSLConfig());
|
||||
validator.setURLConnectionFactory(factory);
|
||||
validator.setEncoding(getPropertyFromInitParams(filterConfig, "encoding", null));
|
||||
validator.setEncoding(getString(ConfigurationKeys.ENCODING));
|
||||
|
||||
return validator;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,16 +23,21 @@ import java.util.*;
|
|||
import javax.servlet.*;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.jasig.cas.client.Protocol;
|
||||
import org.jasig.cas.client.configuration.ConfigurationKeys;
|
||||
import org.jasig.cas.client.proxy.*;
|
||||
import org.jasig.cas.client.ssl.HttpURLConnectionFactory;
|
||||
import org.jasig.cas.client.ssl.HttpsURLConnectionFactory;
|
||||
import org.jasig.cas.client.util.CommonUtils;
|
||||
import org.jasig.cas.client.util.ReflectUtils;
|
||||
|
||||
import static org.jasig.cas.client.configuration.ConfigurationKeys.*;
|
||||
|
||||
/**
|
||||
* Creates either a CAS20ProxyTicketValidator or a CAS20ServiceTicketValidator depending on whether any of the
|
||||
* proxy parameters are set.
|
||||
* <p>
|
||||
* <p/>
|
||||
* This filter can also pass additional parameters to the ticket validator. Any init parameter not included in the
|
||||
* reserved list {@link org.jasig.cas.client.validation.Cas20ProxyReceivingTicketValidationFilter#RESERVED_INIT_PARAMS}.
|
||||
*
|
||||
|
|
@ -40,20 +45,20 @@ import org.jasig.cas.client.util.ReflectUtils;
|
|||
* @author Brad Cupit (brad [at] lsu {dot} edu)
|
||||
* @version $Revision$ $Date$
|
||||
* @since 3.1
|
||||
*
|
||||
*/
|
||||
public class Cas20ProxyReceivingTicketValidationFilter extends AbstractTicketValidationFilter {
|
||||
|
||||
private static final String[] RESERVED_INIT_PARAMS = new String[] { "proxyGrantingTicketStorageClass",
|
||||
"proxyReceptorUrl", "acceptAnyProxy", "allowedProxyChains", "casServerUrlPrefix", "proxyCallbackUrl",
|
||||
"renew", "exceptionOnValidationFailure", "redirectAfterValidation", "useSession", "serverName", "service",
|
||||
"artifactParameterName", "serviceParameterName", "encodeServiceUrl", "millisBetweenCleanUps",
|
||||
"hostnameVerifier", "encoding", "config", "ticketValidatorClass" };
|
||||
|
||||
private static final int DEFAULT_MILLIS_BETWEEN_CLEANUPS = 60 * 1000;
|
||||
private static final String[] RESERVED_INIT_PARAMS = new String[]{ARTIFACT_PARAMETER_NAME.getName(), SERVER_NAME.getName(), SERVICE.getName(), RENEW.getName(), LOGOUT_PARAMETER_NAME.getName(),
|
||||
ARTIFACT_PARAMETER_OVER_POST.getName(), EAGERLY_CREATE_SESSIONS.getName(), ENCODE_SERVICE_URL.getName(), SSL_CONFIG_FILE.getName(), ROLE_ATTRIBUTE.getName(), IGNORE_CASE.getName(),
|
||||
CAS_SERVER_LOGIN_URL.getName(), GATEWAY.getName(), AUTHENTICATION_REDIRECT_STRATEGY_CLASS.getName(), GATEWAY_STORAGE_CLASS.getName(), CAS_SERVER_URL_PREFIX.getName(), ENCODING.getName(),
|
||||
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()
|
||||
};
|
||||
|
||||
/**
|
||||
* The URL to send to the CAS server as the URL that will process proxying requests on the CAS client.
|
||||
* The URL to send to the CAS server as the URL that will process proxying requests on the CAS client.
|
||||
*/
|
||||
private String proxyReceptorUrl;
|
||||
|
||||
|
|
@ -63,25 +68,37 @@ public class Cas20ProxyReceivingTicketValidationFilter extends AbstractTicketVal
|
|||
|
||||
private int millisBetweenCleanUps;
|
||||
|
||||
protected Class<? extends Cas20ServiceTicketValidator> defaultServiceTicketValidatorClass;
|
||||
|
||||
protected Class<? extends Cas20ProxyTicketValidator> defaultProxyTicketValidatorClass;
|
||||
|
||||
/**
|
||||
* Storage location of ProxyGrantingTickets and Proxy Ticket IOUs.
|
||||
*/
|
||||
private ProxyGrantingTicketStorage proxyGrantingTicketStorage = new ProxyGrantingTicketStorageImpl();
|
||||
|
||||
protected void initInternal(final FilterConfig filterConfig) throws ServletException {
|
||||
setProxyReceptorUrl(getPropertyFromInitParams(filterConfig, "proxyReceptorUrl", null));
|
||||
public Cas20ProxyReceivingTicketValidationFilter() {
|
||||
this(Protocol.CAS2);
|
||||
this.defaultServiceTicketValidatorClass = Cas20ServiceTicketValidator.class;
|
||||
this.defaultProxyTicketValidatorClass = Cas20ProxyTicketValidator.class;
|
||||
}
|
||||
|
||||
final String proxyGrantingTicketStorageClass = getPropertyFromInitParams(filterConfig,
|
||||
"proxyGrantingTicketStorageClass", null);
|
||||
protected Cas20ProxyReceivingTicketValidationFilter(final Protocol protocol) {
|
||||
super(protocol);
|
||||
}
|
||||
|
||||
protected void initInternal(final FilterConfig filterConfig) throws ServletException {
|
||||
setProxyReceptorUrl(getString(ConfigurationKeys.PROXY_RECEPTOR_URL));
|
||||
|
||||
final Class<? extends ProxyGrantingTicketStorage> proxyGrantingTicketStorageClass = getClass(ConfigurationKeys.PROXY_GRANTING_TICKET_STORAGE_CLASS);
|
||||
|
||||
if (proxyGrantingTicketStorageClass != null) {
|
||||
this.proxyGrantingTicketStorage = ReflectUtils.newInstance(proxyGrantingTicketStorageClass);
|
||||
|
||||
if (this.proxyGrantingTicketStorage instanceof AbstractEncryptedProxyGrantingTicketStorageImpl) {
|
||||
final AbstractEncryptedProxyGrantingTicketStorageImpl p = (AbstractEncryptedProxyGrantingTicketStorageImpl) this.proxyGrantingTicketStorage;
|
||||
final String cipherAlgorithm = getPropertyFromInitParams(filterConfig, "cipherAlgorithm",
|
||||
AbstractEncryptedProxyGrantingTicketStorageImpl.DEFAULT_ENCRYPTION_ALGORITHM);
|
||||
final String secretKey = getPropertyFromInitParams(filterConfig, "secretKey", null);
|
||||
final String cipherAlgorithm = getString(ConfigurationKeys.CIPHER_ALGORITHM);
|
||||
final String secretKey = getString(ConfigurationKeys.SECRET_KEY);
|
||||
|
||||
p.setCipherAlgorithm(cipherAlgorithm);
|
||||
|
||||
|
|
@ -95,9 +112,7 @@ public class Cas20ProxyReceivingTicketValidationFilter extends AbstractTicketVal
|
|||
}
|
||||
}
|
||||
|
||||
logger.trace("Setting proxyReceptorUrl parameter: {}", this.proxyReceptorUrl);
|
||||
this.millisBetweenCleanUps = Integer.parseInt(getPropertyFromInitParams(filterConfig, "millisBetweenCleanUps",
|
||||
Integer.toString(DEFAULT_MILLIS_BETWEEN_CLEANUPS)));
|
||||
this.millisBetweenCleanUps = getInt(ConfigurationKeys.MILLIS_BETWEEN_CLEAN_UPS);
|
||||
super.initInternal(filterConfig);
|
||||
}
|
||||
|
||||
|
|
@ -115,13 +130,13 @@ public class Cas20ProxyReceivingTicketValidationFilter extends AbstractTicketVal
|
|||
this.timer.schedule(this.timerTask, this.millisBetweenCleanUps, this.millisBetweenCleanUps);
|
||||
}
|
||||
|
||||
private <T> T createNewTicketValidator(final String ticketValidatorClass, final String casServerUrlPrefix,
|
||||
final Class<T> clazz) {
|
||||
if (CommonUtils.isBlank(ticketValidatorClass)) {
|
||||
private <T> T createNewTicketValidator(final Class<? extends Cas20ServiceTicketValidator> ticketValidatorClass, final String casServerUrlPrefix,
|
||||
final Class<T> clazz) {
|
||||
if (ticketValidatorClass == null) {
|
||||
return ReflectUtils.newInstance(clazz, casServerUrlPrefix);
|
||||
}
|
||||
|
||||
return ReflectUtils.newInstance(ticketValidatorClass, casServerUrlPrefix);
|
||||
return (T) ReflectUtils.newInstance(ticketValidatorClass, casServerUrlPrefix);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -131,38 +146,37 @@ public class Cas20ProxyReceivingTicketValidationFilter extends AbstractTicketVal
|
|||
* @return a fully constructed TicketValidator.
|
||||
*/
|
||||
protected final TicketValidator getTicketValidator(final FilterConfig filterConfig) {
|
||||
final String allowAnyProxy = getPropertyFromInitParams(filterConfig, "acceptAnyProxy", null);
|
||||
final String allowedProxyChains = getPropertyFromInitParams(filterConfig, "allowedProxyChains", null);
|
||||
final String casServerUrlPrefix = getPropertyFromInitParams(filterConfig, "casServerUrlPrefix", null);
|
||||
final String ticketValidatorClass = getPropertyFromInitParams(filterConfig, "ticketValidatorClass", null);
|
||||
final boolean allowAnyProxy = getBoolean(ConfigurationKeys.ACCEPT_ANY_PROXY);
|
||||
final String allowedProxyChains = getString(ConfigurationKeys.ALLOWED_PROXY_CHAINS);
|
||||
final String casServerUrlPrefix = getString(ConfigurationKeys.CAS_SERVER_URL_PREFIX);
|
||||
final Class<? extends Cas20ServiceTicketValidator> ticketValidatorClass = getClass(ConfigurationKeys.TICKET_VALIDATOR_CLASS);
|
||||
final Cas20ServiceTicketValidator validator;
|
||||
|
||||
if (CommonUtils.isNotBlank(allowAnyProxy) || CommonUtils.isNotBlank(allowedProxyChains)) {
|
||||
if (allowAnyProxy || CommonUtils.isNotBlank(allowedProxyChains)) {
|
||||
final Cas20ProxyTicketValidator v = createNewTicketValidator(ticketValidatorClass, casServerUrlPrefix,
|
||||
Cas20ProxyTicketValidator.class);
|
||||
v.setAcceptAnyProxy(parseBoolean(allowAnyProxy));
|
||||
this.defaultProxyTicketValidatorClass);
|
||||
v.setAcceptAnyProxy(allowAnyProxy);
|
||||
v.setAllowedProxyChains(CommonUtils.createProxyList(allowedProxyChains));
|
||||
validator = v;
|
||||
} else {
|
||||
validator = createNewTicketValidator(ticketValidatorClass, casServerUrlPrefix,
|
||||
Cas20ServiceTicketValidator.class);
|
||||
this.defaultServiceTicketValidatorClass);
|
||||
}
|
||||
validator.setProxyCallbackUrl(getPropertyFromInitParams(filterConfig, "proxyCallbackUrl", null));
|
||||
validator.setProxyCallbackUrl(getString(ConfigurationKeys.PROXY_CALLBACK_URL));
|
||||
validator.setProxyGrantingTicketStorage(this.proxyGrantingTicketStorage);
|
||||
|
||||
final HttpURLConnectionFactory factory = new HttpsURLConnectionFactory(getHostnameVerifier(filterConfig),
|
||||
getSSLConfig(filterConfig));
|
||||
final HttpURLConnectionFactory factory = new HttpsURLConnectionFactory(getHostnameVerifier(),
|
||||
getSSLConfig());
|
||||
validator.setURLConnectionFactory(factory);
|
||||
|
||||
validator.setProxyRetriever(new Cas20ProxyRetriever(casServerUrlPrefix, getPropertyFromInitParams(filterConfig,
|
||||
"encoding", null), factory));
|
||||
validator.setRenew(parseBoolean(getPropertyFromInitParams(filterConfig, "renew", "false")));
|
||||
validator.setEncoding(getPropertyFromInitParams(filterConfig, "encoding", null));
|
||||
validator.setProxyRetriever(new Cas20ProxyRetriever(casServerUrlPrefix, getString(ConfigurationKeys.ENCODING), factory));
|
||||
validator.setRenew(getBoolean(ConfigurationKeys.RENEW));
|
||||
validator.setEncoding(getString(ConfigurationKeys.ENCODING));
|
||||
|
||||
final Map<String, String> additionalParameters = new HashMap<String, String>();
|
||||
final List<String> params = Arrays.asList(RESERVED_INIT_PARAMS);
|
||||
|
||||
for (final Enumeration<?> e = filterConfig.getInitParameterNames(); e.hasMoreElements();) {
|
||||
for (final Enumeration<?> e = filterConfig.getInitParameterNames(); e.hasMoreElements(); ) {
|
||||
final String s = (String) e.nextElement();
|
||||
|
||||
if (!params.contains(s)) {
|
||||
|
|
@ -183,7 +197,7 @@ public class Cas20ProxyReceivingTicketValidationFilter extends AbstractTicketVal
|
|||
* This processes the ProxyReceptor request before the ticket validation code executes.
|
||||
*/
|
||||
protected final boolean preFilter(final ServletRequest servletRequest, final ServletResponse servletResponse,
|
||||
final FilterChain filterChain) throws IOException, ServletException {
|
||||
final FilterChain filterChain) throws IOException, ServletException {
|
||||
final HttpServletRequest request = (HttpServletRequest) servletRequest;
|
||||
final HttpServletResponse response = (HttpServletResponse) servletResponse;
|
||||
final String requestUri = request.getRequestURI();
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
*/
|
||||
package org.jasig.cas.client.validation;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import org.jasig.cas.client.util.XmlUtils;
|
||||
|
||||
|
|
@ -53,8 +54,22 @@ public class Cas20ProxyTicketValidator extends Cas20ServiceTicketValidator {
|
|||
throws TicketValidationException {
|
||||
final List<String> proxies = XmlUtils.getTextForElements(response, "proxy");
|
||||
|
||||
if (proxies == null) {
|
||||
throw new InvalidProxyChainTicketValidationException(
|
||||
"Invalid proxy chain: No proxy could be retrieved from response. "
|
||||
+ "This indicates a problem with CAS validation. Review logs/configuration to find the root cause."
|
||||
);
|
||||
}
|
||||
// this means there was nothing in the proxy chain, which is okay
|
||||
if ((this.allowEmptyProxyChain && proxies.isEmpty()) || this.acceptAnyProxy) {
|
||||
if ((this.allowEmptyProxyChain && proxies.isEmpty())) {
|
||||
logger.debug("Found an empty proxy chain, permitted by client configuration");
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.acceptAnyProxy) {
|
||||
logger.debug("Client configuration accepts any proxy. "
|
||||
+ "It is generally dangerous to use a non-proxied CAS filter "
|
||||
+ "specially for protecting resources that require proxy access.");
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -63,6 +78,10 @@ public class Cas20ProxyTicketValidator extends Cas20ServiceTicketValidator {
|
|||
return;
|
||||
}
|
||||
|
||||
logger.warn("Proxies received from the CAS validation response are {}. "
|
||||
+ "However, none are allowed by allowed proxy chain of the client which is {}",
|
||||
Arrays.toString(proxiedList), this.allowedProxyChains);
|
||||
|
||||
throw new InvalidProxyChainTicketValidationException("Invalid proxy chain: " + proxies.toString());
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@ public class Cas20ServiceTicketValidator extends AbstractCasProtocolUrlBasedTick
|
|||
* @param urlParameters the Map containing the existing parameters to send to the server.
|
||||
*/
|
||||
protected final void populateUrlAttributeMap(final Map<String, String> urlParameters) {
|
||||
urlParameters.put("pgtUrl", encodeUrl(this.proxyCallbackUrl));
|
||||
urlParameters.put("pgtUrl", this.proxyCallbackUrl);
|
||||
}
|
||||
|
||||
protected String getUrlSuffix() {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* 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.validation;
|
||||
|
||||
import org.jasig.cas.client.Protocol;
|
||||
|
||||
/**
|
||||
* Creates either a Cas30ProxyTicketValidator or a Cas30ServiceTicketValidator depending on whether any of the
|
||||
* proxy parameters are set.
|
||||
* <p/>
|
||||
* This filter can also pass additional parameters to the ticket validator. Any init parameter not included in the
|
||||
* reserved list {@link org.jasig.cas.client.validation.Cas20ProxyReceivingTicketValidationFilter#RESERVED_INIT_PARAMS}.
|
||||
*
|
||||
* @author Jerome Leleu
|
||||
* @since 3.4.0
|
||||
*/
|
||||
public class Cas30ProxyReceivingTicketValidationFilter extends Cas20ProxyReceivingTicketValidationFilter {
|
||||
|
||||
public Cas30ProxyReceivingTicketValidationFilter() {
|
||||
super(Protocol.CAS3);
|
||||
this.defaultServiceTicketValidatorClass = Cas30ServiceTicketValidator.class;
|
||||
this.defaultProxyTicketValidatorClass = Cas30ProxyTicketValidator.class;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* 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.validation;
|
||||
|
||||
/**
|
||||
* Service and proxy tickets validation service for the CAS protocol v3.
|
||||
*
|
||||
* @author Jerome Leleu
|
||||
* @since 3.4.0
|
||||
*/
|
||||
public class Cas30ProxyTicketValidator extends Cas20ProxyTicketValidator {
|
||||
|
||||
public Cas30ProxyTicketValidator(final String casServerUrlPrefix) {
|
||||
super(casServerUrlPrefix);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getUrlSuffix() {
|
||||
return "p3/proxyValidate";
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* 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.validation;
|
||||
|
||||
/**
|
||||
* Service tickets validation service for the CAS protocol v3.
|
||||
*
|
||||
* @author Jerome Leleu
|
||||
* @since 3.4.0
|
||||
*/
|
||||
public class Cas30ServiceTicketValidator extends Cas20ServiceTicketValidator {
|
||||
|
||||
public Cas30ServiceTicketValidator(String casServerUrlPrefix) {
|
||||
super(casServerUrlPrefix);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getUrlSuffix() {
|
||||
return "p3/serviceValidate";
|
||||
}
|
||||
}
|
||||
|
|
@ -64,7 +64,7 @@ public final class ProxyList {
|
|||
this(new ArrayList<String[]>());
|
||||
}
|
||||
|
||||
public boolean contains(String[] proxiedList) {
|
||||
public boolean contains(final String[] proxiedList) {
|
||||
StringBuilder loggingOutput;
|
||||
|
||||
for (final List<UrlPatternMatcherStrategy> proxyChain : this.proxyChains) {
|
||||
|
|
|
|||
|
|
@ -1,288 +0,0 @@
|
|||
/*
|
||||
* 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.validation;
|
||||
|
||||
import java.io.*;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.*;
|
||||
import org.jasig.cas.client.authentication.AttributePrincipal;
|
||||
import org.jasig.cas.client.authentication.AttributePrincipalImpl;
|
||||
import org.jasig.cas.client.util.CommonUtils;
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.DateTimeZone;
|
||||
import org.joda.time.Interval;
|
||||
import org.opensaml.Configuration;
|
||||
import org.opensaml.DefaultBootstrap;
|
||||
import org.opensaml.common.IdentifierGenerator;
|
||||
import org.opensaml.common.impl.SecureRandomIdentifierGenerator;
|
||||
import org.opensaml.saml1.core.*;
|
||||
import org.opensaml.ws.soap.soap11.Envelope;
|
||||
import org.opensaml.xml.ConfigurationException;
|
||||
import org.opensaml.xml.io.Unmarshaller;
|
||||
import org.opensaml.xml.io.UnmarshallerFactory;
|
||||
import org.opensaml.xml.io.UnmarshallingException;
|
||||
import org.opensaml.xml.parse.BasicParserPool;
|
||||
import org.opensaml.xml.parse.XMLParserException;
|
||||
import org.opensaml.xml.schema.XSAny;
|
||||
import org.opensaml.xml.schema.XSString;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
/**
|
||||
* TicketValidator that can understand validating a SAML artifact. This includes the SOAP request/response.
|
||||
*
|
||||
* @author Scott Battaglia
|
||||
* @since 3.1
|
||||
*/
|
||||
public final class Saml11TicketValidator extends AbstractUrlBasedTicketValidator {
|
||||
|
||||
static {
|
||||
try {
|
||||
// we really only need to do this once, so this is why its here.
|
||||
DefaultBootstrap.bootstrap();
|
||||
} catch (final ConfigurationException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/** Time tolerance to allow for time drifting. */
|
||||
private long tolerance = 1000L;
|
||||
|
||||
private final BasicParserPool basicParserPool;
|
||||
|
||||
private final IdentifierGenerator identifierGenerator;
|
||||
|
||||
public Saml11TicketValidator(final String casServerUrlPrefix) {
|
||||
super(casServerUrlPrefix);
|
||||
this.basicParserPool = new BasicParserPool();
|
||||
this.basicParserPool.setNamespaceAware(true);
|
||||
|
||||
try {
|
||||
this.identifierGenerator = new SecureRandomIdentifierGenerator();
|
||||
} catch (final Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
protected String getUrlSuffix() {
|
||||
return "samlValidate";
|
||||
}
|
||||
|
||||
protected void populateUrlAttributeMap(final Map<String, String> urlParameters) {
|
||||
final String service = urlParameters.get("service");
|
||||
urlParameters.remove("service");
|
||||
urlParameters.remove("ticket");
|
||||
urlParameters.put("TARGET", service);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setDisableXmlSchemaValidation(final boolean disabled) {
|
||||
if (disabled) {
|
||||
this.basicParserPool.setSchema(null);
|
||||
}
|
||||
}
|
||||
|
||||
protected byte[] getBytes(final String text) {
|
||||
try {
|
||||
return CommonUtils.isNotBlank(getEncoding()) ? text.getBytes(getEncoding()) : text.getBytes();
|
||||
} catch (final Exception e) {
|
||||
return text.getBytes();
|
||||
}
|
||||
}
|
||||
|
||||
protected Assertion parseResponseFromServer(final String response) throws TicketValidationException {
|
||||
try {
|
||||
|
||||
final Document responseDocument = this.basicParserPool.parse(new ByteArrayInputStream(getBytes(response)));
|
||||
final Element responseRoot = responseDocument.getDocumentElement();
|
||||
final UnmarshallerFactory unmarshallerFactory = Configuration.getUnmarshallerFactory();
|
||||
final Unmarshaller unmarshaller = unmarshallerFactory.getUnmarshaller(responseRoot);
|
||||
final Envelope envelope = (Envelope) unmarshaller.unmarshall(responseRoot);
|
||||
final Response samlResponse = (Response) envelope.getBody().getOrderedChildren().get(0);
|
||||
|
||||
final List<org.opensaml.saml1.core.Assertion> assertions = samlResponse.getAssertions();
|
||||
if (assertions.isEmpty()) {
|
||||
throw new TicketValidationException("No assertions found.");
|
||||
}
|
||||
|
||||
for (final org.opensaml.saml1.core.Assertion assertion : assertions) {
|
||||
|
||||
if (!isValidAssertion(assertion)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
final AuthenticationStatement authenticationStatement = getSAMLAuthenticationStatement(assertion);
|
||||
|
||||
if (authenticationStatement == null) {
|
||||
throw new TicketValidationException("No AuthentiationStatement found in SAML Assertion.");
|
||||
}
|
||||
final Subject subject = authenticationStatement.getSubject();
|
||||
|
||||
if (subject == null) {
|
||||
throw new TicketValidationException("No Subject found in SAML Assertion.");
|
||||
}
|
||||
|
||||
final List<Attribute> attributes = getAttributesFor(assertion, subject);
|
||||
final Map<String, Object> personAttributes = new HashMap<String, Object>();
|
||||
for (final Attribute samlAttribute : attributes) {
|
||||
final List<?> values = getValuesFrom(samlAttribute);
|
||||
|
||||
personAttributes.put(samlAttribute.getAttributeName(), values.size() == 1 ? values.get(0) : values);
|
||||
}
|
||||
|
||||
final AttributePrincipal principal = new AttributePrincipalImpl(subject.getNameIdentifier()
|
||||
.getNameIdentifier(), personAttributes);
|
||||
|
||||
final Map<String, Object> authenticationAttributes = new HashMap<String, Object>();
|
||||
authenticationAttributes.put("samlAuthenticationStatement::authMethod",
|
||||
authenticationStatement.getAuthenticationMethod());
|
||||
|
||||
final DateTime notBefore = assertion.getConditions().getNotBefore();
|
||||
final DateTime notOnOrAfter = assertion.getConditions().getNotOnOrAfter();
|
||||
final DateTime authenticationInstant = authenticationStatement.getAuthenticationInstant();
|
||||
return new AssertionImpl(principal, notBefore.toDate(), notOnOrAfter.toDate(),
|
||||
authenticationInstant.toDate(), authenticationAttributes);
|
||||
}
|
||||
} catch (final UnmarshallingException e) {
|
||||
throw new TicketValidationException(e);
|
||||
} catch (final XMLParserException e) {
|
||||
throw new TicketValidationException(e);
|
||||
}
|
||||
|
||||
throw new TicketValidationException(
|
||||
"No Assertion found within valid time range. Either there's a replay of the ticket or there's clock drift. Check tolerance range, or server/client synchronization.");
|
||||
}
|
||||
|
||||
private boolean isValidAssertion(final org.opensaml.saml1.core.Assertion assertion) {
|
||||
final DateTime notBefore = assertion.getConditions().getNotBefore();
|
||||
final DateTime notOnOrAfter = assertion.getConditions().getNotOnOrAfter();
|
||||
|
||||
if (notBefore == null || notOnOrAfter == null) {
|
||||
logger.debug("Assertion has no bounding dates. Will not process.");
|
||||
return false;
|
||||
}
|
||||
|
||||
final DateTime currentTime = new DateTime(DateTimeZone.UTC);
|
||||
final Interval validityRange = new Interval(notBefore.minus(this.tolerance), notOnOrAfter.plus(this.tolerance));
|
||||
|
||||
if (validityRange.contains(currentTime)) {
|
||||
logger.debug("Current time is within the interval validity.");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (currentTime.isBefore(validityRange.getStart())) {
|
||||
logger.debug("skipping assertion that's not yet valid...");
|
||||
return false;
|
||||
}
|
||||
|
||||
logger.debug("skipping expired assertion...");
|
||||
return false;
|
||||
}
|
||||
|
||||
private AuthenticationStatement getSAMLAuthenticationStatement(final org.opensaml.saml1.core.Assertion assertion) {
|
||||
final List<AuthenticationStatement> statements = assertion.getAuthenticationStatements();
|
||||
|
||||
if (statements.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return statements.get(0);
|
||||
}
|
||||
|
||||
private List<Attribute> getAttributesFor(final org.opensaml.saml1.core.Assertion assertion, final Subject subject) {
|
||||
final List<Attribute> attributes = new ArrayList<Attribute>();
|
||||
for (final AttributeStatement attribute : assertion.getAttributeStatements()) {
|
||||
if (subject.getNameIdentifier().getNameIdentifier()
|
||||
.equals(attribute.getSubject().getNameIdentifier().getNameIdentifier())) {
|
||||
attributes.addAll(attribute.getAttributes());
|
||||
}
|
||||
}
|
||||
|
||||
return attributes;
|
||||
}
|
||||
|
||||
private List<?> getValuesFrom(final Attribute attribute) {
|
||||
final List<Object> list = new ArrayList<Object>();
|
||||
for (final Object o : attribute.getAttributeValues()) {
|
||||
if (o instanceof XSAny) {
|
||||
list.add(((XSAny) o).getTextContent());
|
||||
} else if (o instanceof XSString) {
|
||||
list.add(((XSString) o).getValue());
|
||||
} else {
|
||||
list.add(o.toString());
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
protected String retrieveResponseFromServer(final URL validationUrl, final String ticket) {
|
||||
final String MESSAGE_TO_SEND = "<SOAP-ENV:Envelope xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\"><SOAP-ENV:Header/><SOAP-ENV:Body><samlp:Request xmlns:samlp=\"urn:oasis:names:tc:SAML:1.0:protocol\" MajorVersion=\"1\" MinorVersion=\"1\" RequestID=\""
|
||||
+ this.identifierGenerator.generateIdentifier()
|
||||
+ "\" IssueInstant=\""
|
||||
+ CommonUtils.formatForUtcTime(new Date())
|
||||
+ "\">"
|
||||
+ "<samlp:AssertionArtifact>"
|
||||
+ ticket
|
||||
+ "</samlp:AssertionArtifact></samlp:Request></SOAP-ENV:Body></SOAP-ENV:Envelope>";
|
||||
HttpURLConnection conn = null;
|
||||
DataOutputStream out = null;
|
||||
BufferedReader in = null;
|
||||
|
||||
try {
|
||||
conn = this.getURLConnectionFactory().buildHttpURLConnection(validationUrl.openConnection());
|
||||
conn.setRequestMethod("POST");
|
||||
conn.setRequestProperty("Content-Type", "text/xml");
|
||||
conn.setRequestProperty("Content-Length", Integer.toString(MESSAGE_TO_SEND.length()));
|
||||
conn.setRequestProperty("SOAPAction", "http://www.oasis-open.org/committees/security");
|
||||
conn.setUseCaches(false);
|
||||
conn.setDoInput(true);
|
||||
conn.setDoOutput(true);
|
||||
|
||||
out = new DataOutputStream(conn.getOutputStream());
|
||||
out.writeBytes(MESSAGE_TO_SEND);
|
||||
out.flush();
|
||||
|
||||
in = new BufferedReader(CommonUtils.isNotBlank(getEncoding()) ? new InputStreamReader(
|
||||
conn.getInputStream(), Charset.forName(getEncoding())) : new InputStreamReader(
|
||||
conn.getInputStream()));
|
||||
final StringBuilder buffer = new StringBuilder(256);
|
||||
|
||||
String line;
|
||||
|
||||
while ((line = in.readLine()) != null) {
|
||||
buffer.append(line);
|
||||
}
|
||||
return buffer.toString();
|
||||
} catch (final IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
} finally {
|
||||
CommonUtils.closeQuietly(out);
|
||||
CommonUtils.closeQuietly(in);
|
||||
if (conn != null) {
|
||||
conn.disconnect();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setTolerance(final long tolerance) {
|
||||
this.tolerance = tolerance;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns="urn:oasis:names:tc:SAML:1.0:protocol">
|
||||
<soap:Header/>
|
||||
<soap:Body>
|
||||
<Request MajorVersion="1" MinorVersion="1" RequestID="%s" IssueInstant="%s">
|
||||
<AssertionArtifact>%s</AssertionArtifact>
|
||||
</Request>
|
||||
</soap:Body>
|
||||
</soap:Envelope>
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* 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.configuration;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
public final class ConfigurationKeyTests {
|
||||
|
||||
|
||||
@Test
|
||||
public void gettersWithNoDefaultValue() {
|
||||
final String name = "name";
|
||||
final ConfigurationKey<Boolean> configurationKey = new ConfigurationKey<Boolean>(name);
|
||||
assertEquals(name, configurationKey.getName());
|
||||
assertNull(configurationKey.getDefaultValue());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void gettersWithDefaultValue() {
|
||||
final String name = "name";
|
||||
final Boolean defaultValue = Boolean.TRUE;
|
||||
final ConfigurationKey<Boolean> configurationKey = new ConfigurationKey<Boolean>(name, defaultValue);
|
||||
assertEquals(name, configurationKey.getName());
|
||||
assertEquals(defaultValue, configurationKey.getDefaultValue());
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* 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.configuration;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
public final class ConfigurationStrategyNameTests {
|
||||
|
||||
@Test
|
||||
public void stringToClass() {
|
||||
assertEquals(JndiConfigurationStrategyImpl.class, ConfigurationStrategyName.resolveToConfigurationStrategy(ConfigurationStrategyName.JNDI.name()));
|
||||
assertEquals(WebXmlConfigurationStrategyImpl.class, ConfigurationStrategyName.resolveToConfigurationStrategy(ConfigurationStrategyName.WEB_XML.name()));
|
||||
assertEquals(PropertiesConfigurationStrategyImpl.class, ConfigurationStrategyName.resolveToConfigurationStrategy(ConfigurationStrategyName.PROPERTY_FILE.name()));
|
||||
assertEquals(SystemPropertiesConfigurationStrategyImpl.class, ConfigurationStrategyName.resolveToConfigurationStrategy(ConfigurationStrategyName.SYSTEM_PROPERTIES.name()));
|
||||
assertEquals(LegacyConfigurationStrategyImpl.class, ConfigurationStrategyName.resolveToConfigurationStrategy(ConfigurationStrategyName.DEFAULT.name()));
|
||||
assertEquals(LegacyConfigurationStrategyImpl.class, ConfigurationStrategyName.resolveToConfigurationStrategy("bleh!"));
|
||||
}
|
||||
}
|
||||
|
|
@ -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.configuration;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import org.jasig.cas.client.util.AbstractCasFilter;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.mock.web.MockFilterConfig;
|
||||
|
||||
/**
|
||||
* Tests {@link SystemPropertiesConfigurationStrategyImpl}.
|
||||
*
|
||||
* @author Jerome Leleu
|
||||
* @since 3.4.0
|
||||
*/
|
||||
public class SystemPropertiesConfigurationStrategyImplTests {
|
||||
|
||||
private final static String PARAMETER_NAME = "parameter";
|
||||
|
||||
private SystemPropertiesConfigurationStrategyImpl impl;
|
||||
|
||||
private MockFilterConfig filterConfig;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
this.filterConfig = new MockFilterConfig();
|
||||
this.impl = new SystemPropertiesConfigurationStrategyImpl();
|
||||
this.impl.init(this.filterConfig, AbstractCasFilter.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNoSystemPropertyDefined() {
|
||||
final ConfigurationKey<String> key = ConfigurationKeys.SERVER_NAME;
|
||||
// no system property defined
|
||||
assertEquals(key.getDefaultValue(), impl.getString(key));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWithSystemProperty() {
|
||||
final ConfigurationKey<String> key = ConfigurationKeys.ARTIFACT_PARAMETER_NAME;
|
||||
System.setProperty(key.getName(), PARAMETER_NAME);
|
||||
assertEquals(PARAMETER_NAME, impl.getString(key));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,145 @@
|
|||
/*
|
||||
* 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.configuration;
|
||||
|
||||
import org.jasig.cas.client.util.AbstractCasFilter;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.mock.web.MockFilterConfig;
|
||||
import org.springframework.mock.web.MockServletContext;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
public final class WebXmlConfigurationStrategyImplTests {
|
||||
|
||||
private WebXmlConfigurationStrategyImpl impl;
|
||||
|
||||
private MockFilterConfig filterConfig;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
this.filterConfig = new MockFilterConfig();
|
||||
this.impl = new WebXmlConfigurationStrategyImpl();
|
||||
this.impl.init(this.filterConfig, AbstractCasFilter.class);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void noKeyFoundGetDefaultForBoolean() {
|
||||
final ConfigurationKey<Boolean> key = ConfigurationKeys.ACCEPT_ANY_PROXY;
|
||||
assertEquals(key.getDefaultValue(), this.impl.getBoolean(key));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void noKeyFoundGetDefaultForString() {
|
||||
final ConfigurationKey<String> key = ConfigurationKeys.ARTIFACT_PARAMETER_NAME;
|
||||
assertEquals(key.getDefaultValue(), this.impl.getString(key));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void noKeyFoundGetDefaultForLong() {
|
||||
final ConfigurationKey<Long> key = ConfigurationKeys.TOLERANCE;
|
||||
assertEquals(key.getDefaultValue().longValue(), this.impl.getLong(key));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void noKeyFoundGetDefaultForInt() {
|
||||
final ConfigurationKey<Integer> key = ConfigurationKeys.MILLIS_BETWEEN_CLEAN_UPS;
|
||||
assertEquals(key.getDefaultValue().intValue(), this.impl.getInt(key));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void filterConfigValueForBoolean() {
|
||||
final ConfigurationKey<Boolean> key = ConfigurationKeys.ACCEPT_ANY_PROXY;
|
||||
final Boolean value = Boolean.TRUE;
|
||||
this.filterConfig.addInitParameter(key.getName(), value.toString());
|
||||
assertEquals(value, this.impl.getBoolean(key));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void filterConfigValueForString() {
|
||||
final ConfigurationKey<String> key = ConfigurationKeys.ARTIFACT_PARAMETER_NAME;
|
||||
final String value = "foobar";
|
||||
this.filterConfig.addInitParameter(key.getName(), value);
|
||||
assertEquals(value, this.impl.getString(key));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void filterConfigValueForLong() {
|
||||
final ConfigurationKey<Long> key = ConfigurationKeys.TOLERANCE;
|
||||
final long value = 1500;
|
||||
this.filterConfig.addInitParameter(key.getName(), Long.toString(value));
|
||||
assertEquals(value, this.impl.getLong(key));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void filterConfigValueForInt() {
|
||||
final ConfigurationKey<Integer> key = ConfigurationKeys.MILLIS_BETWEEN_CLEAN_UPS;
|
||||
final int value = 1500;
|
||||
this.filterConfig.addInitParameter(key.getName(), Integer.toString(value));
|
||||
assertEquals(value, this.impl.getInt(key));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void servletConfigValueForBoolean() {
|
||||
final ConfigurationKey<Boolean> key = ConfigurationKeys.ACCEPT_ANY_PROXY;
|
||||
final Boolean value = Boolean.TRUE;
|
||||
final MockServletContext context = (MockServletContext) this.filterConfig.getServletContext();
|
||||
context.addInitParameter(key.getName(), value.toString());
|
||||
assertEquals(value, this.impl.getBoolean(key));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void servletConfigValueForString() {
|
||||
final ConfigurationKey<String> key = ConfigurationKeys.ARTIFACT_PARAMETER_NAME;
|
||||
final String value = "foobar";
|
||||
final MockServletContext context = (MockServletContext) this.filterConfig.getServletContext();
|
||||
context.addInitParameter(key.getName(), value);
|
||||
assertEquals(value, this.impl.getString(key));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void servletConfigValueForLong() {
|
||||
final ConfigurationKey<Long> key = ConfigurationKeys.TOLERANCE;
|
||||
final long value = 1500;
|
||||
final MockServletContext context = (MockServletContext) this.filterConfig.getServletContext();
|
||||
context.addInitParameter(key.getName(), Long.toString(value));
|
||||
assertEquals(value, this.impl.getLong(key));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void servletConfigValueForInt() {
|
||||
final ConfigurationKey<Integer> key = ConfigurationKeys.MILLIS_BETWEEN_CLEAN_UPS;
|
||||
final int value = 1500;
|
||||
final MockServletContext context = (MockServletContext) this.filterConfig.getServletContext();
|
||||
context.addInitParameter(key.getName(), Integer.toString(value));
|
||||
assertEquals(value, this.impl.getInt(key));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,3 +1,21 @@
|
|||
/*
|
||||
* 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.session;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
|
|
|
|||
|
|
@ -25,6 +25,8 @@ import java.io.IOException;
|
|||
|
||||
import javax.servlet.ServletException;
|
||||
|
||||
import org.jasig.cas.client.Protocol;
|
||||
import org.jasig.cas.client.configuration.ConfigurationKeys;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.mock.web.MockFilterChain;
|
||||
|
|
@ -35,12 +37,12 @@ import org.springframework.mock.web.MockHttpSession;
|
|||
|
||||
/**
|
||||
* Tests {@link SingleSignOutFilter}.
|
||||
*
|
||||
*
|
||||
* @author Jerome Leleu
|
||||
* @since 3.3.1
|
||||
*/
|
||||
public class SingleSignOutFilterTests {
|
||||
|
||||
|
||||
private final static String CAS_SERVER_URL_PREFIX = "http://myhost.com/mycasserver";
|
||||
private final static String TICKET = "ST-yyyyy";
|
||||
private final static String RELAY_STATE = "e1s1";
|
||||
|
|
@ -49,7 +51,7 @@ public class SingleSignOutFilterTests {
|
|||
private MockHttpServletRequest request;
|
||||
private MockHttpServletResponse response;
|
||||
private MockFilterChain filterChain;
|
||||
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
filter = new SingleSignOutFilter();
|
||||
|
|
@ -61,16 +63,10 @@ public class SingleSignOutFilterTests {
|
|||
filterChain = new MockFilterChain();
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void initWithoutCasServerUrlPrefix() throws ServletException {
|
||||
filter = new SingleSignOutFilter();
|
||||
filter.init(new MockFilterConfig());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void tokenRequest() throws IOException, ServletException {
|
||||
request.setParameter(SingleSignOutHandler.DEFAULT_ARTIFACT_PARAMETER_NAME, TICKET);
|
||||
request.setQueryString(SingleSignOutHandler.DEFAULT_ARTIFACT_PARAMETER_NAME + "=" + TICKET);
|
||||
request.setParameter(Protocol.CAS2.getArtifactParameterName(), TICKET);
|
||||
request.setQueryString(Protocol.CAS2.getArtifactParameterName() + "=" + TICKET);
|
||||
final MockHttpSession session = new MockHttpSession();
|
||||
request.setSession(session);
|
||||
filter.doFilter(request, response, filterChain);
|
||||
|
|
@ -79,7 +75,7 @@ public class SingleSignOutFilterTests {
|
|||
|
||||
@Test
|
||||
public void backChannelRequest() throws IOException, ServletException {
|
||||
request.setParameter(SingleSignOutHandler.DEFAULT_LOGOUT_PARAMETER_NAME,
|
||||
request.setParameter(ConfigurationKeys.LOGOUT_PARAMETER_NAME.getDefaultValue(),
|
||||
LogoutMessageGenerator.generateBackChannelLogoutMessage(TICKET));
|
||||
request.setMethod("POST");
|
||||
final MockHttpSession session = new MockHttpSession();
|
||||
|
|
@ -91,8 +87,8 @@ public class SingleSignOutFilterTests {
|
|||
@Test
|
||||
public void frontChannelRequest() throws IOException, ServletException {
|
||||
final String logoutMessage = LogoutMessageGenerator.generateFrontChannelLogoutMessage(TICKET);
|
||||
request.setParameter(SingleSignOutHandler.DEFAULT_FRONT_LOGOUT_PARAMETER_NAME, logoutMessage);
|
||||
request.setQueryString(SingleSignOutHandler.DEFAULT_FRONT_LOGOUT_PARAMETER_NAME + "=" + logoutMessage);
|
||||
request.setParameter(ConfigurationKeys.FRONT_LOGOUT_PARAMETER_NAME.getDefaultValue(), logoutMessage);
|
||||
request.setQueryString(ConfigurationKeys.FRONT_LOGOUT_PARAMETER_NAME.getDefaultValue() + "=" + logoutMessage);
|
||||
request.setMethod("GET");
|
||||
final MockHttpSession session = new MockHttpSession();
|
||||
SingleSignOutFilter.getSingleSignOutHandler().getSessionMappingStorage().addSessionById(TICKET, session);
|
||||
|
|
@ -104,16 +100,16 @@ public class SingleSignOutFilterTests {
|
|||
@Test
|
||||
public void frontChannelRequestRelayState() throws IOException, ServletException {
|
||||
final String logoutMessage = LogoutMessageGenerator.generateFrontChannelLogoutMessage(TICKET);
|
||||
request.setParameter(SingleSignOutHandler.DEFAULT_FRONT_LOGOUT_PARAMETER_NAME, logoutMessage);
|
||||
request.setParameter(SingleSignOutHandler.DEFAULT_RELAY_STATE_PARAMETER_NAME, RELAY_STATE);
|
||||
request.setQueryString(SingleSignOutHandler.DEFAULT_FRONT_LOGOUT_PARAMETER_NAME + "=" + logoutMessage + "&" +
|
||||
SingleSignOutHandler.DEFAULT_RELAY_STATE_PARAMETER_NAME + "=" + RELAY_STATE);
|
||||
request.setParameter(ConfigurationKeys.FRONT_LOGOUT_PARAMETER_NAME.getDefaultValue(), logoutMessage);
|
||||
request.setParameter(ConfigurationKeys.RELAY_STATE_PARAMETER_NAME.getDefaultValue(), RELAY_STATE);
|
||||
request.setQueryString(ConfigurationKeys.FRONT_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&" +
|
||||
SingleSignOutHandler.DEFAULT_RELAY_STATE_PARAMETER_NAME + "=" + RELAY_STATE, response.getRedirectedUrl());
|
||||
ConfigurationKeys.RELAY_STATE_PARAMETER_NAME.getDefaultValue() + "=" + RELAY_STATE, response.getRedirectedUrl());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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.ssl;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
public final class HttpsURLConnectionFactoryTests {
|
||||
|
||||
private HttpsURLConnectionFactory httpsURLConnectionFactory;
|
||||
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
this.httpsURLConnectionFactory = new HttpsURLConnectionFactory();
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void serializeAndDeserialize() throws Exception {
|
||||
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
final ObjectOutputStream oos = new ObjectOutputStream(baos);
|
||||
|
||||
oos.writeObject(this.httpsURLConnectionFactory);
|
||||
oos.close();
|
||||
|
||||
final byte[] serializedHttpsUrlConnectionFactory = baos.toByteArray();
|
||||
|
||||
final ByteArrayInputStream bais = new ByteArrayInputStream(serializedHttpsUrlConnectionFactory);
|
||||
final ObjectInputStream ois = new ObjectInputStream(bais);
|
||||
|
||||
final HttpsURLConnectionFactory deserializedObject = (HttpsURLConnectionFactory) ois.readObject();
|
||||
assertEquals(this.httpsURLConnectionFactory, deserializedObject);
|
||||
}
|
||||
}
|
||||
|
|
@ -43,7 +43,7 @@ import junit.framework.TestCase;
|
|||
*/
|
||||
public class WhitelistHostnameVerifierTests extends TestCase {
|
||||
/**
|
||||
* Test method for {@link WhitelistHostnameVerifier#verify(String, SSLSession)}.
|
||||
* Test method for {@link WhitelistHostnameVerifier#verify(String, javax.net.ssl.SSLSession)}.
|
||||
*/
|
||||
public void testVerify() {
|
||||
final WhitelistHostnameVerifier verifier = new WhitelistHostnameVerifier("red.vt.edu, green.vt.edu,blue.vt.edu");
|
||||
|
|
|
|||
|
|
@ -24,6 +24,8 @@ import javax.servlet.FilterChain;
|
|||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
|
||||
import org.jasig.cas.client.Protocol;
|
||||
import org.junit.Test;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.mock.web.MockHttpServletResponse;
|
||||
|
|
@ -55,6 +57,10 @@ public final class CasFilterTests {
|
|||
}
|
||||
|
||||
private static class TestCasFilter extends AbstractCasFilter {
|
||||
|
||||
public TestCasFilter() {
|
||||
super(Protocol.CAS2);
|
||||
}
|
||||
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException,
|
||||
ServletException {
|
||||
// nothing to do
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ package org.jasig.cas.client.util;
|
|||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
import org.jasig.cas.client.PublicTestHttpServer;
|
||||
import org.jasig.cas.client.ssl.HttpsURLConnectionFactory;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* 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.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.mock.web.MockFilterChain;
|
||||
import org.springframework.mock.web.MockFilterConfig;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.mock.web.MockHttpServletResponse;
|
||||
|
||||
import javax.servlet.FilterChain;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
public final class ErrorRedirectFilterTests {
|
||||
|
||||
private static final String REDIRECT_URL = "/ise.html";
|
||||
|
||||
private ErrorRedirectFilter errorRedirectFilter;
|
||||
|
||||
private FilterChain filterChain;
|
||||
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
this.errorRedirectFilter = new ErrorRedirectFilter();
|
||||
|
||||
final MockFilterConfig filterConfig = new MockFilterConfig();
|
||||
filterConfig.addInitParameter(IllegalStateException.class.getName(), REDIRECT_URL);
|
||||
this.errorRedirectFilter.init(filterConfig);
|
||||
this.filterChain = new MockFilterChain();
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void noRootCause() throws Exception {
|
||||
final MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
final MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
|
||||
// this should be okay as the mock filter chain allows one call
|
||||
this.errorRedirectFilter.doFilter(request, response, this.filterChain);
|
||||
|
||||
// this will fail as the mock filter chain will throw IllegalStateException
|
||||
this.errorRedirectFilter.doFilter(request, response, this.filterChain);
|
||||
|
||||
assertEquals(REDIRECT_URL, response.getRedirectedUrl());
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -50,7 +50,10 @@ public class Cas10TicketValidationFilterTests {
|
|||
final MockServletContext context = new MockServletContext();
|
||||
context.addInitParameter("casServerUrlPrefix", "https://cas.example.com");
|
||||
context.addInitParameter("renew", "true");
|
||||
final TicketValidator validator = f.getTicketValidator(new MockFilterConfig(context));
|
||||
context.addInitParameter("service", "http://www.jasig.org");
|
||||
final MockFilterConfig config = new MockFilterConfig(context);
|
||||
f.init(config);
|
||||
final TicketValidator validator = f.getTicketValidator(config);
|
||||
assertTrue(validator instanceof Cas10TicketValidator);
|
||||
assertTrue(((Cas10TicketValidator) validator).isRenew());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,8 +18,7 @@
|
|||
*/
|
||||
package org.jasig.cas.client.validation;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.fail;
|
||||
import static org.junit.Assert.*;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import org.jasig.cas.client.PublicTestHttpServer;
|
||||
import org.junit.Before;
|
||||
|
|
@ -80,4 +79,15 @@ public final class Cas10TicketValidatorTests extends AbstractTicketValidatorTest
|
|||
// expected
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void urlEncodedValues() {
|
||||
final String ticket = "ST-1-owKEOtYJjg77iHcCQpkl-cas01.example.org%26%73%65%72%76%69%63%65%3d%68%74%74%70%25%33%41%25%32%46%25%32%46%31%32%37%2e%30%2e%30%2e%31%25%32%46%62%6f%72%69%6e%67%25%32%46%23";
|
||||
final String service = "foobar";
|
||||
final String url = this.ticketValidator.constructValidationUrl(ticket, service);
|
||||
|
||||
final String encodedValue = this.ticketValidator.encodeUrl(ticket);
|
||||
assertTrue(url.contains(encodedValue));
|
||||
assertFalse(url.contains(ticket));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ import org.jasig.cas.client.proxy.CleanUpTimerTask;
|
|||
import org.jasig.cas.client.proxy.ProxyGrantingTicketStorage;
|
||||
import org.jasig.cas.client.proxy.ProxyGrantingTicketStorageImpl;
|
||||
import org.jasig.cas.client.util.MethodFlag;
|
||||
import org.junit.Test;
|
||||
import org.springframework.mock.web.MockFilterConfig;
|
||||
import org.springframework.mock.web.MockServletContext;
|
||||
|
||||
|
|
@ -148,32 +149,40 @@ public class Cas20ProxyReceivingTicketValidationFilterTests extends TestCase {
|
|||
|
||||
public void testGetTicketValidator() throws Exception {
|
||||
Cas20ProxyReceivingTicketValidationFilter filter = newCas20ProxyReceivingTicketValidationFilter();
|
||||
filter.setProxyGrantingTicketStorage(storage);
|
||||
filter.setMillisBetweenCleanUps(250);
|
||||
filter.setTimer(defaultTimer);
|
||||
filter.setTimerTask(new TimerTask() {
|
||||
public void run() {
|
||||
}
|
||||
});
|
||||
filter.init();
|
||||
|
||||
// Test case #1
|
||||
final MockFilterConfig config1 = new MockFilterConfig();
|
||||
config1.addInitParameter("allowedProxyChains", "https://a.example.com");
|
||||
config1.addInitParameter("casServerUrlPrefix", "https://cas.jasig.org/");
|
||||
config1.addInitParameter("service", "http://www.jasig.org");
|
||||
filter.init(config1);
|
||||
assertNotNull(filter.getTicketValidator(config1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getTicketValidatorWithProxyChains() throws Exception {
|
||||
Cas20ProxyReceivingTicketValidationFilter filter = newCas20ProxyReceivingTicketValidationFilter();
|
||||
// Test case #2
|
||||
final MockFilterConfig config2 = new MockFilterConfig();
|
||||
config2.addInitParameter("allowedProxyChains", "https://a.example.com https://b.example.com");
|
||||
config2.addInitParameter("casServerUrlPrefix", "https://cas.jasig.org/");
|
||||
config2.addInitParameter("service", "http://www.jasig.org");
|
||||
filter.init(config2);
|
||||
assertNotNull(filter.getTicketValidator(config2));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void getTIcketValidatorWithProxyChainsAndLineBreak() throws Exception {
|
||||
Cas20ProxyReceivingTicketValidationFilter filter = newCas20ProxyReceivingTicketValidationFilter();
|
||||
|
||||
// Test case #3
|
||||
final MockFilterConfig config3 = new MockFilterConfig();
|
||||
config3.addInitParameter("allowedProxyChains",
|
||||
"https://a.example.com https://b.example.com\nhttps://c.example.com");
|
||||
config3.addInitParameter("casServerUrlPrefix", "https://cas.jasig.org/");
|
||||
config3.addInitParameter("service", "http://www.jasig.org");
|
||||
filter.init(config3);
|
||||
assertNotNull(filter.getTicketValidator(config3));
|
||||
}
|
||||
|
||||
|
|
@ -195,7 +204,10 @@ public class Cas20ProxyReceivingTicketValidationFilterTests extends TestCase {
|
|||
final MockServletContext context = new MockServletContext();
|
||||
context.addInitParameter("casServerUrlPrefix", "https://cas.example.com");
|
||||
context.addInitParameter("renew", "true");
|
||||
final TicketValidator validator = f.getTicketValidator(new MockFilterConfig(context));
|
||||
context.addInitParameter("service", "http://www.jasig.org");
|
||||
final MockFilterConfig config = new MockFilterConfig(context);
|
||||
f.init(config);
|
||||
final TicketValidator validator = f.getTicketValidator(config);
|
||||
assertTrue(validator instanceof AbstractUrlBasedTicketValidator);
|
||||
assertTrue(((AbstractUrlBasedTicketValidator) validator).isRenew());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,13 +16,14 @@ specific language governing permissions and limitations
|
|||
under the License.
|
||||
|
||||
This project includes:
|
||||
"Java Concurrency in Practice" book annotations under Creative Commons Attribution License
|
||||
AOP alliance under Public Domain
|
||||
Apache Santuario under The Apache Software License, Version 2.0
|
||||
Apache Velocity under The Apache Software License, Version 2.0
|
||||
Atlassian Event under Atlassian End User License
|
||||
Atlassian JIRA - Code - Core under Atlassian End User License
|
||||
Atlassian Seraph under BSD License
|
||||
atlassian-osuser under BSD License
|
||||
Atlassian Seraph under Atlassian End User License
|
||||
atlassian-osuser under Atlassian End User License
|
||||
Bouncy Castle Provider under Bouncy Castle Licence
|
||||
Codec under The Apache Software License, Version 2.0
|
||||
commons-collections under Apache License, Version 2.0
|
||||
|
|
@ -33,7 +34,6 @@ This project includes:
|
|||
Jasig CAS Client for Java - Atlassian Integration under Apache License Version 2.0
|
||||
Jasig CAS Client for Java - Core under Apache License Version 2.0
|
||||
Java Servlet API under CDDL + GPLv2 with classpath exception
|
||||
jcip-annotations under Creative Commons Attribution License
|
||||
JCL 1.1.1 implemented over SLF4J under MIT License
|
||||
Joda time under Apache 2
|
||||
JUL to SLF4J bridge under MIT License
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<parent>
|
||||
<groupId>org.jasig.cas.client</groupId>
|
||||
<version>3.3.2-SNAPSHOT</version>
|
||||
<version>3.4.0-SNAPSHOT</version>
|
||||
<artifactId>cas-client</artifactId>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
|
@ -46,6 +46,11 @@
|
|||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-context</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<artifactId>atlassian-osuser</artifactId>
|
||||
<groupId>com.atlassian.osuser</groupId>
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ specific language governing permissions and limitations
|
|||
under the License.
|
||||
|
||||
This project includes:
|
||||
"Java Concurrency in Practice" book annotations under Creative Commons Attribution License
|
||||
Apache Santuario under The Apache Software License, Version 2.0
|
||||
Apache Velocity under The Apache Software License, Version 2.0
|
||||
Bouncy Castle Provider under Bouncy Castle Licence
|
||||
|
|
@ -27,7 +28,6 @@ This project includes:
|
|||
Jasig CAS Client for Java - JBoss Integration under Apache License Version 2.0
|
||||
Java Servlet API under CDDL + GPLv2 with classpath exception
|
||||
JBoss Application Server Tomcat under lgpl
|
||||
jcip-annotations under Creative Commons Attribution License
|
||||
JCL 1.1.1 implemented over SLF4J under MIT License
|
||||
Joda time under Apache 2
|
||||
JUL to SLF4J bridge under MIT License
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<parent>
|
||||
<groupId>org.jasig.cas.client</groupId>
|
||||
<version>3.3.2-SNAPSHOT</version>
|
||||
<version>3.4.0-SNAPSHOT</version>
|
||||
<artifactId>cas-client</artifactId>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* 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.configuration;
|
||||
|
||||
/**
|
||||
* Simple extension to the {@link org.jasig.cas.client.configuration.JndiConfigurationStrategyImpl} to provide a JBoss 7 compatible prefix.
|
||||
*
|
||||
* @author Scott Battaglia
|
||||
* @since 3.4.0
|
||||
*/
|
||||
public final class JBossCompatibleJndiConfigurationStrategyImpl extends JndiConfigurationStrategyImpl {
|
||||
|
||||
private static final String ENVIRONMENT_PREFIX = "java:/comp/env/cas/";
|
||||
|
||||
public JBossCompatibleJndiConfigurationStrategyImpl() {
|
||||
super(ENVIRONMENT_PREFIX);
|
||||
}
|
||||
}
|
||||
|
|
@ -27,6 +27,8 @@ import javax.servlet.ServletResponse;
|
|||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.http.HttpSession;
|
||||
|
||||
import org.jasig.cas.client.Protocol;
|
||||
import org.jasig.cas.client.jaas.AssertionPrincipal;
|
||||
import org.jasig.cas.client.util.AbstractCasFilter;
|
||||
import org.jasig.cas.client.util.CommonUtils;
|
||||
|
|
@ -50,12 +52,16 @@ import org.jboss.web.tomcat.security.login.WebAuthentication;
|
|||
*/
|
||||
public final class WebAuthenticationFilter extends AbstractCasFilter {
|
||||
|
||||
public WebAuthenticationFilter() {
|
||||
super(Protocol.CAS2);
|
||||
}
|
||||
|
||||
public void doFilter(final ServletRequest servletRequest, final ServletResponse servletResponse,
|
||||
final FilterChain chain) throws IOException, ServletException {
|
||||
final HttpServletRequest request = (HttpServletRequest) servletRequest;
|
||||
final HttpServletResponse response = (HttpServletResponse) servletResponse;
|
||||
final HttpSession session = request.getSession();
|
||||
final String ticket = CommonUtils.safeGetParameter(request, getArtifactParameterName());
|
||||
final String ticket = CommonUtils.safeGetParameter(request, getProtocol().getArtifactParameterName());
|
||||
|
||||
if (session != null && session.getAttribute(CONST_CAS_ASSERTION) == null && ticket != null) {
|
||||
try {
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ specific language governing permissions and limitations
|
|||
under the License.
|
||||
|
||||
This project includes:
|
||||
"Java Concurrency in Practice" book annotations under Creative Commons Attribution License
|
||||
Apache Santuario under The Apache Software License, Version 2.0
|
||||
Apache Velocity under The Apache Software License, Version 2.0
|
||||
Bouncy Castle Provider under Bouncy Castle Licence
|
||||
|
|
@ -26,7 +27,6 @@ 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
|
||||
Java Servlet API under CDDL + GPLv2 with classpath exception
|
||||
jcip-annotations under Creative Commons Attribution License
|
||||
JCL 1.1.1 implemented over SLF4J under MIT License
|
||||
Joda time under Apache 2
|
||||
JUL to SLF4J bridge under MIT License
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
<parent>
|
||||
<artifactId>cas-client</artifactId>
|
||||
<groupId>org.jasig.cas.client</groupId>
|
||||
<version>3.3.2-SNAPSHOT</version>
|
||||
<version>3.4.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ specific language governing permissions and limitations
|
|||
under the License.
|
||||
|
||||
This project includes:
|
||||
"Java Concurrency in Practice" book annotations under Creative Commons Attribution License
|
||||
Apache Santuario under The Apache Software License, Version 2.0
|
||||
Apache Velocity under The Apache Software License, Version 2.0
|
||||
Bouncy Castle Provider under Bouncy Castle Licence
|
||||
|
|
@ -28,7 +29,6 @@ This project includes:
|
|||
Jasig CAS Client for Java - Core under Apache License Version 2.0
|
||||
Jasig CAS Client for Java - Tomcat 6.x Integration under Apache License Version 2.0
|
||||
Java Servlet API under CDDL + GPLv2 with classpath exception
|
||||
jcip-annotations under Creative Commons Attribution License
|
||||
JCL 1.1.1 implemented over SLF4J under MIT License
|
||||
Joda time under Apache 2
|
||||
JUL to SLF4J bridge under MIT License
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
<parent>
|
||||
<artifactId>cas-client</artifactId>
|
||||
<groupId>org.jasig.cas.client</groupId>
|
||||
<version>3.3.2-SNAPSHOT</version>
|
||||
<version>3.4.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
|
@ -20,6 +20,14 @@
|
|||
<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>catalina</artifactId>
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ specific language governing permissions and limitations
|
|||
under the License.
|
||||
|
||||
This project includes:
|
||||
"Java Concurrency in Practice" book annotations under Creative Commons Attribution License
|
||||
Apache Santuario under The Apache Software License, Version 2.0
|
||||
Apache Velocity under The Apache Software License, Version 2.0
|
||||
Bouncy Castle Provider under Bouncy Castle Licence
|
||||
|
|
@ -27,7 +28,6 @@ This project includes:
|
|||
Jasig CAS Client for Java - Core under Apache License Version 2.0
|
||||
Jasig CAS Client for Java - Tomcat 7.x Integration under Apache License Version 2.0
|
||||
Java Servlet API under CDDL + GPLv2 with classpath exception
|
||||
jcip-annotations under Creative Commons Attribution License
|
||||
JCL 1.1.1 implemented over SLF4J under MIT License
|
||||
Joda time under Apache 2
|
||||
JUL to SLF4J bridge under MIT License
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
<parent>
|
||||
<artifactId>cas-client</artifactId>
|
||||
<groupId>org.jasig.cas.client</groupId>
|
||||
<version>3.3.2-SNAPSHOT</version>
|
||||
<version>3.4.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
|
@ -20,6 +20,14 @@
|
|||
<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>
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ specific language governing permissions and limitations
|
|||
under the License.
|
||||
|
||||
This project includes:
|
||||
"Java Concurrency in Practice" book annotations under Creative Commons Attribution License
|
||||
Apache Santuario under The Apache Software License, Version 2.0
|
||||
Apache Velocity under The Apache Software License, Version 2.0
|
||||
Bouncy Castle Provider under Bouncy Castle Licence
|
||||
|
|
@ -27,7 +28,6 @@ This project includes:
|
|||
Jasig CAS Client for Java - Core under Apache License Version 2.0
|
||||
Jasig CAS Client for Java - Distributed Proxy Storage Support: EhCache under Apache License Version 2.0
|
||||
Java Servlet API under CDDL + GPLv2 with classpath exception
|
||||
jcip-annotations under Creative Commons Attribution License
|
||||
JCL 1.1.1 implemented over SLF4J under MIT License
|
||||
Joda time under Apache 2
|
||||
JUL to SLF4J bridge under MIT License
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
<parent>
|
||||
<artifactId>cas-client</artifactId>
|
||||
<groupId>org.jasig.cas.client</groupId>
|
||||
<version>3.3.2-SNAPSHOT</version>
|
||||
<version>3.4.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<name>Jasig CAS Client for Java - Distributed Proxy Storage Support: EhCache
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ specific language governing permissions and limitations
|
|||
under the License.
|
||||
|
||||
This project includes:
|
||||
"Java Concurrency in Practice" book annotations under Creative Commons Attribution License
|
||||
Apache Santuario under The Apache Software License, Version 2.0
|
||||
Apache Velocity under The Apache Software License, Version 2.0
|
||||
Bouncy Castle Provider under Bouncy Castle Licence
|
||||
|
|
@ -27,7 +28,6 @@ This project includes:
|
|||
Jasig CAS Client for Java - Distributed Proxy Storage Support:
|
||||
Memcached under Apache License Version 2.0
|
||||
Java Servlet API under CDDL + GPLv2 with classpath exception
|
||||
jcip-annotations under Creative Commons Attribution License
|
||||
JCL 1.1.1 implemented over SLF4J under MIT License
|
||||
Joda time under Apache 2
|
||||
JUL to SLF4J bridge under MIT License
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
<parent>
|
||||
<artifactId>cas-client</artifactId>
|
||||
<groupId>org.jasig.cas.client</groupId>
|
||||
<version>3.3.2-SNAPSHOT</version>
|
||||
<version>3.4.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,44 @@
|
|||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<parent>
|
||||
<groupId>org.jasig.cas.client</groupId>
|
||||
<version>3.4.0-SNAPSHOT</version>
|
||||
<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>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.jasig.cas.client</groupId>
|
||||
<artifactId>cas-client-core</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>joda-time</groupId>
|
||||
<artifactId>joda-time</artifactId>
|
||||
<version>2.7</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.springframework</groupId>
|
||||
<artifactId>spring-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-core</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
|
|
@ -18,13 +18,12 @@
|
|||
*/
|
||||
package org.jasig.cas.client.authentication;
|
||||
|
||||
import javax.servlet.FilterConfig;
|
||||
import javax.servlet.ServletException;
|
||||
import org.jasig.cas.client.Protocol;
|
||||
|
||||
/**
|
||||
* Extension to the default Authentication filter that sets the required SAML1.1 artifact parameter name and service parameter name.
|
||||
* <p>
|
||||
* Note, as of 3.3, the final keyword was removed to allow you to override the method to retrieve tickets, per CASC-154s
|
||||
* Note, as of 3.3, the final keyword was removed to allow you to override the method to retrieve tickets, per CASC-154
|
||||
*
|
||||
* @author Scott Battaglia
|
||||
* @since 3.1.12
|
||||
|
|
@ -32,13 +31,7 @@ import javax.servlet.ServletException;
|
|||
*/
|
||||
public class Saml11AuthenticationFilter extends AuthenticationFilter {
|
||||
|
||||
protected final void initInternal(final FilterConfig filterConfig) throws ServletException {
|
||||
super.initInternal(filterConfig);
|
||||
|
||||
logger.warn("SAML1.1 compliance requires the [artifactParameterName] and [serviceParameterName] to be set to specified values.");
|
||||
logger.warn("This filter will overwrite any user-provided values (if any are provided)");
|
||||
|
||||
setArtifactParameterName("SAMLart");
|
||||
setServiceParameterName("TARGET");
|
||||
public Saml11AuthenticationFilter() {
|
||||
super(Protocol.SAML11);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* 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 java.util.Date;
|
||||
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.DateTimeZone;
|
||||
import org.joda.time.format.DateTimeFormatter;
|
||||
import org.joda.time.format.ISODateTimeFormat;
|
||||
|
||||
/**
|
||||
* SAML utility class.
|
||||
*
|
||||
* @author Marvin S. Addison
|
||||
* @since 3.4
|
||||
*/
|
||||
public final class SamlUtils {
|
||||
|
||||
private static final DateTimeFormatter ISO_FORMAT = ISODateTimeFormat.dateTimeNoMillis();
|
||||
|
||||
private SamlUtils() {
|
||||
// nothing to do
|
||||
}
|
||||
|
||||
public static String formatForUtcTime(final Date date) {
|
||||
return ISO_FORMAT.print(new DateTime(date).withZone(DateTimeZone.UTC));
|
||||
}
|
||||
|
||||
public static Date parseUtcDate(final String date) {
|
||||
if (CommonUtils.isEmpty(date)) {
|
||||
return null;
|
||||
}
|
||||
return ISODateTimeFormat.dateTimeParser().parseDateTime(date).toDate();
|
||||
}
|
||||
}
|
||||
|
|
@ -19,51 +19,39 @@
|
|||
package org.jasig.cas.client.validation;
|
||||
|
||||
import javax.servlet.FilterConfig;
|
||||
import javax.servlet.ServletException;
|
||||
|
||||
import org.jasig.cas.client.Protocol;
|
||||
import org.jasig.cas.client.configuration.ConfigurationKeys;
|
||||
import org.jasig.cas.client.ssl.HttpURLConnectionFactory;
|
||||
import org.jasig.cas.client.ssl.HttpsURLConnectionFactory;
|
||||
|
||||
/**
|
||||
* Implementation of TicketValidationFilter that can instanciate a SAML 1.1 Ticket Validator.
|
||||
* <p>
|
||||
* <p/>
|
||||
* Deployers can provide the "casServerUrlPrefix" and "tolerance" properties of the Saml11TicketValidator via the
|
||||
* context or filter init parameters.
|
||||
*
|
||||
* @author Scott Battaglia
|
||||
* @author Marvin S. Addison
|
||||
* @version $Revision$ $Date$
|
||||
* @since 3.1
|
||||
*/
|
||||
public class Saml11TicketValidationFilter extends AbstractTicketValidationFilter {
|
||||
|
||||
public Saml11TicketValidationFilter() {
|
||||
setArtifactParameterName("SAMLart");
|
||||
setServiceParameterName("TARGET");
|
||||
}
|
||||
|
||||
protected final void initInternal(final FilterConfig filterConfig) throws ServletException {
|
||||
super.initInternal(filterConfig);
|
||||
|
||||
logger.warn("SAML1.1 compliance requires the [artifactParameterName] and [serviceParameterName] to be set to specified values.");
|
||||
logger.warn("This filter will overwrite any user-provided values (if any are provided)");
|
||||
|
||||
setArtifactParameterName("SAMLart");
|
||||
setServiceParameterName("TARGET");
|
||||
super(Protocol.SAML11);
|
||||
}
|
||||
|
||||
protected final TicketValidator getTicketValidator(final FilterConfig filterConfig) {
|
||||
final Saml11TicketValidator validator = new Saml11TicketValidator(getPropertyFromInitParams(filterConfig,
|
||||
"casServerUrlPrefix", null));
|
||||
final String tolerance = getPropertyFromInitParams(filterConfig, "tolerance", "1000");
|
||||
validator.setTolerance(Long.parseLong(tolerance));
|
||||
validator.setRenew(parseBoolean(getPropertyFromInitParams(filterConfig, "renew", "false")));
|
||||
final Saml11TicketValidator validator = new Saml11TicketValidator(getString(ConfigurationKeys.CAS_SERVER_URL_PREFIX));
|
||||
final long tolerance = getLong(ConfigurationKeys.TOLERANCE);
|
||||
validator.setTolerance(tolerance);
|
||||
validator.setRenew(getBoolean(ConfigurationKeys.RENEW));
|
||||
|
||||
final HttpURLConnectionFactory factory = new HttpsURLConnectionFactory(getHostnameVerifier(filterConfig),
|
||||
getSSLConfig(filterConfig));
|
||||
final HttpURLConnectionFactory factory = new HttpsURLConnectionFactory(getHostnameVerifier(), getSSLConfig());
|
||||
validator.setURLConnectionFactory(factory);
|
||||
|
||||
validator.setEncoding(getPropertyFromInitParams(filterConfig, "encoding", null));
|
||||
validator.setDisableXmlSchemaValidation(parseBoolean(getPropertyFromInitParams(filterConfig,
|
||||
"disableXmlSchemaValidation", "false")));
|
||||
validator.setEncoding(getString(ConfigurationKeys.ENCODING));
|
||||
return validator;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,238 @@
|
|||
/*
|
||||
* 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.validation;
|
||||
|
||||
import java.io.*;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.nio.charset.Charset;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.SecureRandom;
|
||||
import java.util.*;
|
||||
import org.jasig.cas.client.authentication.AttributePrincipalImpl;
|
||||
import org.jasig.cas.client.util.*;
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.DateTimeZone;
|
||||
import org.joda.time.Interval;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Element;
|
||||
import org.w3c.dom.NodeList;
|
||||
|
||||
import javax.xml.namespace.NamespaceContext;
|
||||
|
||||
/**
|
||||
* TicketValidator that can understand validating a SAML artifact. This includes the SOAP request/response.
|
||||
*
|
||||
* @author Scott Battaglia
|
||||
* @author Marvin S. Addison
|
||||
* @since 3.1
|
||||
*/
|
||||
public final class Saml11TicketValidator extends AbstractUrlBasedTicketValidator {
|
||||
|
||||
/** Authentication attribute containing SAML AuthenticationMethod attribute value. */
|
||||
public static final String AUTH_METHOD_ATTRIBUTE = "samlAuthenticationStatement::authMethod";
|
||||
|
||||
/** SAML 1.1 request template. */
|
||||
private static final String SAML_REQUEST_TEMPLATE;
|
||||
|
||||
/** SAML 1.1. namespace context. */
|
||||
private static final NamespaceContext NS_CONTEXT = new MapNamespaceContext(
|
||||
"soap->http://schemas.xmlsoap.org/soap/envelope/",
|
||||
"sa->urn:oasis:names:tc:SAML:1.0:assertion",
|
||||
"sp->urn:oasis:names:tc:SAML:1.0:protocol");
|
||||
|
||||
/** XPath expression to extract Assertion validity start date. */
|
||||
private static final ThreadLocalXPathExpression XPATH_ASSERTION_DATE_START =
|
||||
new ThreadLocalXPathExpression("//sa:Assertion/sa:Conditions/@NotBefore", NS_CONTEXT);
|
||||
|
||||
/** XPath expression to extract Assertion validity end date. */
|
||||
private static final ThreadLocalXPathExpression XPATH_ASSERTION_DATE_END =
|
||||
new ThreadLocalXPathExpression("//sa:Assertion/sa:Conditions/@NotOnOrAfter", NS_CONTEXT);
|
||||
|
||||
/** XPath expression to extract NameIdentifier. */
|
||||
private static final ThreadLocalXPathExpression XPATH_NAME_ID =
|
||||
new ThreadLocalXPathExpression("//sa:AuthenticationStatement/sa:Subject/sa:NameIdentifier", NS_CONTEXT);
|
||||
|
||||
/** XPath expression to extract authentication method. */
|
||||
private static final ThreadLocalXPathExpression XPATH_AUTH_METHOD =
|
||||
new ThreadLocalXPathExpression("//sa:AuthenticationStatement/@AuthenticationMethod", NS_CONTEXT);
|
||||
|
||||
/** XPath expression to extract attributes. */
|
||||
private static final ThreadLocalXPathExpression XPATH_ATTRIBUTES =
|
||||
new ThreadLocalXPathExpression("//sa:AttributeStatement/sa:Attribute", NS_CONTEXT);
|
||||
|
||||
private static final String HEX_CHARS = "0123456789abcdef";
|
||||
|
||||
/** Time tolerance to allow for time drifting. */
|
||||
private long tolerance = 1000L;
|
||||
|
||||
private final Random random;
|
||||
|
||||
|
||||
/** Class initializer. */
|
||||
static {
|
||||
try {
|
||||
SAML_REQUEST_TEMPLATE = IOUtils.readString(
|
||||
Saml11TicketValidator.class.getResourceAsStream("/META-INF/cas/samlRequestTemplate.xml"));
|
||||
} catch (IOException e) {
|
||||
throw new IllegalStateException("Cannot load SAML request template from classpath", e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public Saml11TicketValidator(final String casServerUrlPrefix) {
|
||||
super(casServerUrlPrefix);
|
||||
|
||||
try {
|
||||
random = SecureRandom.getInstance("SHA1PRNG");
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
throw new IllegalStateException("Cannot find required SHA1PRNG algorithm");
|
||||
}
|
||||
}
|
||||
|
||||
protected String getUrlSuffix() {
|
||||
return "samlValidate";
|
||||
}
|
||||
|
||||
protected void populateUrlAttributeMap(final Map<String, String> urlParameters) {
|
||||
final String service = urlParameters.get("service");
|
||||
urlParameters.remove("service");
|
||||
urlParameters.remove("ticket");
|
||||
urlParameters.put("TARGET", service);
|
||||
}
|
||||
|
||||
protected Assertion parseResponseFromServer(final String response) throws TicketValidationException {
|
||||
try {
|
||||
final Document document = XmlUtils.newDocument(response);
|
||||
final Date assertionValidityStart = SamlUtils.parseUtcDate(
|
||||
XPATH_ASSERTION_DATE_START.evaluateAsString(document));
|
||||
final Date assertionValidityEnd = SamlUtils.parseUtcDate(
|
||||
XPATH_ASSERTION_DATE_END.evaluateAsString(document));
|
||||
if (!isValidAssertion(assertionValidityStart, assertionValidityEnd)) {
|
||||
throw new TicketValidationException("Invalid SAML assertion");
|
||||
}
|
||||
final String nameId = XPATH_NAME_ID.evaluateAsString(document);
|
||||
if (nameId == null) {
|
||||
throw new TicketValidationException("SAML assertion does not contain NameIdentifier element");
|
||||
}
|
||||
final String authMethod = XPATH_AUTH_METHOD.evaluateAsString(document);
|
||||
final NodeList attributes = XPATH_ATTRIBUTES.evaluateAsNodeList(document);
|
||||
final Map<String, Object> principalAttributes = new HashMap<String, Object>(attributes.getLength());
|
||||
Element attribute;
|
||||
NodeList values;
|
||||
String name;
|
||||
for (int i = 0; i < attributes.getLength(); i++) {
|
||||
attribute = (Element) attributes.item(i);
|
||||
name = attribute.getAttribute("AttributeName");
|
||||
logger.trace("Processing attribute {}", name);
|
||||
values = attribute.getElementsByTagNameNS("*", "AttributeValue");
|
||||
if (values.getLength() == 1) {
|
||||
principalAttributes.put(name, values.item(0).getTextContent());
|
||||
} else {
|
||||
final Collection<Object> items = new ArrayList<Object>(values.getLength());
|
||||
for (int j = 0; j < values.getLength(); j++) {
|
||||
items.add(values.item(j).getTextContent());
|
||||
}
|
||||
principalAttributes.put(name, items);
|
||||
}
|
||||
}
|
||||
return new AssertionImpl(
|
||||
new AttributePrincipalImpl(nameId, principalAttributes),
|
||||
assertionValidityStart,
|
||||
assertionValidityEnd,
|
||||
new Date(),
|
||||
Collections.singletonMap(AUTH_METHOD_ATTRIBUTE, (Object) authMethod));
|
||||
} catch (final Exception e) {
|
||||
throw new TicketValidationException("Error processing SAML response", e);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isValidAssertion(final Date notBefore, final Date notOnOrAfter) {
|
||||
if (notBefore == null || notOnOrAfter == null) {
|
||||
logger.debug("Assertion is not valid because it does not have bounding dates.");
|
||||
return false;
|
||||
}
|
||||
|
||||
final DateTime currentTime = new DateTime(DateTimeZone.UTC);
|
||||
final Interval validityRange = new Interval(
|
||||
new DateTime(notBefore).minus(this.tolerance),
|
||||
new DateTime(notOnOrAfter).plus(this.tolerance));
|
||||
|
||||
if (validityRange.contains(currentTime)) {
|
||||
logger.debug("Current time is within the interval validity.");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (currentTime.isBefore(validityRange.getStart())) {
|
||||
logger.debug("Assertion is not yet valid");
|
||||
} else {
|
||||
logger.debug("Assertion is expired");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected String retrieveResponseFromServer(final URL validationUrl, final String ticket) {
|
||||
final String request = String.format(
|
||||
SAML_REQUEST_TEMPLATE,
|
||||
generateId(),
|
||||
SamlUtils.formatForUtcTime(new Date()),
|
||||
ticket);
|
||||
HttpURLConnection conn = null;
|
||||
try {
|
||||
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);
|
||||
conn.setDoOutput(true);
|
||||
|
||||
|
||||
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);
|
||||
} finally {
|
||||
if (conn != null) {
|
||||
conn.disconnect();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setTolerance(final long tolerance) {
|
||||
this.tolerance = tolerance;
|
||||
}
|
||||
|
||||
private String generateId() {
|
||||
final byte[] data = new byte[16];
|
||||
random.nextBytes(data);
|
||||
final StringBuilder id = new StringBuilder(33);
|
||||
id.append('_');
|
||||
for (int i = 0; i < data.length; i++) {
|
||||
id.append(HEX_CHARS.charAt((data[i] & 0xF0) >> 4));
|
||||
id.append(HEX_CHARS.charAt(data[i] & 0x0F));
|
||||
}
|
||||
return id.toString();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* 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 java.util.Date;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* Test cases for {@link SamlUtils}.
|
||||
*
|
||||
* @author Marvin S. Addison
|
||||
*/
|
||||
public class SamlUtilsTest {
|
||||
|
||||
@Test
|
||||
public void testParseUtcDate() {
|
||||
final Date expected = new Date(1424437961025L);
|
||||
assertEquals(expected, SamlUtils.parseUtcDate("2015-02-20T08:12:41.025-0500"));
|
||||
}
|
||||
}
|
||||
|
|
@ -20,6 +20,7 @@ package org.jasig.cas.client.validation;
|
|||
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.mock.web.MockFilterConfig;
|
||||
import org.springframework.mock.web.MockServletContext;
|
||||
|
|
@ -50,7 +51,10 @@ public class Saml11TicketValidationFilterTests {
|
|||
final MockServletContext context = new MockServletContext();
|
||||
context.addInitParameter("casServerUrlPrefix", "https://cas.example.com");
|
||||
context.addInitParameter("renew", "true");
|
||||
final TicketValidator validator = f.getTicketValidator(new MockFilterConfig(context));
|
||||
context.addInitParameter("service", "http://www.jasig.org");
|
||||
final MockFilterConfig config = new MockFilterConfig(context);
|
||||
f.init(config);
|
||||
final TicketValidator validator = f.getTicketValidator(config);
|
||||
assertTrue(validator instanceof Saml11TicketValidator);
|
||||
assertTrue(((Saml11TicketValidator) validator).isRenew());
|
||||
}
|
||||
|
|
@ -21,9 +21,10 @@ package org.jasig.cas.client.validation;
|
|||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.fail;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import org.jasig.cas.client.PublicTestHttpServer;
|
||||
import org.jasig.cas.client.util.CommonUtils;
|
||||
import org.jasig.cas.client.util.SamlUtils;
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.DateTimeZone;
|
||||
import org.joda.time.Interval;
|
||||
|
|
@ -45,7 +46,7 @@ public final class Saml11TicketValidatorTests extends AbstractTicketValidatorTes
|
|||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
this.validator = new Saml11TicketValidator(CONST_CAS_SERVER_URL_PREFIX + "9051");
|
||||
this.validator = new Saml11TicketValidator(AbstractTicketValidatorTests.CONST_CAS_SERVER_URL_PREFIX + "9051");
|
||||
this.validator.setTolerance(1000L);
|
||||
}
|
||||
|
||||
|
|
@ -82,13 +83,13 @@ public final class Saml11TicketValidatorTests extends AbstractTicketValidatorTes
|
|||
final Interval range = currentTimeRangeInterval();
|
||||
final Date now = new Date();
|
||||
final String RESPONSE = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><SOAP-ENV:Envelope xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\"><SOAP-ENV:Header/><SOAP-ENV:Body><Response xmlns=\"urn:oasis:names:tc:SAML:1.0:protocol\" xmlns:saml=\"urn:oasis:names:tc:SAML:1.0:assertion\" xmlns:samlp=\"urn:oasis:names:tc:SAML:1.0:protocol\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" IssueInstant=\""
|
||||
+ CommonUtils.formatForUtcTime(now)
|
||||
+ SamlUtils.formatForUtcTime(now)
|
||||
+ "\" MajorVersion=\"1\" MinorVersion=\"1\" Recipient=\"test\" ResponseID=\"_e1e2124c08ab456eab0bbab3e1c0c433\"><Status><StatusCode Value=\"samlp:Success\"></StatusCode></Status><Assertion xmlns=\"urn:oasis:names:tc:SAML:1.0:assertion\" AssertionID=\"_d2fd0d6e4da6a6d7d2ba5274ab570d5c\" IssueInstant=\""
|
||||
+ CommonUtils.formatForUtcTime(now)
|
||||
+ SamlUtils.formatForUtcTime(now)
|
||||
+ "\" Issuer=\"testIssuer\" MajorVersion=\"1\" MinorVersion=\"1\"><Conditions NotBefore=\""
|
||||
+ CommonUtils.formatForUtcTime(range.getStart().toDate())
|
||||
+ SamlUtils.formatForUtcTime(range.getStart().toDate())
|
||||
+ "\" NotOnOrAfter=\""
|
||||
+ CommonUtils.formatForUtcTime(range.getEnd().toDate())
|
||||
+ SamlUtils.formatForUtcTime(range.getEnd().toDate())
|
||||
+ "\"><AudienceRestrictionCondition><Audience>test</Audience></AudienceRestrictionCondition></Conditions><AuthenticationStatement AuthenticationInstant=\"2008-06-19T14:34:44.426Z\" AuthenticationMethod=\"urn:ietf:rfc:2246\"><Subject><NameIdentifier>testPrincipal</NameIdentifier><SubjectConfirmation><ConfirmationMethod>urn:oasis:names:tc:SAML:1.0:cm:artifact</ConfirmationMethod></SubjectConfirmation></Subject></AuthenticationStatement></Assertion></Response></SOAP-ENV:Body></SOAP-ENV:Envelope>";
|
||||
server.content = RESPONSE.getBytes(server.encoding);
|
||||
try {
|
||||
|
|
@ -106,22 +107,28 @@ public final class Saml11TicketValidatorTests extends AbstractTicketValidatorTes
|
|||
|
||||
final String response = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><soap11:Envelope xmlns:soap11=\"http://schemas.xmlsoap.org/soap/envelope/\"><soap11:Body>"
|
||||
+ "<saml1p:Response xmlns:saml1p=\"urn:oasis:names:tc:SAML:1.0:protocol\" InResponseTo=\"_fd1632b5dfa921623e7ca6f9ab727161\" IssueInstant=\""
|
||||
+ CommonUtils.formatForUtcTime(now)
|
||||
+ SamlUtils.formatForUtcTime(now)
|
||||
+ "\" MajorVersion=\"1\" MinorVersion=\"1\" Recipient=\"https://example.com/test-client/secure/?TARGET=https%3A%2F%2Fexample.com%2Ftest-client%2Fsecure%2F\" ResponseID=\"_436dbb2cca5166af29250f431a07888f\">"
|
||||
+ "<saml1p:Status><saml1p:StatusCode Value=\"saml1p:Success\"/></saml1p:Status>"
|
||||
+ "<saml1:Assertion xmlns:saml1=\"urn:oasis:names:tc:SAML:1.0:assertion\" IssueInstant=\""
|
||||
+ CommonUtils.formatForUtcTime(now)
|
||||
+ SamlUtils.formatForUtcTime(now)
|
||||
+ "\" Issuer=\"localhost\" MajorVersion=\"1\" MinorVersion=\"1\">"
|
||||
+ "<saml1:Conditions NotBefore=\""
|
||||
+ CommonUtils.formatForUtcTime(range.getStart().toDate())
|
||||
+ SamlUtils.formatForUtcTime(range.getStart().toDate())
|
||||
+ "\" NotOnOrAfter=\""
|
||||
+ CommonUtils.formatForUtcTime(range.getEnd().toDate())
|
||||
+ SamlUtils.formatForUtcTime(range.getEnd().toDate())
|
||||
+ "\">"
|
||||
+ "<saml1:AudienceRestrictionCondition><saml1:Audience>https://example.com/test-client/secure/</saml1:Audience></saml1:AudienceRestrictionCondition></saml1:Conditions>"
|
||||
+ "<saml1:AudienceRestrictionCondition><saml1:Audience>https://example.com/test-client/secure/</saml1:Audience>"
|
||||
+ "</saml1:AudienceRestrictionCondition></saml1:Conditions>"
|
||||
+ "<saml1:AuthenticationStatement AuthenticationInstant=\""
|
||||
+ CommonUtils.formatForUtcTime(now)
|
||||
+ SamlUtils.formatForUtcTime(now)
|
||||
+ "\" AuthenticationMethod=\"urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport\">"
|
||||
+ "<saml1:Subject><saml1:NameIdentifier>testPrincipal</saml1:NameIdentifier><saml1:SubjectConfirmation><saml1:ConfirmationMethod>urn:oasis:names:tc:SAML:1.0:cm:artifact</saml1:ConfirmationMethod></saml1:SubjectConfirmation></saml1:Subject></saml1:AuthenticationStatement><saml1:AttributeStatement><saml1:Subject><saml1:NameIdentifier>testPrincipal</saml1:NameIdentifier><saml1:SubjectConfirmation><saml1:ConfirmationMethod>urn:oasis:names:tc:SAML:1.0:cm:artifact</saml1:ConfirmationMethod></saml1:SubjectConfirmation></saml1:Subject><saml1:Attribute AttributeName=\"uid\" AttributeNamespace=\"http://www.ja-sig.org/products/cas/\"><saml1:AttributeValue xmlns:xs=\"http://www.w3.org/2001/XMLSchema\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:type=\"xs:string\">12345</saml1:AttributeValue>"
|
||||
+ "<saml1:Subject><saml1:NameIdentifier>testPrincipal</saml1:NameIdentifier>"
|
||||
+ "<saml1:SubjectConfirmation><saml1:ConfirmationMethod>urn:oasis:names:tc:SAML:1.0:cm:artifact</saml1:ConfirmationMethod></saml1:SubjectConfirmation>"
|
||||
+ "</saml1:Subject></saml1:AuthenticationStatement>"
|
||||
+ "<saml1:AttributeStatement><saml1:Subject><saml1:NameIdentifier>testPrincipal</saml1:NameIdentifier>"
|
||||
+ "<saml1:SubjectConfirmation><saml1:ConfirmationMethod>urn:oasis:names:tc:SAML:1.0:cm:artifact</saml1:ConfirmationMethod></saml1:SubjectConfirmation></saml1:Subject>"
|
||||
+ "<saml1:Attribute AttributeName=\"uid\" AttributeNamespace=\"http://www.ja-sig.org/products/cas/\"><saml1:AttributeValue xmlns:xs=\"http://www.w3.org/2001/XMLSchema\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:type=\"xs:string\">12345</saml1:AttributeValue>"
|
||||
+ "</saml1:Attribute><saml1:Attribute AttributeName=\"accountState\" AttributeNamespace=\"http://www.ja-sig.org/products/cas/\">"
|
||||
+ "<saml1:AttributeValue xmlns:xs=\"http://www.w3.org/2001/XMLSchema\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:type=\"xs:string\">ACTIVE</saml1:AttributeValue>"
|
||||
+ "</saml1:Attribute><saml1:Attribute AttributeName=\"eduPersonAffiliation\" AttributeNamespace=\"http://www.ja-sig.org/products/cas/\">"
|
||||
|
|
@ -132,7 +139,13 @@ public final class Saml11TicketValidatorTests extends AbstractTicketValidatorTes
|
|||
server.content = response.getBytes(server.encoding);
|
||||
try {
|
||||
final Assertion a = this.validator.validate("test", "test");
|
||||
assertEquals(
|
||||
"urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport",
|
||||
a.getAttributes().get(Saml11TicketValidator.AUTH_METHOD_ATTRIBUTE));
|
||||
assertEquals("testPrincipal", a.getPrincipal().getName());
|
||||
assertEquals("12345", a.getPrincipal().getAttributes().get("uid"));
|
||||
assertEquals("ACTIVE", a.getPrincipal().getAttributes().get("accountState"));
|
||||
assertEquals(3, ((Collection) a.getPrincipal().getAttributes().get("eduPersonAffiliation")).size());
|
||||
} catch (final TicketValidationException e) {
|
||||
fail(e.toString());
|
||||
}
|
||||
54
pom.xml
54
pom.xml
|
|
@ -6,7 +6,7 @@
|
|||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.jasig.cas.client</groupId>
|
||||
<version>3.3.2-SNAPSHOT</version>
|
||||
<version>3.4.0-SNAPSHOT</version>
|
||||
<artifactId>cas-client</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
|
|
@ -159,6 +159,56 @@
|
|||
</plugins>
|
||||
</build>
|
||||
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-core</artifactId>
|
||||
<version>${spring.version}</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<artifactId>commons-logging</artifactId>
|
||||
<groupId>commons-logging</groupId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-context</artifactId>
|
||||
<version>${spring.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-test</artifactId>
|
||||
<version>${spring.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>log4j</groupId>
|
||||
<artifactId>log4j</artifactId>
|
||||
<scope>test</scope>
|
||||
<version>1.2.15</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<artifactId>jmxri</artifactId>
|
||||
<groupId>com.sun.jmx</groupId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>com.sun.jdmk</groupId>
|
||||
<artifactId>jmxtools</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>javax.jms</groupId>
|
||||
<artifactId>jms</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
|
|
@ -198,12 +248,14 @@
|
|||
<module>cas-client-integration-jboss</module>
|
||||
<module>cas-client-support-distributed-ehcache</module>
|
||||
<module>cas-client-support-distributed-memcached</module>
|
||||
<module>cas-client-support-saml</module>
|
||||
<module>cas-client-integration-tomcat-common</module>
|
||||
<module>cas-client-integration-tomcat-v6</module>
|
||||
<module>cas-client-integration-tomcat-v7</module>
|
||||
</modules>
|
||||
|
||||
<properties>
|
||||
<spring.version>3.1.3.RELEASE</spring.version>
|
||||
<ehcache.version>2.2.0</ehcache.version>
|
||||
<clover.version>3.0.2</clover.version>
|
||||
<slf4j.version>1.7.1</slf4j.version>
|
||||
|
|
|
|||
Loading…
Reference in New Issue