Compare commits

..

1 Commits

Author SHA1 Message Date
Scott Battaglia 11e2ec4a19 NOJIRA
tag for 3.1.1
2008-02-19 18:15:51 +00:00
285 changed files with 1756 additions and 26807 deletions

20
.github/FUNDING.yml vendored
View File

@ -1,20 +0,0 @@
#
# Licensed to Apereo under one or more contributor license
# agreements. See the NOTICE file distributed with this work
# for additional information regarding copyright ownership.
# Apereo licenses this file to you under the Apache License,
# Version 2.0 (the "License"); you may not use this file
# except in compliance with the License. You may obtain a
# copy of the License at the following location:
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#
custom: ['https://www.apereo.org/content/apereo-membership']

11
.github/renovate.json vendored
View File

@ -1,11 +0,0 @@
{
"extends": [
"config:base",
":preserveSemverRanges",
":rebaseStalePrs",
":disableRateLimiting",
":semanticCommits",
":semanticCommitTypeAll(renovatebot)"
],
"labels": ["dependencies", "bot"]
}

73
.github/stale.yml vendored
View File

@ -1,73 +0,0 @@
#
# Licensed to Apereo under one or more contributor license
# agreements. See the NOTICE file distributed with this work
# for additional information regarding copyright ownership.
# Apereo licenses this file to you under the Apache License,
# Version 2.0 (the "License"); you may not use this file
# except in compliance with the License. You may obtain a
# copy of the License at the following location:
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#
# Configuration for probot-stale - https://github.com/probot/stale
# Number of days of inactivity before an Issue or Pull Request becomes stale
daysUntilStale: 7
# Number of days of inactivity before a stale Issue or Pull Request is closed.
# Set to false to disable. If disabled, issues still need to be closed manually, but will remain marked as stale.
daysUntilClose: 7
# Issues or Pull Requests with these labels will never be considered stale. Set to `[]` to disable
exemptLabels:
# Set to true to ignore issues in a project (defaults to false)
exemptProjects: false
# Set to true to ignore issues in a milestone (defaults to false)
exemptMilestones: false
# Label to use when marking as stale
staleLabel: Pending
# Comment to post when marking as stale. Set to `false` to disable
markComment: >
This patch has been automatically marked as stale because it has not had
recent activity. It will be closed if no further activity occurs. Thank you
for your contributions.
# Comment to post when removing the stale label.
# unmarkComment: >
# Your comment here.
# Comment to post when closing a stale Issue or Pull Request.
closeComment: >
This patch has been automatically closed because it has not had
recent activity. If you wish to resume work, please re-open the pull request
and continue as usual. Thank you for your contributions.
# Limit the number of actions per hour, from 1-30. Default is 30
limitPerRun: 30
# Limit to only `issues` or `pulls`
# only: pulls
# Optionally, specify configuration settings that are specific to just 'issues' or 'pulls':
# pulls:
# daysUntilStale: 30
# markComment: >
# This pull request has been automatically marked as stale because it has not had
# recent activity. It will be closed if no further activity occurs. Thank you
# for your contributions.
# issues:
# exemptLabels:
# - confirmed

12
.gitignore vendored
View File

@ -1,12 +0,0 @@
.classpath
!/.project
.project
.settings
bin
target
*.ipr
*.iml
*.iws
.idea/
.DS_Store
.idea

View File

@ -1,44 +0,0 @@
#
# Licensed to Apereo under one or more contributor license
# agreements. See the NOTICE file distributed with this work
# for additional information regarding copyright ownership.
# Apereo licenses this file to you under the Apache License,
# Version 2.0 (the "License"); you may not use this file
# except in compliance with the License. You may obtain a
# copy of the License at the following location:
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#
pull_request_rules:
- name: automatic merge by dependabot
conditions:
- status-success=continuous-integration/travis-ci/pr
- status-success=WIP
- "#changes-requested-reviews-by=0"
- base=master
- label=dependencies
actions:
merge:
method: squash
strict: false
delete_head_branch:
- name: automatic merge by renovate
conditions:
- status-success=continuous-integration/travis-ci/pr
- status-success=WIP
- "#changes-requested-reviews-by=0"
- base=master
- label=dependencies
actions:
merge:
method: squash
strict: false
delete_head_branch:

View File

@ -1,38 +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.
#
language: java
sudo: required
branches:
only:
- master
cache:
directories:
- "$HOME/.m2/repository"
script: "mvn install --settings travis/settings.xml"
jdk:
- openjdk8
env:
global:
- secure: "JM/FMiec3GYShrMlJQSW2QG208+V0GCAj2bsP5eF8q4yzgp6o4rT+r57KDIDD6MapRN+G1Pnl3WPcS0aQYnwOhPg4tA2De1bFUPaJltP47eHFfblpjZeHMxcauCQ6BwFFr8yuC0ORsYCW3TOK00Mxq4CRlTlg5iclzHyS/pnkLI="
- secure: "eXfgf3v8Kw/L22DO39Y61os13bfNpop8Xpkmz+HZ1djQWavOkRn58gSg8EVjBYRPOrTuEbhEWb+s3qpx8j3qRdi6roMs9MTr5gEPTAyjTtJ/Zv1qhJ6OlEl2w5c2fRMsk5cB//mtxtZ+qMaz6sdZI2csbQ2xlhjz4AbGQL5i1lY="
after_success:
- chmod -R 777 ./travis/deploy-to-sonatype.sh
- ./travis/deploy-to-sonatype.sh

101
NOTICE
View File

@ -1,101 +0,0 @@
Licensed to Apereo under one or more contributor license
agreements. See the NOTICE file distributed with this work
for additional information regarding copyright ownership.
Apereo licenses this file to you under the Apache License,
Version 2.0 (the "License"); you may not use this file
except in compliance with the License. You may obtain a
copy of the License at the following location:
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
This project includes:
Apache Commons Codec under Apache License, Version 2.0
Apache Log4j under The Apache Software License, Version 2.0
Apache Log4j API under Apache License, Version 2.0
Apache Log4j to SLF4J Adapter under Apache License, Version 2.0
Apache XML Security under The Apache Software License, Version 2.0
Apereo CAS Client for Java under Apache License Version 2.0
asm under BSD
asm-analysis under BSD
asm-commons under BSD
asm-tree under BSD
Bouncy Castle PKIX, CMS, EAC, TSP, PKCS, OCSP, CMP, and CRMF APIs under Bouncy Castle Licence
Bouncy Castle Provider under Bouncy Castle Licence
catalina under Apache License, Version 2.0
coyote under Apache License, Version 2.0
Eclipse Compiler for Java(TM) under Eclipse Public License - v 2.0
Ehcache Core under The Apache Software License, Version 2.0
Hamcrest Core under New BSD License
Jackson-annotations under The Apache Software License, Version 2.0
Jackson-core under The Apache Software License, Version 2.0
jackson-databind under The Apache Software License, Version 2.0
Jasig CAS Client for Java - Common Tomcat Integration Support under Apache License Version 2.0
Jasig CAS Client for Java - Core under Apache License Version 2.0
Jasig CAS Client for Java - Distributed Proxy Storage Support: EhCache under Apache License Version 2.0
Jasig CAS Client for Java - Distributed Proxy Storage Support: Memcached under Apache License Version 2.0
Jasig CAS Client for Java - JBoss Integration under Apache License Version 2.0
Jasig CAS Client for Java - Jetty Container Integration under Apache License Version 2.0
Jasig CAS Client for Java - SAML Protocol Support under Apache License Version 2.0
Jasig CAS Client for Java - Spring Boot Support under Apache License Version 2.0
Jasig CAS Client for Java - Tomcat 6.x Integration under Apache License Version 2.0
Jasig CAS Client for Java - Tomcat 7.x Integration under Apache License Version 2.0
Jasig CAS Client for Java - Tomcat 8.5.x Integration under Apache License Version 2.0
Jasig CAS Client for Java - Tomcat 8.x Integration under Apache License Version 2.0
Jasig CAS Client for Java - Tomcat 9.0.x Integration under Apache License Version 2.0
Java Servlet API under CDDL + GPLv2 with classpath exception
javax.annotation API under CDDL + GPLv2 with classpath exception
JBoss Application Server Tomcat under lgpl
JCL 1.2 implemented over SLF4J under MIT License
Jetty :: Apache JSP Implementation under Apache Software License - Version 2.0 or Eclipse Public License - Version 1.0
Jetty :: Http Utility under Apache Software License - Version 2.0 or Eclipse Public License - Version 1.0
Jetty :: IO Utility under Apache Software License - Version 2.0 or Eclipse Public License - Version 1.0
Jetty :: JNDI Naming under Apache Software License - Version 2.0 or Eclipse Public License - Version 1.0
Jetty :: Plus under Apache Software License - Version 2.0 or Eclipse Public License - Version 1.0
Jetty :: Schemas under Apache Software License - Version 2.0 or Eclipse Public License - Version 1.0
Jetty :: Security under Apache Software License - Version 2.0 or Eclipse Public License - Version 1.0
Jetty :: Server Core under Apache Software License - Version 2.0 or Eclipse Public License - Version 1.0
Jetty :: Servlet Annotations under Apache Software License - Version 2.0 or Eclipse Public License - Version 1.0
Jetty :: Servlet Handling under Apache Software License - Version 2.0 or Eclipse Public License - Version 1.0
Jetty :: Utilities under Apache Software License - Version 2.0 or Eclipse Public License - Version 1.0
Jetty :: Webapp Application Support under Apache Software License - Version 2.0 or Eclipse Public License - Version 1.0
Jetty :: XML utilities under Apache Software License - Version 2.0 or Eclipse Public License - Version 1.0
Joda-Time under Apache License, Version 2.0
JUL to SLF4J bridge under MIT License
JUnit under Eclipse Public License 1.0
Logback Classic Module under Eclipse Public License - v 1.0 or GNU Lesser General Public License
Logback Core Module under Eclipse Public License - v 1.0 or GNU Lesser General Public License
MortBay :: Apache EL :: API and Implementation under Apache License Version 2.0
MortBay :: Apache Jasper :: JSP Implementation under Apache License Version 2.0
SLF4J API Module under MIT License
SLF4J Simple Binding under MIT License
SnakeYAML under Apache License, Version 2.0
Spring AOP under Apache License, Version 2.0
Spring Beans under Apache License, Version 2.0
Spring Boot under Apache License, Version 2.0
Spring Boot AutoConfigure under Apache License, Version 2.0
Spring Boot Logging Starter under Apache License, Version 2.0
Spring Boot Starter under Apache License, Version 2.0
Spring Commons Logging Bridge under Apache License, Version 2.0
Spring Context under Apache License, Version 2.0
Spring Core under Apache License, Version 2.0
Spring Expression Language (SpEL) under Apache License, Version 2.0
Spring TestContext Framework under Apache License, Version 2.0
Spring Web under Apache License, Version 2.0
Spymemcached under The Apache Software License, Version 2.0
tomcat-annotations-api under Apache License, Version 2.0
tomcat-catalina under Apache License, Version 2.0
tomcat-coyote under Apache License, Version 2.0
tomcat-el-api under Apache License, Version 2.0
tomcat-embed-core under Apache License, Version 2.0
tomcat-jaspic-api under Apache License, Version 2.0
tomcat-jni under Apache License, Version 2.0
tomcat-jsp-api under Apache License, Version 2.0
tomcat-util-scan under Apache License, Version 2.0

1504
README.md

File diff suppressed because it is too large Load Diff

View File

@ -1,84 +1,64 @@
<!--
Licensed to Apereo under one or more contributor license
agreements. See the NOTICE file distributed with this work
for additional information regarding copyright ownership.
Apereo licenses this file to you under the Apache License,
Version 2.0 (the "License"); you may not use this file
except in compliance with the License. You may obtain a
copy of the License at the following location:
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->
<assembly>
<id>release</id>
<formats>
<format>zip</format>
<format>tar.gz</format>
</formats>
<includeBaseDirectory>true</includeBaseDirectory>
<fileSets>
<fileSet>
<lineEnding>unix</lineEnding>
<useDefaultExcludes>true</useDefaultExcludes>
<useStrictFiltering>false</useStrictFiltering>
<directory>${basedir}</directory>
<outputDirectory></outputDirectory>
<includes>
<include>*.xml</include>
<include>*.txt</include>
</includes>
</fileSet>
</fileSets>
<moduleSets>
<moduleSet>
<includes></includes>
<sources>
<fileSets>
<fileSet>
<directory>src</directory>
<outputDirectory>src</outputDirectory>
<lineEnding>unix</lineEnding>
<useDefaultExcludes>true</useDefaultExcludes>
</fileSet>
<id>release</id>
<formats>
<format>zip</format>
<format>tar.gz</format>
</formats>
<includeBaseDirectory>true</includeBaseDirectory>
<fileSets>
<fileSet>
<lineEnding>unix</lineEnding>
<useDefaultExcludes>true</useDefaultExcludes>
<useStrictFiltering>false</useStrictFiltering>
<directory>${basedir}</directory>
<outputDirectory></outputDirectory>
<includes>
<include>*.xml</include>
<include>*.txt</include>
</includes>
</fileSet>
</fileSets>
<moduleSets>
<moduleSet>
<includes></includes>
<sources>
<fileSets>
<fileSet>
<directory>src</directory>
<outputDirectory>src</outputDirectory>
<lineEnding>unix</lineEnding>
<useDefaultExcludes>true</useDefaultExcludes>
</fileSet>
<fileSet>
<lineEnding>unix</lineEnding>
<useDefaultExcludes>true</useDefaultExcludes>
<includes>
<include>*.xml</include>
</includes>
</fileSet>
<fileSet>
<lineEnding>unix</lineEnding>
<useDefaultExcludes>true</useDefaultExcludes>
<includes>
<include>*.xml</include>
</includes>
</fileSet>
<fileSet>
<lineEnding>unix</lineEnding>
<directory>target/site/apidocs/</directory>
<useDefaultExcludes>true</useDefaultExcludes>
<outputDirectory>docs</outputDirectory>
<includes>
<include>**/*</include>
</includes>
</fileSet>
</fileSets>
<fileSet>
<lineEnding>unix</lineEnding>
<directory>target/site/apidocs/</directory>
<useDefaultExcludes>true</useDefaultExcludes>
<outputDirectory>docs</outputDirectory>
<includes>
<include>**/*</include>
</includes>
</fileSet>
</fileSets>
<includeModuleDirectory>true</includeModuleDirectory>
<useDefaultExcludes>true</useDefaultExcludes>
</sources>
<binaries>
<outputDirectory>modules</outputDirectory>
<includeDependencies>true</includeDependencies>
<unpack>false</unpack>
<useDefaultExcludes>true</useDefaultExcludes>
<includes/>
</binaries>
</moduleSet>
</moduleSets>
<includeModuleDirectory>true</includeModuleDirectory>
<useDefaultExcludes>true</useDefaultExcludes>
</sources>
<binaries>
<outputDirectory>modules</outputDirectory>
<includeDependencies>true</includeDependencies>
<unpack>false</unpack>
<useDefaultExcludes>true</useDefaultExcludes>
<includes />
</binaries>
</moduleSet>
</moduleSets>
</assembly>

View File

@ -1,50 +0,0 @@
====
Licensed to Apereo under one or more contributor license
agreements. See the NOTICE file distributed with this work
for additional information regarding copyright ownership.
Apereo licenses this file to you under the Apache License,
Version 2.0 (the "License"); you may not use this file
except in compliance with the License. You may obtain a
copy of the License at the following location:
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
====
License for Use
Copyright (c) 2007, JA-SIG, Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of the JA-SIG, Inc. nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@ -1,42 +0,0 @@
Licensed to Apereo under one or more contributor license
agreements. See the NOTICE file distributed with this work
for additional information regarding copyright ownership.
Apereo licenses this file to you under the Apache License,
Version 2.0 (the "License"); you may not use this file
except in compliance with the License. You may obtain a
copy of the License at the following location:
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
This project includes:
Apache Commons Codec under Apache License, Version 2.0
Apache Log4j under The Apache Software License, Version 2.0
Apache XML Security under The Apache Software License, Version 2.0
Bouncy Castle PKIX, CMS, EAC, TSP, PKCS, OCSP, CMP, and CRMF APIs under Bouncy Castle Licence
Bouncy Castle Provider under Bouncy Castle Licence
Hamcrest Core under New BSD License
Jackson-annotations under The Apache Software License, Version 2.0
Jackson-core under The Apache Software License, Version 2.0
jackson-databind under The Apache Software 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
JCL 1.2 implemented over SLF4J under MIT License
JUnit under Eclipse Public License 1.0
SLF4J API Module under MIT License
SLF4J Simple Binding under MIT License
Spring AOP under Apache License, Version 2.0
Spring Beans under Apache License, Version 2.0
Spring Commons Logging Bridge under Apache License, Version 2.0
Spring Context under Apache License, Version 2.0
Spring Core under Apache License, Version 2.0
Spring Expression Language (SpEL) under Apache License, Version 2.0
Spring TestContext Framework under Apache License, Version 2.0
Spring Web under Apache License, Version 2.0

View File

@ -1,44 +1,53 @@
<!--
Licensed to Apereo under one or more contributor license
agreements. See the NOTICE file distributed with this work
for additional information regarding copyright ownership.
Apereo licenses this file to you under the Apache License,
Version 2.0 (the "License"); you may not use this file
except in compliance with the License. You may obtain a
copy of the License at the following location:
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->
<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">
<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.6.2-SNAPSHOT</version>
<groupId>org.jasig.cas</groupId>
<version>3.1.1</version>
<artifactId>cas-client</artifactId>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>org.jasig.cas</groupId>
<artifactId>cas-client-core</artifactId>
<packaging>jar</packaging>
<name>Jasig CAS Client for Java - Core</name>
<name>JA-SIG CAS Client for Java - Core</name>
<build>
<sourceDirectory>src/main/java</sourceDirectory>
<testSourceDirectory>src/test/java</testSourceDirectory>
<testResources>
<testResource>
<directory>src/test/resources</directory>
<filtering>false</filtering>
</testResource>
</testResources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.1.1</version>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.4</source>
<target>1.4</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<includes>
<include>**/*Tests*</include>
</includes>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-clover-plugin</artifactId>
<configuration>
<licenseLocation>${basedir}/src/test/clover/clover.license</licenseLocation>
</configuration>
<executions>
<execution>
<phase>pre-site</phase>
<goals>
<goal>test-jar</goal>
<goal>instrument</goal>
</goals>
</execution>
</executions>
@ -47,70 +56,49 @@
</build>
<dependencies>
<dependency>
<groupId>xml-security</groupId>
<artifactId>xmlsec</artifactId>
<version>1.3.0</version>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>xml-security</groupId>
<artifactId>xmlsec</artifactId>
<version>1.3.0</version>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${spring.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<scope>provided</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>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<scope>test</scope>
<version>1.2.17</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>
<dependency>
<groupId>org.opensaml</groupId>
<artifactId>opensaml</artifactId>
<version>1.1b</version>
<type>jar</type>
<scope>compile</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>2.5.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>2.5.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>2.5.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>2.5.1</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>

View File

@ -1,51 +0,0 @@
/**
* Licensed to Apereo under one or more contributor license
* agreements. See the NOTICE file distributed with this work
* for additional information regarding copyright ownership.
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at the following location:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
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;
}
}

View File

@ -1,21 +1,3 @@
/**
* Licensed to Apereo under one or more contributor license
* agreements. See the NOTICE file distributed with this work
* for additional information regarding copyright ownership.
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at the following location:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jasig.cas.client.authentication;
import java.io.Serializable;
@ -47,6 +29,6 @@ public interface AttributePrincipal extends Principal, Serializable {
* The Map of key/value pairs associated with this principal.
* @return the map of key/value pairs associated with this principal.
*/
Map<String, Object> getAttributes();
Map getAttributes();
}

View File

@ -1,45 +1,28 @@
/**
* Licensed to Apereo under one or more contributor license
* agreements. See the NOTICE file distributed with this work
* for additional information regarding copyright ownership.
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at the following location:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jasig.cas.client.authentication;
import org.jasig.cas.client.proxy.ProxyRetriever;
import org.jasig.cas.client.util.CommonUtils;
import java.util.Collections;
import java.util.Map;
import org.jasig.cas.client.proxy.ProxyRetriever;
import org.jasig.cas.client.util.CommonUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Concrete implementation of the AttributePrincipal interface.
*
* @author Scott Battaglia
* @version $Revision$ $Date$
* @since 3.1
*/
public class AttributePrincipalImpl extends SimplePrincipal implements AttributePrincipal {
private static final Logger LOGGER = LoggerFactory.getLogger(AttributePrincipalImpl.class);
public class AttributePrincipalImpl implements AttributePrincipal {
/** Unique Id for Serialization */
private static final long serialVersionUID = -1443182634624927187L;
private static final long serialVersionUID = -8810123156070148535L;
/** The unique identifier for this principal. */
private final String name;
/** Map of key/value pairs about this principal. */
private final Map<String, Object> attributes;
private final Map attributes;
/** The CAS 2 ticket used to retrieve a proxy ticket. */
private final String proxyGrantingTicket;
@ -53,7 +36,7 @@ public class AttributePrincipalImpl extends SimplePrincipal implements Attribute
* @param name the unique identifier for the principal.
*/
public AttributePrincipalImpl(final String name) {
this(name, Collections.<String, Object> emptyMap());
this(name, Collections.EMPTY_MAP);
}
/**
@ -62,8 +45,8 @@ public class AttributePrincipalImpl extends SimplePrincipal implements Attribute
* @param name the unique identifier for the principal.
* @param attributes the key/value pairs for this principal.
*/
public AttributePrincipalImpl(final String name, final Map<String, Object> attributes) {
this(name, attributes, null, null);
public AttributePrincipalImpl(final String name, final Map attributes) {
this(name, attributes, null, null);
}
/**
@ -73,41 +56,40 @@ public class AttributePrincipalImpl extends SimplePrincipal implements Attribute
* @param proxyGrantingTicket the ticket associated with this principal.
* @param proxyRetriever the ProxyRetriever implementation to call back to the CAS server.
*/
public AttributePrincipalImpl(final String name, final String proxyGrantingTicket,
final ProxyRetriever proxyRetriever) {
this(name, Collections.<String, Object> emptyMap(), proxyGrantingTicket, proxyRetriever);
public AttributePrincipalImpl(final String name, final String proxyGrantingTicket, final ProxyRetriever proxyRetriever) {
this(name, Collections.EMPTY_MAP, proxyGrantingTicket, proxyRetriever);
}
/**
* Constructs a new principal with the supplied name, attributes, and proxying capabilities.
* Constructs a new principal witht he supplied name, attributes, and proxying capabilities.
*
* @param name the unique identifier for the principal.
* @param attributes the key/value pairs for this principal.
* @param proxyGrantingTicket the ticket associated with this principal.
* @param proxyRetriever the ProxyRetriever implementation to call back to the CAS server.
*/
public AttributePrincipalImpl(final String name, final Map<String, Object> attributes,
final String proxyGrantingTicket, final ProxyRetriever proxyRetriever) {
super(name);
public AttributePrincipalImpl(final String name, final Map attributes, final String proxyGrantingTicket, final ProxyRetriever proxyRetriever) {
this.name = name;
this.attributes = attributes;
this.proxyGrantingTicket = proxyGrantingTicket;
this.proxyRetriever = proxyRetriever;
CommonUtils.assertNotNull(this.name, "name cannot be null.");
CommonUtils.assertNotNull(this.attributes, "attributes cannot be null.");
}
@Override
public Map<String, Object> getAttributes() {
public Map getAttributes() {
return this.attributes;
}
@Override
public String getProxyTicketFor(final String service) {
public String getProxyTicketFor(String service) {
if (proxyGrantingTicket != null) {
return this.proxyRetriever.getProxyTicketIdFor(this.proxyGrantingTicket, service);
}
LOGGER.debug("No ProxyGrantingTicket was supplied, so no Proxy Ticket can be retrieved.");
return null;
}
public String getName() {
return this.name;
}
}

View File

@ -1,28 +1,12 @@
/**
* Licensed to Apereo under one or more contributor license
* agreements. See the NOTICE file distributed with this work
* for additional information regarding copyright ownership.
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at the following location:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
/*
* Copyright 2007 The JA-SIG Collaborative. All rights reserved. See license
* distributed with this file and available online at
* http://www.ja-sig.org/products/cas/overview/license/index.html
*/
package org.jasig.cas.client.authentication;
import org.jasig.cas.client.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;
import org.jasig.cas.client.validation.Assertion;
import javax.servlet.FilterChain;
@ -34,8 +18,6 @@ import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
/**
* Filter implementation to intercept all requests and attempt to authenticate
@ -46,16 +28,18 @@ import java.util.Map;
* <li><code>casServerLoginUrl</code> - the url to log into CAS, i.e. https://cas.rutgers.edu/login</li>
* <li><code>renew</code> - true/false on whether to use renew or not.</li>
* <li><code>gateway</code> - true/false on whether to use gateway or not.</li>
* <li><code>method</code> - the method used by the CAS server to send the user back to the application (redirect or post).</li>
* </ul>
*
* <p>Please see AbstractCasFilter for additional properties.</p>
*
* @author Scott Battaglia
* @author Misagh Moayyed
* @version $Revision: 11768 $ $Date: 2007-02-07 15:44:16 -0500 (Wed, 07 Feb 2007) $
* @since 3.0
*/
public class AuthenticationFilter extends AbstractCasFilter {
public static final String CONST_CAS_GATEWAY = "_const_cas_gateway_";
/**
* The URL to the CAS Server login.
*/
@ -71,155 +55,52 @@ public class AuthenticationFilter extends AbstractCasFilter {
*/
private boolean gateway = false;
/**
* The method used by the CAS server to send the user back to the application.
*/
private String method;
private GatewayResolver gatewayStorage = new DefaultGatewayResolverImpl();
private AuthenticationRedirectStrategy authenticationRedirectStrategy = new DefaultAuthenticationRedirectStrategy();
private UrlPatternMatcherStrategy ignoreUrlPatternMatcherStrategyClass = null;
private String internalIp = null;
private static final String X_REAL_IP = "x-real-ip";
private static final Map<String, Class<? extends UrlPatternMatcherStrategy>> PATTERN_MATCHER_TYPES =
new HashMap<String, Class<? extends UrlPatternMatcherStrategy>>();
static {
PATTERN_MATCHER_TYPES.put("CONTAINS", ContainsPatternUrlPatternMatcherStrategy.class);
PATTERN_MATCHER_TYPES.put("REGEX", RegexUrlPatternMatcherStrategy.class);
PATTERN_MATCHER_TYPES.put("FULL_REGEX", EntireRegionRegexUrlPatternMatcherStrategy.class);
PATTERN_MATCHER_TYPES.put("EXACT", ExactUrlPatternMatcherStrategy.class);
}
public AuthenticationFilter() {
this(Protocol.CAS2);
}
protected AuthenticationFilter(final Protocol protocol) {
super(protocol);
}
@Override
protected void initInternal(final FilterConfig filterConfig) throws ServletException {
if (!isIgnoreInitConfiguration()) {
super.initInternal(filterConfig);
final String loginUrl = getString(ConfigurationKeys.CAS_SERVER_LOGIN_URL);
if (loginUrl != null) {
setCasServerLoginUrl(loginUrl);
} else {
setCasServerUrlPrefix(getString(ConfigurationKeys.CAS_SERVER_URL_PREFIX));
}
setRenew(getBoolean(ConfigurationKeys.RENEW));
setGateway(getBoolean(ConfigurationKeys.GATEWAY));
setMethod(getString(ConfigurationKeys.METHOD));
setInternalIp(getString(ConfigurationKeys.INTERNAL_IP));
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);
if (ignoreUrlMatcherClass != null) {
this.ignoreUrlPatternMatcherStrategyClass = ReflectUtils.newInstance(ignoreUrlMatcherClass.getName());
} else {
try {
logger.trace("Assuming {} is a qualified class name...", ignoreUrlPatternType);
this.ignoreUrlPatternMatcherStrategyClass = ReflectUtils.newInstance(ignoreUrlPatternType);
} catch (final IllegalArgumentException e) {
logger.error("Could not instantiate class [{}]", ignoreUrlPatternType, e);
}
}
if (this.ignoreUrlPatternMatcherStrategyClass != null) {
this.ignoreUrlPatternMatcherStrategyClass.setPattern(ignorePattern);
}
}
final Class<? extends GatewayResolver> gatewayStorageClass = getClass(ConfigurationKeys.GATEWAY_STORAGE_CLASS);
if (gatewayStorageClass != null) {
setGatewayStorage(ReflectUtils.newInstance(gatewayStorageClass));
}
final Class<? extends AuthenticationRedirectStrategy> authenticationRedirectStrategyClass = getClass(ConfigurationKeys.AUTHENTICATION_REDIRECT_STRATEGY_CLASS);
if (authenticationRedirectStrategyClass != null) {
this.authenticationRedirectStrategy = ReflectUtils.newInstance(authenticationRedirectStrategyClass);
}
}
super.initInternal(filterConfig);
setCasServerLoginUrl(getPropertyFromInitParams(filterConfig, "casServerLoginUrl", null));
setRenew(Boolean.parseBoolean(getPropertyFromInitParams(filterConfig, "renew", "false")));
setGateway(Boolean.parseBoolean(getPropertyFromInitParams(filterConfig, "gateway", "false")));
}
@Override
public void init() {
super.init();
final String message = String.format(
"one of %s and %s must not be null.",
ConfigurationKeys.CAS_SERVER_LOGIN_URL.getName(),
ConfigurationKeys.CAS_SERVER_URL_PREFIX.getName());
CommonUtils.assertNotNull(this.casServerLoginUrl, message);
CommonUtils.assertNotNull(this.casServerLoginUrl, "casServerLoginUrl cannot be null.");
}
@Override
public final void doFilter(final ServletRequest servletRequest, final ServletResponse servletResponse,
final FilterChain filterChain) throws IOException, ServletException {
public final void doFilter(final ServletRequest servletRequest, final ServletResponse servletResponse, final FilterChain filterChain) throws IOException, ServletException {
final HttpServletRequest request = (HttpServletRequest) servletRequest;
final HttpServletResponse response = (HttpServletResponse) servletResponse;
if (isInternalRequest(request)) {
logger.debug("Request is ignored [internal].");
filterChain.doFilter(request, response);
return;
}
if (isRequestUrlExcluded(request)) {
logger.debug("Request is ignored.");
filterChain.doFilter(request, response);
return;
}
final HttpSession session = request.getSession(false);
final Assertion assertion = session != null ? (Assertion) session.getAttribute(CONST_CAS_ASSERTION) : null;
final String ticket = request.getParameter(getArtifactParameterName());
final Assertion assertion = session != null ? (Assertion) session
.getAttribute(CONST_CAS_ASSERTION) : null;
final boolean wasGatewayed = session != null
&& session.getAttribute(CONST_CAS_GATEWAY) != null;
if (assertion != null) {
filterChain.doFilter(request, response);
if (CommonUtils.isBlank(ticket) && assertion == null && !wasGatewayed) {
log.debug("no ticket and no assertion found");
if (this.gateway) {
log.debug("setting gateway attribute in session");
request.getSession(true).setAttribute(CONST_CAS_GATEWAY, "yes");
}
final String serviceUrl = constructServiceUrl(request, response);
final String urlToRedirectTo = CommonUtils.constructRedirectUrl(this.casServerLoginUrl, getServiceParameterName(), serviceUrl, this.renew, this.gateway);
if (log.isDebugEnabled()) {
log.debug("redirecting to \"" + urlToRedirectTo + "\"");
}
response.sendRedirect(urlToRedirectTo);
return;
}
final String serviceUrl = constructServiceUrl(request, response);
final String ticket = retrieveTicketFromRequest(request);
final boolean wasGatewayed = this.gateway && this.gatewayStorage.hasGatewayedAlready(request, serviceUrl);
if (CommonUtils.isNotBlank(ticket) || wasGatewayed) {
filterChain.doFilter(request, response);
return;
if (session != null) {
log.debug("removing gateway attribute from session");
session.setAttribute(CONST_CAS_GATEWAY, null);
}
final String modifiedServiceUrl;
logger.debug("no ticket and no assertion found");
if (this.gateway) {
logger.debug("setting gateway attribute in session");
modifiedServiceUrl = this.gatewayStorage.storeGatewayInformation(request, serviceUrl);
} else {
modifiedServiceUrl = serviceUrl;
}
logger.debug("Constructed service url: {}", modifiedServiceUrl);
final String urlToRedirectTo = CommonUtils.constructRedirectUrl(this.casServerLoginUrl,
getProtocol().getServiceParameterName(), modifiedServiceUrl, this.renew, this.gateway, this.method);
logger.debug("redirecting to \"{}\"", urlToRedirectTo);
this.authenticationRedirectStrategy.redirect(request, response, urlToRedirectTo);
filterChain.doFilter(request, response);
}
public final void setRenew(final boolean renew) {
@ -230,52 +111,7 @@ public class AuthenticationFilter extends AbstractCasFilter {
this.gateway = gateway;
}
public void setMethod(final String method) {
this.method = method;
}
public final void setCasServerUrlPrefix(final String casServerUrlPrefix) {
setCasServerLoginUrl(CommonUtils.addTrailingSlash(casServerUrlPrefix) + "login");
}
public final void setCasServerLoginUrl(final String casServerLoginUrl) {
this.casServerLoginUrl = casServerLoginUrl;
}
public void setInternalIp(String internalIp) {
this.internalIp = internalIp;
}
public final void setGatewayStorage(final GatewayResolver gatewayStorage) {
this.gatewayStorage = gatewayStorage;
}
private boolean isInternalRequest(final HttpServletRequest request) {
if (this.internalIp == null) {
return false;
}
String realIp = request.getHeader(X_REAL_IP);
return this.internalIp.equals(realIp);
}
private boolean isRequestUrlExcluded(final HttpServletRequest request) {
if (this.ignoreUrlPatternMatcherStrategyClass == null) {
return false;
}
final StringBuffer urlBuffer = request.getRequestURL();
if (request.getQueryString() != null) {
urlBuffer.append("?").append(request.getQueryString());
}
final String requestUri = urlBuffer.toString();
return this.ignoreUrlPatternMatcherStrategyClass.matches(requestUri);
}
public final void setIgnoreUrlPatternMatcherStrategyClass(
final UrlPatternMatcherStrategy ignoreUrlPatternMatcherStrategyClass) {
this.ignoreUrlPatternMatcherStrategyClass = ignoreUrlPatternMatcherStrategyClass;
}
}

View File

@ -1,46 +0,0 @@
/**
* Licensed to Apereo under one or more contributor license
* agreements. See the NOTICE file distributed with this work
* for additional information regarding copyright ownership.
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at the following location:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jasig.cas.client.authentication;
import java.io.IOException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* Interface to abstract the authentication strategy for redirecting. The traditional method was to always just redirect,
* but due to AJAX, etc. we may need to support other strategies. This interface is designed to hold that logic such that
* authentication filter class does not get crazily complex.
*
* @author Scott Battaglia
* @since 3.3.0
*/
public interface AuthenticationRedirectStrategy {
/**
* Method name is a bit of a misnomer. This method handles "redirection" for a localized version of redirection (i.e. AJAX might mean an XML fragment that contains the url to go to).
*
* @param request the original HttpServletRequest. MAY NOT BE NULL.
* @param response the original HttpServletResponse. MAY NOT BE NULL.
* @param potentialRedirectUrl the url that might be used (there are no guarantees of course!)
* @throws IOException the exception to throw if there is some type of error. This will bubble up through the filter.
*/
void redirect(HttpServletRequest request, HttpServletResponse response, String potentialRedirectUrl)
throws IOException;
}

View File

@ -1,40 +0,0 @@
/**
* Licensed to Apereo under one or more contributor license
* agreements. See the NOTICE file distributed with this work
* for additional information regarding copyright ownership.
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at the following location:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jasig.cas.client.authentication;
/**
* A pattern matcher that looks inside the url to find the exact pattern specified.
*
* @author Misagh Moayyed
* @since 3.3.1
*/
public final class ContainsPatternUrlPatternMatcherStrategy implements UrlPatternMatcherStrategy {
private String pattern;
@Override
public boolean matches(final String url) {
return url.contains(this.pattern);
}
@Override
public void setPattern(final String pattern) {
this.pattern = pattern;
}
}

View File

@ -1,38 +0,0 @@
/**
* Licensed to Apereo under one or more contributor license
* agreements. See the NOTICE file distributed with this work
* for additional information regarding copyright ownership.
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at the following location:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jasig.cas.client.authentication;
import java.io.IOException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* Implementation of the {@link AuthenticationRedirectStrategy} class that preserves the original behavior that existed prior to 3.3.0.
*
* @author Scott Battaglia
* @since 3.3.0
*/
public final class DefaultAuthenticationRedirectStrategy implements AuthenticationRedirectStrategy {
@Override
public void redirect(final HttpServletRequest request, final HttpServletResponse response,
final String potentialRedirectUrl) throws IOException {
response.sendRedirect(potentialRedirectUrl);
}
}

View File

@ -1,45 +0,0 @@
/**
* Licensed to Apereo under one or more contributor license
* agreements. See the NOTICE file distributed with this work
* for additional information regarding copyright ownership.
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at the following location:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jasig.cas.client.authentication;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
public final class DefaultGatewayResolverImpl implements GatewayResolver {
public static final String CONST_CAS_GATEWAY = "_const_cas_gateway_";
@Override
public boolean hasGatewayedAlready(final HttpServletRequest request, final String serviceUrl) {
final HttpSession session = request.getSession(false);
if (session == null) {
return false;
}
final boolean result = session.getAttribute(CONST_CAS_GATEWAY) != null;
return result;
}
@Override
public String storeGatewayInformation(final HttpServletRequest request, final String serviceUrl) {
request.getSession(true).setAttribute(CONST_CAS_GATEWAY, "yes");
return serviceUrl;
}
}

View File

@ -1,53 +0,0 @@
/**
* Licensed to Apereo under one or more contributor license
* agreements. See the NOTICE file distributed with this work
* for additional information regarding copyright ownership.
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at the following location:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jasig.cas.client.authentication;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* A pattern matcher that looks inside the url to find the pattern, that
* is assumed to have been specified via regular expressions syntax.
* The match behavior is based on {@link Matcher#matches()}:
* Attempts to match the entire region against the pattern.
*
* @author Misagh Moayyed
* @since 3.5
*/
public final class EntireRegionRegexUrlPatternMatcherStrategy implements UrlPatternMatcherStrategy {
private Pattern pattern;
public EntireRegionRegexUrlPatternMatcherStrategy() {
}
public EntireRegionRegexUrlPatternMatcherStrategy(final String pattern) {
this.setPattern(pattern);
}
@Override
public boolean matches(final String url) {
return this.pattern.matcher(url).matches();
}
@Override
public void setPattern(final String pattern) {
this.pattern = Pattern.compile(pattern);
}
}

View File

@ -1,48 +0,0 @@
/**
* Licensed to Apereo under one or more contributor license
* agreements. See the NOTICE file distributed with this work
* for additional information regarding copyright ownership.
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at the following location:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jasig.cas.client.authentication;
/**
* A pattern matcher that produces a successful match if the pattern
* specified matches the given url exactly and equally.
*
* @author Misagh Moayyed
* @since 3.3.1
*/
public final class ExactUrlPatternMatcherStrategy implements UrlPatternMatcherStrategy {
private String pattern;
public ExactUrlPatternMatcherStrategy() {}
public ExactUrlPatternMatcherStrategy(final String pattern) {
this.setPattern(pattern);
}
@Override
public boolean matches(final String url) {
return url.equals(this.pattern);
}
@Override
public void setPattern(final String pattern) {
this.pattern = pattern;
}
}

View File

@ -1,54 +0,0 @@
/**
* Licensed to Apereo under one or more contributor license
* agreements. See the NOTICE file distributed with this work
* for additional information regarding copyright ownership.
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at the following location:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jasig.cas.client.authentication;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.jasig.cas.client.util.CommonUtils;
/**
* Implementation of the redirect strategy that can handle a Faces Ajax request in addition to the standard redirect style.
*
* @author Scott Battaglia
* @since 3.3.0
*/
public final class FacesCompatibleAuthenticationRedirectStrategy implements AuthenticationRedirectStrategy {
private static final String FACES_PARTIAL_AJAX_PARAMETER = "javax.faces.partial.ajax";
@Override
public void redirect(final HttpServletRequest request, final HttpServletResponse response,
final String potentialRedirectUrl) throws IOException {
if (CommonUtils.isNotBlank(request.getParameter(FACES_PARTIAL_AJAX_PARAMETER))) {
// this is an ajax request - redirect ajaxly
response.setContentType("text/xml");
response.setStatus(200);
final PrintWriter writer = response.getWriter();
writer.write("<?xml version='1.0' encoding='UTF-8'?>");
writer.write(String.format("<partial-response><redirect url=\"%s\"></redirect></partial-response>",
potentialRedirectUrl));
} else {
response.sendRedirect(potentialRedirectUrl);
}
}
}

View File

@ -1,51 +0,0 @@
/**
* Licensed to Apereo under one or more contributor license
* agreements. See the NOTICE file distributed with this work
* for additional information regarding copyright ownership.
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at the following location:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jasig.cas.client.authentication;
import javax.servlet.http.HttpServletRequest;
/**
* Implementations of this should only have a default constructor if
* you plan on constructing them via the web.xml.
*
* @author Scott Battaglia
* @version $Revision$
* @since 1.0
*
*/
public interface GatewayResolver {
/**
* Determines if the request has been gatewayed already. Should also do gateway clean up.
*
* @param request the Http Servlet Request
* @param serviceUrl the service url
* @return true if yes, false otherwise.
*/
boolean hasGatewayedAlready(HttpServletRequest request, String serviceUrl);
/**
* Storage the request for gatewaying and return the service url, which can be modified.
*
* @param request the HttpServletRequest.
* @param serviceUrl the service url
* @return the potentially modified service url to redirect to
*/
String storeGatewayInformation(HttpServletRequest request, String serviceUrl);
}

View File

@ -1,57 +0,0 @@
/**
* Licensed to Apereo under one or more contributor license
* agreements. See the NOTICE file distributed with this work
* for additional information regarding copyright ownership.
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at the following location:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jasig.cas.client.authentication;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* A pattern matcher that looks inside the url to find the pattern, that
* is assumed to have been specified via regular expressions syntax.
* The match behavior is based on {@link Matcher#find()}:
* Attempts to find the next subsequence of the input sequence that matches
* the pattern. This method starts at the beginning of this matcher's region, or, if
* a previous invocation of the method was successful and the matcher has
* not since been reset, at the first character not matched by the previous
* match.
*
* @author Misagh Moayyed
* @since 3.3.1
*/
public final class RegexUrlPatternMatcherStrategy implements UrlPatternMatcherStrategy {
private Pattern pattern;
public RegexUrlPatternMatcherStrategy() {
}
public RegexUrlPatternMatcherStrategy(final String pattern) {
this.setPattern(pattern);
}
@Override
public boolean matches(final String url) {
return this.pattern.matcher(url).find();
}
@Override
public void setPattern(final String pattern) {
this.pattern = Pattern.compile(pattern);
}
}

View File

@ -1,75 +0,0 @@
/**
* Licensed to Apereo under one or more contributor license
* agreements. See the NOTICE file distributed with this work
* for additional information regarding copyright ownership.
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at the following location:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jasig.cas.client.authentication;
import java.security.Principal;
import java.security.acl.Group;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Set;
/**
* Simple security group implementation
*
* @author Marvin S. Addison
* @version $Revision$
* @since 3.1.11
*
*/
public final class SimpleGroup extends SimplePrincipal implements Group {
/** SimpleGroup.java */
private static final long serialVersionUID = 4382154818494550205L;
/** Group members */
private final Set<Principal> members = new HashSet<Principal>();
/**
* Creates a new group with the given name.
* @param name Group name.
*/
public SimpleGroup(final String name) {
super(name);
}
@Override
public boolean addMember(final Principal user) {
return this.members.add(user);
}
@Override
public boolean isMember(final Principal member) {
return this.members.contains(member);
}
@Override
public Enumeration<? extends Principal> members() {
return Collections.enumeration(this.members);
}
@Override
public boolean removeMember(final Principal user) {
return this.members.remove(user);
}
public String toString() {
return super.toString() + ": " + members.toString();
}
}

View File

@ -1,72 +0,0 @@
/**
* Licensed to Apereo under one or more contributor license
* agreements. See the NOTICE file distributed with this work
* for additional information regarding copyright ownership.
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at the following location:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jasig.cas.client.authentication;
import java.io.Serializable;
import java.security.Principal;
import org.jasig.cas.client.util.CommonUtils;
/**
* Simple security principal implementation.
*
* @author Marvin S. Addison
* @version $Revision$
* @since 3.1.11
*
*/
public class SimplePrincipal implements Principal, Serializable {
/** SimplePrincipal.java */
private static final long serialVersionUID = -5645357206342793145L;
/** The unique identifier for this principal. */
private final String name;
/**
* Creates a new principal with the given name.
* @param name Principal name.
*/
public SimplePrincipal(final String name) {
this.name = name;
CommonUtils.assertNotNull(this.name, "name cannot be null.");
}
@Override
public final String getName() {
return this.name;
}
public String toString() {
return getName();
}
public boolean equals(final Object o) {
if (o == null) {
return false;
} else if (!(o instanceof SimplePrincipal)) {
return false;
} else {
return getName().equals(((SimplePrincipal) o).getName());
}
}
public int hashCode() {
return 37 * getName().hashCode();
}
}

View File

@ -1,42 +0,0 @@
/**
* Licensed to Apereo under one or more contributor license
* agreements. See the NOTICE file distributed with this work
* for additional information regarding copyright ownership.
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at the following location:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jasig.cas.client.authentication;
/**
* Defines an abstraction by which request urls can be matches against a given pattern.
* New instances for all extensions for this strategy interface will be created per
* each request. The client will ultimately invoke the {@link #matches(String)} method
* having already applied and set the pattern via the {@link #setPattern(String)} method.
* The pattern itself will be retrieved via the client configuration.
* @author Misagh Moayyed
* @since 3.3.1
*/
public interface UrlPatternMatcherStrategy {
/**
* Execute the match between the given pattern and the url
* @param url the request url typically with query strings included
* @return true if match is successful
*/
boolean matches(String url);
/**
* The pattern against which the url is compared
* @param pattern
*/
void setPattern(String pattern);
}

View File

@ -1,121 +0,0 @@
/**
* Licensed to Apereo under one or more contributor license
* agreements. See the NOTICE file distributed with this work
* for additional information regarding copyright ownership.
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at the following location:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jasig.cas.client.configuration;
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());
@Override
public final boolean getBoolean(final ConfigurationKey<Boolean> configurationKey) {
return getValue(configurationKey, new Parser<Boolean>() {
@Override
public Boolean parse(final String value) {
return CommonUtils.toBoolean(value);
}
});
}
@Override
public final long getLong(final ConfigurationKey<Long> configurationKey) {
return getValue(configurationKey, new Parser<Long>() {
@Override
public Long parse(final String value) {
return CommonUtils.toLong(value, configurationKey.getDefaultValue());
}
});
}
@Override
public final int getInt(final ConfigurationKey<Integer> configurationKey) {
return getValue(configurationKey, new Parser<Integer>() {
@Override
public Integer parse(final String value) {
return CommonUtils.toInt(value, configurationKey.getDefaultValue());
}
});
}
@Override
public final String getString(final ConfigurationKey<String> configurationKey) {
return getValue(configurationKey, new Parser<String>() {
@Override
public String parse(final String value) {
return value;
}
});
}
@Override
public <T> Class<? extends T> getClass(final ConfigurationKey<Class<? extends T>> configurationKey) {
return getValue(configurationKey, new Parser<Class<? extends T>>() {
@Override
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);
}
}

View File

@ -1,68 +0,0 @@
/**
* Licensed to Apereo under one or more contributor license
* agreements. See the NOTICE file distributed with this work
* for additional information regarding copyright ownership.
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at the following location:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
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;
}
@Override
public String toString() {
return getName();
}
}

View File

@ -1,86 +0,0 @@
/**
* Licensed to Apereo under one or more contributor license
* agreements. See the NOTICE file distributed with this work
* for additional information regarding copyright ownership.
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at the following location:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
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<String> METHOD = new ConfigurationKey<String>("method", null);
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);
ConfigurationKey<String> PRIVATE_KEY_PATH = new ConfigurationKey<String>("privateKeyPath", null);
ConfigurationKey<String> PRIVATE_KEY_ALGORITHM = new ConfigurationKey<String>("privateKeyAlgorithm", "RSA");
/**
* @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> INTERNAL_IP = new ConfigurationKey<String>("internalIp", null);
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> RELAY_STATE_PARAMETER_NAME = new ConfigurationKey<String>("relayStateParameterName", "RelayState");
ConfigurationKey<String> LOGOUT_CALLBACK_PATH = new ConfigurationKey<String>("logoutCallbackPath", null);
}

View File

@ -1,79 +0,0 @@
/**
* Licensed to Apereo under one or more contributor license
* agreements. See the NOTICE file distributed with this work
* for additional information regarding copyright ownership.
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at the following location:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
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);
}

View File

@ -1,74 +0,0 @@
/**
* Licensed to Apereo under one or more contributor license
* agreements. See the NOTICE file distributed with this work
* for additional information regarding copyright ownership.
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at the following location:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
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 (ConfigurationStrategy.class.isAssignableFrom(clazz)) {
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;
}
}

View File

@ -1,94 +0,0 @@
/**
* Licensed to Apereo under one or more contributor license
* agreements. See the NOTICE file distributed with this work
* for additional information regarding copyright ownership.
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at the following location:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
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;
}
}
@Override
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);
}
}
}

View File

@ -1,55 +0,0 @@
/**
* Licensed to Apereo under one or more contributor license
* agreements. See the NOTICE file distributed with this work
* for additional information regarding copyright ownership.
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at the following location:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
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();
@Override
public void init(final FilterConfig filterConfig, final Class<? extends Filter> filterClazz) {
this.webXmlConfigurationStrategy.init(filterConfig, filterClazz);
this.jndiConfigurationStrategy.init(filterConfig, filterClazz);
}
@Override
protected String get(final ConfigurationKey key) {
final String value1 = this.webXmlConfigurationStrategy.get(key);
if (CommonUtils.isNotBlank(value1)) {
return value1;
}
return this.jndiConfigurationStrategy.get(key);
}
}

View File

@ -1,101 +0,0 @@
/**
* Licensed to Apereo under one or more contributor license
* agreements. See the NOTICE file distributed with this work
* for additional information regarding copyright ownership.
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at the following location:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
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.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 final 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);
}
@Override
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);
}
}
}

View File

@ -1,40 +0,0 @@
/**
* Licensed to Apereo under one or more contributor license
* agreements. See the NOTICE file distributed with this work
* for additional information regarding copyright ownership.
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at the following location:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
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 {
@Override
public void init(final FilterConfig filterConfig, final Class<? extends Filter> filterClazz) {
}
@Override
protected String get(final ConfigurationKey configurationKey) {
return System.getProperty(configurationKey.getName());
}
}

View File

@ -1,62 +0,0 @@
/**
* Licensed to Apereo under one or more contributor license
* agreements. See the NOTICE file distributed with this work
* for additional information regarding copyright ownership.
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at the following location:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
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;
@Override
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;
}
@Override
public void init(final FilterConfig filterConfig, final Class<? extends Filter> clazz) {
this.filterConfig = filterConfig;
}
}

View File

@ -1,58 +0,0 @@
/**
* Licensed to Apereo under one or more contributor license
* agreements. See the NOTICE file distributed with this work
* for additional information regarding copyright ownership.
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at the following location:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jasig.cas.client.jaas;
import java.io.Serializable;
import org.jasig.cas.client.authentication.SimplePrincipal;
import org.jasig.cas.client.validation.Assertion;
/**
* Principal implementation that contains the CAS ticket validation assertion.
*
* @author Marvin S. Addison
* @version $Revision$
* @since 3.1.11
*
*/
public class AssertionPrincipal extends SimplePrincipal implements Serializable {
/** AssertionPrincipal.java */
private static final long serialVersionUID = 2288520214366461693L;
/** CAS assertion describing authenticated state */
private final Assertion assertion;
/**
* Creates a new principal containing the CAS assertion.
*
* @param name Principal name.
* @param assertion CAS assertion.
*/
public AssertionPrincipal(final String name, final Assertion assertion) {
super(name);
this.assertion = assertion;
}
/**
* @return CAS ticket validation assertion.
*/
public Assertion getAssertion() {
return this.assertion;
}
}

View File

@ -1,588 +0,0 @@
/**
* Licensed to Apereo under one or more contributor license
* agreements. See the NOTICE file distributed with this work
* for additional information regarding copyright ownership.
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at the following location:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jasig.cas.client.jaas;
import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.io.IOException;
import java.security.Principal;
import java.security.acl.Group;
import java.util.*;
import java.util.concurrent.TimeUnit;
import javax.security.auth.Subject;
import javax.security.auth.callback.*;
import javax.security.auth.login.LoginException;
import javax.security.auth.spi.LoginModule;
import org.jasig.cas.client.authentication.SimpleGroup;
import org.jasig.cas.client.authentication.SimplePrincipal;
import org.jasig.cas.client.util.CommonUtils;
import org.jasig.cas.client.util.ReflectUtils;
import org.jasig.cas.client.validation.Assertion;
import org.jasig.cas.client.validation.TicketValidator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* JAAS login module that delegates to a CAS {@link TicketValidator} component
* for authentication, and on success populates a {@link Subject} with principal
* data including NetID and principal attributes. The module expects to be provided
* with the CAS ticket (required) and service (optional) parameters via
* {@link PasswordCallback} and {@link NameCallback}, respectively, by the
* {@link CallbackHandler} that is part of the JAAS framework in which the servlet
* resides.
*
* <p>
* Module configuration options:
* <ul>
* <li>ticketValidatorClass - Fully-qualified class name of CAS ticket validator class.</li>
* <li>casServerUrlPrefix - URL to root of CAS Web application context.</li>
* <li>service (optional) - CAS service parameter that may be overridden by callback handler.
* NOTE: service must be specified by at least one component such that it is available at
* service ticket validation time</li>
* <li>defaultRoles (optional) - Comma-delimited list of static roles applied to all
* authenticated principals.</li>
* <li>roleAttributeNames (optional) - Comma-delimited list of attribute names that describe
* role data delivered to CAS in the service-ticket validation response that should be
* applied to the current authenticated principal.</li>
* <li>principalGroupName (optional) - The name of a group principal containing the
* primary principal name of the current JAAS subject. The default value is "CallerPrincipal",
* which is suitable for JBoss.</li>
* <li>roleGroupName (optional) - The name of a group principal containing all role data.
* The default value is "Roles", which is suitable for JBoss.</li>
* <li>cacheAssertions (optional) - Flag to enable assertion caching. This may be needed
* for JAAS providers that attempt to periodically reauthenticate to renew principal.
* Since CAS tickets are one-time-use, a cached assertion must be provided on reauthentication.</li>
* <li>cacheTimeout (optional) - Assertion cache timeout in minutes.</li>
* <li>cacheTimeoutUnit (optional) - Assertion cache timeout unit. Must be one of {@link TimeUnit} enumeration
* names, e.g. DAYS, HOURS, MINUTES, SECONDS, MILLISECONDS. Default unit is MINUTES.</li>
* </ul>
*
* <p>
* Module options not explicitly listed above are treated as attributes of the
* given ticket validator class, e.g. <code>tolerance</code> in the following example.
*
* <p>
* Sample jaas.config file entry for this module:
* <pre>
* cas {
* org.jasig.cas.client.jaas.CasLoginModule required
* ticketValidatorClass="org.jasig.cas.client.validation.Saml11TicketValidator"
* casServerUrlPrefix="https://cas.example.com/cas"
* tolerance="20000"
* service="https://webapp.example.com/webapp"
* defaultRoles="admin,operator"
* roleAttributeNames="memberOf,eduPersonAffiliation"
* principalGroupName="CallerPrincipal"
* roleGroupName="Roles";
* }
* </pre>
*
* @author Marvin S. Addison
* @version $Revision$ $Date$
* @since 3.1.11
*
*/
public class CasLoginModule implements LoginModule {
/** Constant for login name stored in shared state. */
public static final String LOGIN_NAME = "javax.security.auth.login.name";
/**
* Default group name for storing caller principal.
* The default value supports JBoss, but is configurable to hopefully
* support other JEE containers.
*/
public static final String DEFAULT_PRINCIPAL_GROUP_NAME = "CallerPrincipal";
/**
* Default group name for storing role membership data.
* The default value supports JBoss, but is configurable to hopefully
* support other JEE containers.
*/
public static final String DEFAULT_ROLE_GROUP_NAME = "Roles";
/**
* Default assertion cache timeout in minutes. Default is 8 hours.
*/
public static final int DEFAULT_CACHE_TIMEOUT = 480;
/** Default assertion cache timeout unit is minutes. */
public static final TimeUnit DEFAULT_CACHE_TIMEOUT_UNIT = TimeUnit.MINUTES;
/**
* Stores mapping of ticket to assertion to support JAAS providers that
* attempt to periodically re-authenticate to renew principal. Since
* CAS tickets are one-time-use, a cached assertion must be provided on
* re-authentication.
*/
protected static final Map<TicketCredential, Assertion> ASSERTION_CACHE = new HashMap<TicketCredential, Assertion>();
/** Logger instance */
protected final Logger logger = LoggerFactory.getLogger(getClass());
/** JAAS authentication subject */
protected Subject subject;
/** JAAS callback handler */
protected CallbackHandler callbackHandler;
/** CAS ticket validator */
protected TicketValidator ticketValidator;
/** CAS service parameter used if no service is provided via TextCallback on login */
protected String service;
/** CAS assertion */
protected Assertion assertion;
/** CAS ticket credential */
protected TicketCredential ticket;
/** Login module shared state */
protected Map<String, Object> sharedState;
/** Roles to be added to all authenticated principals by default */
protected String[] defaultRoles;
/** Names of attributes in the CAS assertion that should be used for role data */
protected final Set<String> roleAttributeNames = new HashSet<String>();
/** Name of JAAS Group containing caller principal */
protected String principalGroupName = DEFAULT_PRINCIPAL_GROUP_NAME;
/** Name of JAAS Group containing role data */
protected String roleGroupName = DEFAULT_ROLE_GROUP_NAME;
/** Enables or disable assertion caching */
protected boolean cacheAssertions;
/** Assertion cache timeout in minutes */
protected int cacheTimeout = DEFAULT_CACHE_TIMEOUT;
/** Units of cache timeout. */
protected TimeUnit cacheTimeoutUnit = DEFAULT_CACHE_TIMEOUT_UNIT;
/**
* Initializes the CAS login module.
*
* @param subject Authentication subject.
* @param handler Callback handler.
* @param state Shared state map.
* @param options Login module options. The following are supported:
* <ul>
* <li>service - CAS service URL used for service ticket validation.</li>
* <li>ticketValidatorClass - fully-qualified class name of service ticket validator component.</li>
* <li>defaultRoles (optional) - comma-delimited list of roles to be added to all authenticated principals.</li>
* <li>roleAttributeNames (optional) - comma-delimited list of attributes in the CAS assertion that contain role data.</li>
* <li>principalGroupName (optional) - name of JAAS Group containing caller principal.</li>
* <li>roleGroupName (optional) - name of JAAS Group containing role data</li>
* <li>cacheAssertions (optional) - whether or not to cache assertions.
* Some JAAS providers attempt to reauthenticate users after an indeterminate
* period of time. Since the credential used for authentication is a CAS ticket,
* which by default are single use, reauthentication fails. Assertion caching addresses this
* behavior.</li>
* <li>cacheTimeout (optional) - assertion cache timeout in minutes.</li>
* <li>cacheTimeoutUnit (optional) - Assertion cache timeout unit. Must be one of {@link TimeUnit} enumeration
* names, e.g. DAYS, HOURS, MINUTES, SECONDS, MILLISECONDS. Default unit is MINUTES.</li>
* </ul>
*/
@Override
public final void initialize(final Subject subject, final CallbackHandler handler, final Map<String, ?> state,
final Map<String, ?> options) {
this.assertion = null;
this.callbackHandler = handler;
this.subject = subject;
this.sharedState = (Map<String, Object>) state;
this.sharedState = new HashMap<String, Object>(state);
String ticketValidatorClass = null;
for (final String key : options.keySet()) {
logger.trace("Processing option {}", key);
if ("service".equals(key)) {
this.service = (String) options.get(key);
logger.debug("Set service={}", this.service);
} else if ("ticketValidatorClass".equals(key)) {
ticketValidatorClass = (String) options.get(key);
logger.debug("Set ticketValidatorClass={}", ticketValidatorClass);
} else if ("defaultRoles".equals(key)) {
final String roles = (String) options.get(key);
logger.trace("Got defaultRoles value {}", roles);
this.defaultRoles = roles.split(",\\s*");
logger.debug("Set defaultRoles={}", Arrays.asList(this.defaultRoles));
} else if ("roleAttributeNames".equals(key)) {
final String attrNames = (String) options.get(key);
logger.trace("Got roleAttributeNames value {}", attrNames);
final String[] attributes = attrNames.split(",\\s*");
this.roleAttributeNames.addAll(Arrays.asList(attributes));
logger.debug("Set roleAttributeNames={}", this.roleAttributeNames);
} else if ("principalGroupName".equals(key)) {
this.principalGroupName = (String) options.get(key);
logger.debug("Set principalGroupName={}", this.principalGroupName);
} else if ("roleGroupName".equals(key)) {
this.roleGroupName = (String) options.get(key);
logger.debug("Set roleGroupName={}", this.roleGroupName);
} else if ("cacheAssertions".equals(key)) {
this.cacheAssertions = Boolean.parseBoolean((String) options.get(key));
logger.debug("Set cacheAssertions={}", this.cacheAssertions);
} else if ("cacheTimeout".equals(key)) {
this.cacheTimeout = Integer.parseInt((String) options.get(key));
logger.debug("Set cacheTimeout={}", this.cacheTimeout);
} else if ("cacheTimeoutUnit".equals(key)) {
this.cacheTimeoutUnit = Enum.valueOf(TimeUnit.class, (String) options.get(key));
logger.debug("Set cacheTimeoutUnit={}", this.cacheTimeoutUnit);
}
}
if (this.cacheAssertions) {
cleanCache();
}
CommonUtils.assertNotNull(ticketValidatorClass, "ticketValidatorClass is required.");
this.ticketValidator = createTicketValidator(ticketValidatorClass, options);
}
/**
* Operations to perform before doing login.
*
* @return true if you'd like login to continue, false otherwise.
*/
protected boolean preLogin() {
return true;
}
/**
* This occurs after logout is processed.
*
* @param result the result from the login attempt.
*/
protected void postLogin(final boolean result) {
// template method
}
@Override
public final boolean login() throws LoginException {
logger.debug("Performing login.");
if (!preLogin()) {
logger.debug("preLogin failed.");
return false;
}
final NameCallback serviceCallback = new NameCallback("service");
final PasswordCallback ticketCallback = new PasswordCallback("ticket", false);
boolean result = false;
try {
try {
this.callbackHandler.handle(new Callback[] { ticketCallback, serviceCallback });
} catch (final IOException e) {
logger.info("Login failed due to IO exception in callback handler", e);
throw (LoginException) new LoginException("IO exception in callback handler: " + e).initCause(e);
} catch (final UnsupportedCallbackException e) {
logger.info("Login failed due to unsupported callback", e);
throw (LoginException) new LoginException(
"Callback handler does not support PasswordCallback and TextInputCallback.").initCause(e);
}
if (ticketCallback.getPassword() != null) {
this.ticket = new TicketCredential(new String(ticketCallback.getPassword()));
final String service = CommonUtils.isNotBlank(serviceCallback.getName()) ? serviceCallback.getName()
: this.service;
if (this.cacheAssertions) {
this.assertion = ASSERTION_CACHE.get(ticket);
if (this.assertion != null) {
logger.debug("Assertion found in cache.");
}
}
if (this.assertion == null) {
logger.debug("CAS assertion is null; ticket validation required.");
if (CommonUtils.isBlank(service)) {
logger.info("Login failed because required CAS service parameter not provided.");
throw new LoginException(
"Neither login module nor callback handler provided required service parameter.");
}
try {
logger.debug("Attempting ticket validation with service={} and ticket={}", service,
this.ticket);
this.assertion = this.ticketValidator.validate(this.ticket.getName(), service);
} catch (final Exception e) {
logger.info("Login failed due to CAS ticket validation failure", e);
throw (LoginException) new LoginException("CAS ticket validation failed: " + e).initCause(e);
}
}
logger.info("Login succeeded.");
} else {
logger.info("Login failed because callback handler did not provide CAS ticket.");
throw new LoginException("Callback handler did not provide CAS ticket.");
}
result = true;
} finally {
postLogin(result);
}
return result;
}
@Override
public final boolean abort() throws LoginException {
if (this.ticket != null) {
this.ticket = null;
}
if (this.assertion != null) {
this.assertion = null;
}
return true;
}
/**
* Operations to perform before doing commit.
*
* @return true if you'd like commit to continue, false otherwise.
*/
protected boolean preCommit() {
return true;
}
/**
* This occurs after commit is processed.
*
* @param result the result from the login attempt.
*/
protected void postCommit(final boolean result) {
// template method
}
@Override
public final boolean commit() throws LoginException {
if (!preCommit()) {
return false;
}
boolean result = false;
try {
if (this.assertion != null) {
if (this.ticket != null) {
this.subject.getPrivateCredentials().add(this.ticket);
} else {
throw new LoginException("Ticket credential not found.");
}
final AssertionPrincipal casPrincipal = new AssertionPrincipal(this.assertion.getPrincipal().getName(),
this.assertion);
this.subject.getPrincipals().add(casPrincipal);
// Add group containing principal as sole member
// Supports JBoss JAAS use case
final Group principalGroup = new SimpleGroup(this.principalGroupName);
principalGroup.addMember(casPrincipal);
this.subject.getPrincipals().add(principalGroup);
// Add group principal containing role data
final Group roleGroup = new SimpleGroup(this.roleGroupName);
for (final String defaultRole : defaultRoles) {
roleGroup.addMember(new SimplePrincipal(defaultRole));
}
final Map<String, Object> attributes = this.assertion.getPrincipal().getAttributes();
for (final String key : attributes.keySet()) {
if (this.roleAttributeNames.contains(key)) {
// Attribute value is Object if singular or Collection if plural
final Object value = attributes.get(key);
if (value instanceof Collection<?>) {
for (final Object o : (Collection<?>) value) {
roleGroup.addMember(new SimplePrincipal(o.toString()));
}
} else {
roleGroup.addMember(new SimplePrincipal(value.toString()));
}
}
}
this.subject.getPrincipals().add(roleGroup);
// Place principal name in shared state for downstream JAAS modules (module chaining use case)
this.sharedState.put(LOGIN_NAME, assertion.getPrincipal().getName());
logger.debug("Created JAAS subject with principals: {}", subject.getPrincipals());
if (this.cacheAssertions) {
logger.debug("Caching assertion for principal {}", this.assertion.getPrincipal());
ASSERTION_CACHE.put(this.ticket, this.assertion);
}
} else {
// Login must have failed if there is no assertion defined
// Need to clean up state
if (this.ticket != null) {
this.ticket = null;
}
}
result = true;
} finally {
postCommit(result);
}
return result;
}
@Override
public final boolean logout() throws LoginException {
logger.debug("Performing logout.");
if (!preLogout()) {
return false;
}
// Remove cache entry if assertion caching is enabled
if (this.cacheAssertions) {
for (final TicketCredential ticket : this.subject.getPrivateCredentials(TicketCredential.class)) {
logger.debug("Removing cached assertion for {}", ticket);
ASSERTION_CACHE.remove(ticket);
}
}
// Remove all CAS principals
removePrincipalsOfType(AssertionPrincipal.class);
removePrincipalsOfType(SimplePrincipal.class);
removePrincipalsOfType(SimpleGroup.class);
// Remove all CAS credentials
removeCredentialsOfType(TicketCredential.class);
logger.info("Logout succeeded.");
postLogout();
return true;
}
/**
* Happens before logout occurs.
*
* @return true if we should continue, false otherwise.
*/
protected boolean preLogout() {
return true;
}
/**
* Happens after logout.
*/
protected void postLogout() {
// template method
}
/**
* Creates a {@link TicketValidator} instance from a class name and map of property name/value pairs.
* @param className Fully-qualified name of {@link TicketValidator} concrete class.
* @param propertyMap Map of property name/value pairs to set on validator instance.
* @return Ticket validator with properties set.
*/
private TicketValidator createTicketValidator(final String className, final Map<String, ?> propertyMap) {
CommonUtils.assertTrue(propertyMap.containsKey("casServerUrlPrefix"),
"Required property casServerUrlPrefix not found.");
final Class<TicketValidator> validatorClass = ReflectUtils.loadClass(className);
final TicketValidator validator = ReflectUtils.newInstance(validatorClass,
propertyMap.get("casServerUrlPrefix"));
try {
final BeanInfo info = Introspector.getBeanInfo(validatorClass);
for (final String property : propertyMap.keySet()) {
if (!"casServerUrlPrefix".equals(property)) {
logger.debug("Attempting to set TicketValidator property {}", property);
final String value = (String) propertyMap.get(property);
final PropertyDescriptor pd = ReflectUtils.getPropertyDescriptor(info, property);
if (pd != null) {
ReflectUtils.setProperty(property, convertIfNecessary(pd, value), validator, info);
logger.debug("Set {} = {}", property, value);
} else {
logger.warn("Cannot find property {} on {}", property, className);
}
}
}
} catch (final IntrospectionException e) {
throw new RuntimeException("Error getting bean info for " + validatorClass, e);
}
return validator;
}
/**
* Attempts to do simple type conversion from a string value to the type expected
* by the given property.
*
* Currently only conversion to int, long, and boolean are supported.
*
* @param pd Property descriptor of target property to set.
* @param value Property value as a string.
* @return Value converted to type expected by property if a conversion strategy exists.
*/
private static Object convertIfNecessary(final PropertyDescriptor pd, final String value) {
if (String.class.equals(pd.getPropertyType())) {
return value;
} else if (boolean.class.equals(pd.getPropertyType())) {
return Boolean.valueOf(value);
} else if (int.class.equals(pd.getPropertyType())) {
return new Integer(value);
} else if (long.class.equals(pd.getPropertyType())) {
return new Long(value);
} else {
throw new IllegalArgumentException("No conversion strategy exists for property " + pd.getName()
+ " of type " + pd.getPropertyType());
}
}
/**
* Removes all principals of the given type from the JAAS subject.
* @param clazz Type of principal to remove.
*/
private void removePrincipalsOfType(final Class<? extends Principal> clazz) {
this.subject.getPrincipals().removeAll(this.subject.getPrincipals(clazz));
}
/**
* Removes all credentials of the given type from the JAAS subject.
* @param clazz Type of principal to remove.
*/
private void removeCredentialsOfType(final Class<? extends Principal> clazz) {
this.subject.getPrivateCredentials().removeAll(this.subject.getPrivateCredentials(clazz));
}
/**
* Removes expired entries from the assertion cache.
*/
private void cleanCache() {
logger.debug("Cleaning assertion cache of size {}", ASSERTION_CACHE.size());
final Iterator<Map.Entry<TicketCredential, Assertion>> iter = ASSERTION_CACHE.entrySet().iterator();
final Calendar cutoff = Calendar.getInstance();
cutoff.setTimeInMillis(System.currentTimeMillis() - this.cacheTimeoutUnit.toMillis(this.cacheTimeout));
while (iter.hasNext()) {
final Assertion assertion = iter.next().getValue();
final Calendar created = Calendar.getInstance();
created.setTime(assertion.getValidFromDate());
if (created.before(cutoff)) {
logger.debug("Removing expired assertion for principal {}", assertion.getPrincipal());
iter.remove();
}
}
}
}

View File

@ -1,66 +0,0 @@
/**
* Licensed to Apereo under one or more contributor license
* agreements. See the NOTICE file distributed with this work
* for additional information regarding copyright ownership.
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at the following location:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jasig.cas.client.jaas;
import java.io.IOException;
import javax.security.auth.callback.*;
/**
* Callback handler that provides the CAS service and ticket to a
* {@link NameCallback} and {@link PasswordCallback} respectively,
* which meets the requirements of the {@link CasLoginModule} JAAS module.
*
* @author Marvin S. Addison
* @version $Revision$
* @since 3.1.11
*
*/
public class ServiceAndTicketCallbackHandler implements CallbackHandler {
/** CAS service URL */
private final String service;
/** CAS service ticket */
private final String ticket;
/**
* Creates a new instance with the given service and ticket.
*
* @param service CAS service URL.
* @param ticket CAS service ticket.
*/
public ServiceAndTicketCallbackHandler(final String service, final String ticket) {
this.service = service;
this.ticket = ticket;
}
@Override
public void handle(final Callback[] callbacks) throws IOException, UnsupportedCallbackException {
for (final Callback callback : callbacks) {
if (callback instanceof NameCallback) {
((NameCallback) callback).setName(this.service);
} else if (callback instanceof PasswordCallback) {
((PasswordCallback) callback).setPassword(this.ticket.toCharArray());
} else {
throw new UnsupportedCallbackException(callback, "Callback not supported.");
}
}
}
}

View File

@ -1,94 +0,0 @@
/**
* Licensed to Apereo under one or more contributor license
* agreements. See the NOTICE file distributed with this work
* for additional information regarding copyright ownership.
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at the following location:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jasig.cas.client.jaas;
import java.io.IOException;
import java.security.GeneralSecurityException;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.jasig.cas.client.Protocol;
import org.jasig.cas.client.util.AbstractCasFilter;
import org.jasig.cas.client.util.CommonUtils;
/**
* Servlet filter performs a programmatic JAAS login using the Servlet 3.0 HttpServletRequest#login() facility.
* This component should be compatible with any servlet container that supports the Servlet 3.0/JEE6 specification.
* <p>
* The filter executes when it receives a CAS ticket and expects the
* {@link CasLoginModule} JAAS module to perform the CAS
* ticket validation in order to produce an {@link org.jasig.cas.client.jaas.AssertionPrincipal} from which
* the CAS assertion is obtained and inserted into the session to enable SSO.
* <p>
* If a <code>service</code> init-param is specified for this filter, it supersedes
* the service defined for the {@link CasLoginModule}.
*
* @author Daniel Fisher
* @author Marvin S. Addison
* @since 3.3
*/
public final class Servlet3AuthenticationFilter extends AbstractCasFilter {
public Servlet3AuthenticationFilter() {
super(Protocol.CAS2);
}
@Override
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, getProtocol().getArtifactParameterName());
if (session != null && session.getAttribute(CONST_CAS_ASSERTION) == null && ticket != null) {
try {
final String service = constructServiceUrl(request, response);
logger.debug("Attempting CAS ticket validation with service={} and ticket={}", service, ticket);
request.login(service, ticket);
if (request.getUserPrincipal() instanceof AssertionPrincipal) {
final AssertionPrincipal principal = (AssertionPrincipal) request.getUserPrincipal();
logger.debug("Installing CAS assertion into session.");
request.getSession().setAttribute(CONST_CAS_ASSERTION, principal.getAssertion());
} else {
logger.debug("Aborting -- principal is not of type AssertionPrincipal");
throw new GeneralSecurityException("JAAS authentication did not produce CAS AssertionPrincipal.");
}
} catch (final ServletException e) {
logger.debug("JAAS authentication failed.");
response.sendError(HttpServletResponse.SC_FORBIDDEN, e.getMessage());
} catch (final GeneralSecurityException e) {
response.sendError(HttpServletResponse.SC_FORBIDDEN, e.getMessage());
}
} else if (session != null && request.getUserPrincipal() == null) {
// There is evidence that in some cases the principal can disappear
// in JBoss despite a valid session.
// This block forces consistency between principal and assertion.
logger.info("User principal not found. Removing CAS assertion from session to force re-authentication.");
session.removeAttribute(CONST_CAS_ASSERTION);
}
chain.doFilter(request, response);
}
}

View File

@ -1,75 +0,0 @@
/**
* Licensed to Apereo under one or more contributor license
* agreements. See the NOTICE file distributed with this work
* for additional information regarding copyright ownership.
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at the following location:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jasig.cas.client.jaas;
import java.security.Principal;
/**
* Strongly-typed wrapper for a ticket credential.
*
* @author Marvin S. Addison
* @version $Revision$ $Date$
* @since 3.1.12
*
*/
public final class TicketCredential implements Principal {
/** Hash code seed value */
private static final int HASHCODE_SEED = 17;
/** Ticket ID string */
private final String ticket;
/**
* Creates a new instance that wraps the given ticket.
* @param ticket Ticket identifier string.
*/
public TicketCredential(final String ticket) {
this.ticket = ticket;
}
@Override
public String getName() {
return this.ticket;
}
public String toString() {
return this.ticket;
}
public boolean equals(final Object o) {
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
final TicketCredential that = (TicketCredential) o;
if (ticket != null ? !ticket.equals(that.ticket) : that.ticket != null)
return false;
return true;
}
public int hashCode() {
int hash = HASHCODE_SEED;
hash = hash * 31 + (ticket == null ? 0 : ticket.hashCode());
return hash;
}
}

View File

@ -1,112 +0,0 @@
/**
* Licensed to Apereo under one or more contributor license
* agreements. See the NOTICE file distributed with this work
* for additional information regarding copyright ownership.
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at the following location:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
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;
import java.security.spec.InvalidKeySpecException;
import javax.crypto.Cipher;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESedeKeySpec;
/**
* Provides encryption capabilities. Not entirely safe to configure since we have no way of controlling the
* key and cipher being set.
*
* @author Scott Battaglia
* @version $Revision$ $Date$
* @since 3.2.0
*/
public abstract class AbstractEncryptedProxyGrantingTicketStorageImpl implements ProxyGrantingTicketStorage {
private Key key;
private String cipherAlgorithm = ConfigurationKeys.CIPHER_ALGORITHM.getDefaultValue();
public final void setSecretKey(final String key) throws NoSuchAlgorithmException, InvalidKeyException,
InvalidKeySpecException {
this.key = SecretKeyFactory.getInstance(this.cipherAlgorithm).generateSecret(new DESedeKeySpec(key.getBytes()));
}
public final void setSecretKey(final Key key) {
this.key = key;
}
/**
* Note: you MUST call this method before calling setSecretKey if you're not using the default algorithm. You've been warned.
*
* @param cipherAlgorithm the cipher algorithm.
*/
public final void setCipherAlgorithm(final String cipherAlgorithm) {
this.cipherAlgorithm = cipherAlgorithm;
}
@Override
public final void save(final String proxyGrantingTicketIou, final String proxyGrantingTicket) {
saveInternal(proxyGrantingTicketIou, encrypt(proxyGrantingTicket));
}
@Override
public final String retrieve(final String proxyGrantingTicketIou) {
return decrypt(retrieveInternal(proxyGrantingTicketIou));
}
protected abstract void saveInternal(String proxyGrantingTicketIou, String proxyGrantingTicket);
protected abstract String retrieveInternal(String proxyGrantingTicketIou);
private String encrypt(final String value) {
if (this.key == null) {
return value;
}
if (value == null) {
return null;
}
try {
final Cipher cipher = Cipher.getInstance(this.cipherAlgorithm);
cipher.init(Cipher.ENCRYPT_MODE, this.key);
return new String(cipher.doFinal(value.getBytes()));
} catch (final Exception e) {
throw new RuntimeException(e);
}
}
private String decrypt(final String value) {
if (this.key == null) {
return value;
}
if (value == null) {
return null;
}
try {
final Cipher cipher = Cipher.getInstance(this.cipherAlgorithm);
cipher.init(Cipher.DECRYPT_MODE, this.key);
return new String(cipher.doFinal(value.getBytes()));
} catch (final Exception e) {
throw new RuntimeException(e);
}
}
}

View File

@ -1,111 +1,106 @@
/**
* Licensed to Apereo under one or more contributor license
* agreements. See the NOTICE file distributed with this work
* for additional information regarding copyright ownership.
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at the following location:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
/*
* Copyright 2007 The JA-SIG Collaborative. All rights reserved. See license
* distributed with this file and available online at
* http://www.ja-sig.org/products/cas/overview/license/index.html
*/
package org.jasig.cas.client.proxy;
import java.net.URL;
import java.net.URLEncoder;
import org.jasig.cas.client.ssl.HttpURLConnectionFactory;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jasig.cas.client.util.CommonUtils;
import org.jasig.cas.client.util.XmlUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
/**
* Implementation of a ProxyRetriever that follows the CAS 2.0 specification.
* For more information on the CAS 2.0 specification, please see the <a
* href="http://www.jasig.org/cas/protocol">specification
* href="http://www.ja-sig.org/products/cas/overview/protocol/index.html">specification
* document</a>.
* <p/>
* In general, this class will make a call to the CAS server with some specified
* parameters and receive an XML response to parse.
*
* @author Scott Battaglia
* @version $Revision: 11729 $ $Date: 2007-09-26 14:22:30 -0400 (Tue, 26 Sep 2007) $
* @since 3.0
*/
public final class Cas20ProxyRetriever implements ProxyRetriever {
/** Unique Id for serialization. */
private static final long serialVersionUID = 560409469568911792L;
private static final Logger logger = LoggerFactory.getLogger(Cas20ProxyRetriever.class);
/**
* Instance of Commons Logging.
*/
private final Log log = LogFactory.getLog(this.getClass());
/**
* Url to CAS server.
*/
private final String casServerUrl;
private final String encoding;
/** 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.
*
* @param casServerUrl the URL to the CAS server (i.e. http://localhost/cas/)
* @param encoding the encoding to use.
* @param urlFactory url connection factory use when retrieving proxy responses from the server
*/
public Cas20ProxyRetriever(final String casServerUrl, final String encoding,
final HttpURLConnectionFactory urlFactory) {
CommonUtils.assertNotNull(casServerUrl, "casServerUrl cannot be null.");
public Cas20ProxyRetriever(final String casServerUrl) {
CommonUtils.assertNotNull(casServerUrl,
"casServerUrl cannot be null.");
this.casServerUrl = casServerUrl;
this.encoding = encoding;
this.urlConnectionFactory = urlFactory;
}
@Override
public String getProxyTicketIdFor(final String proxyGrantingTicketId, final String targetService) {
CommonUtils.assertNotNull(proxyGrantingTicketId, "proxyGrantingTicketId cannot be null.");
CommonUtils.assertNotNull(targetService, "targetService cannot be null.");
public String getProxyTicketIdFor(final String proxyGrantingTicketId,
final String targetService) {
final URL url = constructUrl(proxyGrantingTicketId, targetService);
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)) {
logger.debug(error);
return null;
}
final String ticket = XmlUtils.getTextForElement(response, "proxyTicket");
logger.debug("Got proxy ticket {}", ticket);
return ticket;
}
private URL constructUrl(final String proxyGrantingTicketId, final String targetService) {
final String url = constructUrl(proxyGrantingTicketId, targetService);
HttpURLConnection conn = null;
try {
return new URL(this.casServerUrl + (this.casServerUrl.endsWith("/") ? "" : "/") + "proxy" + "?pgt="
+ proxyGrantingTicketId + "&targetService=" + URLEncoder.encode(targetService, "UTF-8"));
final URL constructedUrl = new URL(url);
conn = (HttpURLConnection) constructedUrl.openConnection();
final BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
String line;
final StringBuffer stringBuffer = new StringBuffer(255);
final String response;
synchronized (stringBuffer) {
while ((line = in.readLine()) != null) {
stringBuffer.append(line);
}
response = stringBuffer.toString();
}
final String error = XmlUtils.getTextForElement(response,
"proxyFailure");
if (CommonUtils.isNotEmpty(error)) {
log.debug(error);
return null;
}
return XmlUtils.getTextForElement(response, "proxyTicket");
} catch (final Exception e) {
throw new RuntimeException(e);
} finally {
if (conn != null) {
conn.disconnect();
}
}
}
private String constructUrl(final String proxyGrantingTicketId,
final String targetService) {
try {
return this.casServerUrl + "proxy" + "?pgt="
+ proxyGrantingTicketId + "&targetService="
+ URLEncoder.encode(targetService, "UTF-8");
} catch (final UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
}
}

View File

@ -1,46 +0,0 @@
/**
* Licensed to Apereo under one or more contributor license
* agreements. See the NOTICE file distributed with this work
* for additional information regarding copyright ownership.
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at the following location:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jasig.cas.client.proxy;
import java.util.TimerTask;
/**
* A {@link TimerTask} implementation which performs the
* actual 'cleaning' by calling {@link ProxyGrantingTicketStorage#cleanUp()}.
* <p>
* By default, the {@link org.jasig.cas.client.validation.Cas20ProxyReceivingTicketValidationFilter} configures
* a task that cleans up the {@link org.jasig.cas.client.proxy.ProxyGrantingTicketStorage} associated with it.
*
* @author Brad Cupit (brad [at] lsu {dot} edu)
* @version $Revision$ $Date$
* @since 3.1.6
*/
public final class CleanUpTimerTask extends TimerTask {
private final ProxyGrantingTicketStorage proxyGrantingTicketStorage;
public CleanUpTimerTask(final ProxyGrantingTicketStorage proxyGrantingTicketStorage) {
this.proxyGrantingTicketStorage = proxyGrantingTicketStorage;
}
@Override
public void run() {
this.proxyGrantingTicketStorage.cleanUp();
}
}

View File

@ -1,20 +1,7 @@
/**
* Licensed to Apereo under one or more contributor license
* agreements. See the NOTICE file distributed with this work
* for additional information regarding copyright ownership.
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at the following location:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
/*
* Copyright 2007 The JA-SIG Collaborative. All rights reserved. See license
* distributed with this file and available online at
* http://www.ja-sig.org/products/cas/overview/license/index.html
*/
package org.jasig.cas.client.proxy;
@ -23,6 +10,7 @@ package org.jasig.cas.client.proxy;
* them to a specific ProxyGrantingTicketIou.
*
* @author Scott Battaglia
* @version $Revision: 11729 $ $Date: 2007-09-26 14:22:30 -0400 (Tue, 26 Sep 2007) $
* @since 3.0
*/
public interface ProxyGrantingTicketStorage {
@ -45,10 +33,4 @@ public interface ProxyGrantingTicketStorage {
* @return the ProxyGrantingTicket Id or null if it can't be found
*/
public String retrieve(String proxyGrantingTicketIou);
/**
* Called on a regular basis by an external timer,
* giving implementations a chance to remove stale data.
*/
public void cleanUp();
}

View File

@ -1,44 +1,28 @@
/**
* Licensed to Apereo under one or more contributor license
* agreements. See the NOTICE file distributed with this work
* for additional information regarding copyright ownership.
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at the following location:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
/*
* Copyright 2007 The JA-SIG Collaborative. All rights reserved. See license
* distributed with this file and available online at
* http://www.ja-sig.org/products/cas/overview/license/index.html
*/
package org.jasig.cas.client.proxy;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import org.jasig.cas.client.util.CommonUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Implementation of {@link ProxyGrantingTicketStorage} that is backed by a
* HashMap that keeps a ProxyGrantingTicket for a specified amount of time.
* <p>
* {@link ProxyGrantingTicketStorage#cleanUp()} must be called on a regular basis to
* keep the HashMap from growing indefinitely.
* <p/>
* A cleanup thread is run periodically to clean out the HashMap.
*
* @author Scott Battaglia
* @author Brad Cupit (brad [at] lsu {dot} edu)
* @version $Revision: 11729 $ $Date: 2007-09-26 14:22:30 -0400 (Tue, 26 Sep 2007) $
* @since 3.0
*/
public final class ProxyGrantingTicketStorageImpl implements ProxyGrantingTicketStorage {
private final Logger logger = LoggerFactory.getLogger(getClass());
public final class ProxyGrantingTicketStorageImpl implements
ProxyGrantingTicketStorage {
/**
* Default timeout in milliseconds.
@ -48,15 +32,7 @@ public final class ProxyGrantingTicketStorageImpl implements ProxyGrantingTicket
/**
* Map that stores the PGTIOU to PGT mappings.
*/
private final ConcurrentMap<String, ProxyGrantingTicketHolder> cache = new ConcurrentHashMap<String, ProxyGrantingTicketHolder>();
/**
* time, in milliseconds, before a {@link ProxyGrantingTicketHolder}
* is considered expired and ready for removal.
*
* @see ProxyGrantingTicketStorageImpl#DEFAULT_TIMEOUT
*/
private final long timeout;
private final Map cache = new HashMap();
/**
* Constructor set the timeout to the default value.
@ -72,55 +48,38 @@ public final class ProxyGrantingTicketStorageImpl implements ProxyGrantingTicket
* @param timeout the time to hold on to the ProxyGrantingTicket
*/
public ProxyGrantingTicketStorageImpl(final long timeout) {
this.timeout = timeout;
final Thread thread = new ProxyGrantingTicketCleanupThread(
timeout, this.cache);
thread.setDaemon(true);
thread.start();
}
/**
* NOTE: you can only retrieve a ProxyGrantingTicket once with this method.
* Its removed after retrieval.
*/
@Override
public String retrieve(final String proxyGrantingTicketIou) {
if (CommonUtils.isBlank(proxyGrantingTicketIou)) {
return null;
}
final ProxyGrantingTicketHolder holder = this.cache.get(proxyGrantingTicketIou);
final ProxyGrantingTicketHolder holder = (ProxyGrantingTicketHolder) this.cache
.get(proxyGrantingTicketIou);
if (holder == null) {
logger.info("No Proxy Ticket found for [{}].", proxyGrantingTicketIou);
return null;
}
this.cache.remove(proxyGrantingTicketIou);
this.cache.remove(holder);
logger.debug("Returned ProxyGrantingTicket of [{}]", holder.getProxyGrantingTicket());
return holder.getProxyGrantingTicket();
}
@Override
public void save(final String proxyGrantingTicketIou, final String proxyGrantingTicket) {
final ProxyGrantingTicketHolder holder = new ProxyGrantingTicketHolder(proxyGrantingTicket);
logger.debug("Saving ProxyGrantingTicketIOU and ProxyGrantingTicket combo: [{}, {}]", proxyGrantingTicketIou,
public void save(final String proxyGrantingTicketIou,
final String proxyGrantingTicket) {
final ProxyGrantingTicketHolder holder = new ProxyGrantingTicketHolder(
proxyGrantingTicket);
this.cache.put(proxyGrantingTicketIou, holder);
}
/**
* Cleans up old, expired proxy tickets. This method must be
* called regularly via an external thread or timer.
*/
@Override
public void cleanUp() {
for (final Map.Entry<String, ProxyGrantingTicketHolder> holder : this.cache.entrySet()) {
if (holder.getValue().isExpired(this.timeout)) {
this.cache.remove(holder.getKey());
}
}
}
private static final class ProxyGrantingTicketHolder {
private final class ProxyGrantingTicketHolder {
private final String proxyGrantingTicket;
@ -139,4 +98,48 @@ public final class ProxyGrantingTicketStorageImpl implements ProxyGrantingTicket
return System.currentTimeMillis() - this.timeInserted > timeout;
}
}
private final class ProxyGrantingTicketCleanupThread extends Thread {
private final long timeout;
private final Map cache;
public ProxyGrantingTicketCleanupThread(final long timeout,
final Map cache) {
this.timeout = timeout;
this.cache = cache;
}
public void run() {
while (true) {
try {
Thread.sleep(this.timeout);
} catch (final InterruptedException e) {
// nothing to do
}
final List itemsToRemove = new ArrayList();
synchronized (this.cache) {
for (final Iterator iter = this.cache.keySet().iterator(); iter
.hasNext();) {
final Object key = iter.next();
final ProxyGrantingTicketHolder holder = (ProxyGrantingTicketHolder) this.cache
.get(key);
if (holder.isExpired(this.timeout)) {
itemsToRemove.add(key);
}
}
for (final Iterator iter = itemsToRemove.iterator(); iter
.hasNext();) {
this.cache.remove(iter.next());
}
}
}
}
}
}

View File

@ -1,33 +1,19 @@
/**
* Licensed to Apereo under one or more contributor license
* agreements. See the NOTICE file distributed with this work
* for additional information regarding copyright ownership.
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at the following location:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
/*
* Copyright 2007 The JA-SIG Collaborative. All rights reserved. See license
* distributed with this file and available online at
* http://www.ja-sig.org/products/cas/overview/license/index.html
*/
package org.jasig.cas.client.proxy;
import java.io.Serializable;
/**
* Interface to abstract the retrieval of a proxy ticket to make the
* implementation a black box to the client.
*
* @author Scott Battaglia
* @version $Revision: 11729 $ $Date: 2007-09-26 14:22:30 -0400 (Tue, 26 Sep 2007) $
* @since 3.0
*/
public interface ProxyRetriever extends Serializable {
public interface ProxyRetriever {
/**
* Retrieves a proxy ticket for a specific targetService.
@ -36,5 +22,6 @@ public interface ProxyRetriever extends Serializable {
* @param targetService the service we want to proxy.
* @return the ProxyTicket Id if Granted, null otherwise.
*/
String getProxyTicketIdFor(String proxyGrantingTicketId, String targetService);
String getProxyTicketIdFor(String proxyGrantingTicketId,
String targetService);
}

View File

@ -1,23 +1,3 @@
<!--
Licensed to Apereo under one or more contributor license
agreements. See the NOTICE file distributed with this work
for additional information regarding copyright ownership.
Apereo licenses this file to you under the Apache License,
Version 2.0 (the "License"); you may not use this file
except in compliance with the License. You may obtain a
copy of the License at the following location:
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->
<html>
<body>
<p>The proxy package includes a servlet to act as a proxy receptor,

View File

@ -1,28 +1,14 @@
/**
* Licensed to Apereo under one or more contributor license
* agreements. See the NOTICE file distributed with this work
* for additional information regarding copyright ownership.
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at the following location:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
/*
* Copyright 2007 The JA-SIG Collaborative. All rights reserved. See license
* distributed with this file and available online at
* http://www.ja-sig.org/products/cas/overview/license/index.html
*/
package org.jasig.cas.client.session;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.http.HttpSession;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* HashMap backed implementation of SessionMappingStorage.
@ -32,52 +18,38 @@ import org.slf4j.LoggerFactory;
* @since 3.1
*
*/
public final class HashMapBackedSessionMappingStorage implements SessionMappingStorage {
public final class HashMapBackedSessionMappingStorage implements
SessionMappingStorage {
/**
* Maps the ID from the CAS server to the Session.
*/
private final Map<String, HttpSession> MANAGED_SESSIONS = new HashMap<String, HttpSession>();
private final Map MANAGED_SESSIONS = new HashMap();
/**
* Maps the Session ID to the key from the CAS Server.
*/
private final Map<String, String> ID_TO_SESSION_KEY_MAPPING = new HashMap<String, String>();
private final Map ID_TO_SESSION_KEY_MAPPING = new HashMap();
private final Logger logger = LoggerFactory.getLogger(getClass());
@Override
public synchronized void addSessionById(final String mappingId, final HttpSession session) {
public void addSessionById(String mappingId, HttpSession session) {
ID_TO_SESSION_KEY_MAPPING.put(session.getId(), mappingId);
MANAGED_SESSIONS.put(mappingId, session);
}
}
@Override
public synchronized void removeBySessionById(final String sessionId) {
logger.debug("Attempting to remove Session=[{}]", sessionId);
final String key = ID_TO_SESSION_KEY_MAPPING.get(sessionId);
if (logger.isDebugEnabled()) {
if (key != null) {
logger.debug("Found mapping for session. Session Removed.");
} else {
logger.debug("No mapping for session found. Ignoring.");
}
}
public void removeBySessionById(String sessionId) {
final String key = (String) ID_TO_SESSION_KEY_MAPPING.get(sessionId);
MANAGED_SESSIONS.remove(key);
ID_TO_SESSION_KEY_MAPPING.remove(sessionId);
}
}
@Override
public synchronized HttpSession removeSessionByMappingId(final String mappingId) {
final HttpSession session = MANAGED_SESSIONS.get(mappingId);
public HttpSession removeSessionByMappingId(String mappingId) {
final HttpSession session = (HttpSession) MANAGED_SESSIONS.get(mappingId);
if (session != null) {
removeBySessionById(session.getId());
removeBySessionById(session.getId());
}
return session;
}
}
}

View File

@ -1,20 +1,7 @@
/**
* Licensed to Apereo under one or more contributor license
* agreements. See the NOTICE file distributed with this work
* for additional information regarding copyright ownership.
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at the following location:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
/*
* Copyright 2007 The JA-SIG Collaborative. All rights reserved. See license
* distributed with this file and available online at
* http://www.ja-sig.org/products/cas/overview/license/index.html
*/
package org.jasig.cas.client.session;
@ -29,26 +16,26 @@ import javax.servlet.http.HttpSession;
*
*/
public interface SessionMappingStorage {
/**
* Remove the HttpSession based on the mappingId.
*
* @param mappingId the id the session is keyed under.
* @return the HttpSession if it exists.
*/
HttpSession removeSessionByMappingId(String mappingId);
/**
* Remove a session by its Id.
* @param sessionId the id of the session.
*/
void removeBySessionById(String sessionId);
/**
* Add a session by its mapping Id.
* @param mappingId the id to map the session to.
* @param session the HttpSession.
*/
void addSessionById(String mappingId, HttpSession session);
/**
* Remove the HttpSession based on the mappingId.
*
* @param mappingId the id the session is keyed under.
* @return the HttpSession if it exists.
*/
HttpSession removeSessionByMappingId(String mappingId);
/**
* Remove a session by its Id.
* @param sessionId the id of the session.
*/
void removeBySessionById(String sessionId);
/**
* Add a session by its mapping Id.
* @param mappingId the id to map the session to.
* @param session the HttpSession.
*/
void addSessionById(String mappingId, HttpSession session);
}

View File

@ -1,32 +1,22 @@
/**
* Licensed to Apereo under one or more contributor license
* agreements. See the NOTICE file distributed with this work
* for additional information regarding copyright ownership.
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at the following location:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
/*
* Copyright 2007 The JA-SIG Collaborative. All rights reserved. See license
* distributed with this file and available online at
* http://www.ja-sig.org/products/cas/overview/license/index.html
*/
package org.jasig.cas.client.session;
import java.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;
import org.jasig.cas.client.util.CommonUtils;
import org.jasig.cas.client.util.XmlUtils;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.io.IOException;
/**
* Implements the Single Sign Out protocol. It handles registering the session and destroying the session.
@ -37,70 +27,66 @@ import org.jasig.cas.client.util.AbstractConfigurationFilter;
*/
public final class SingleSignOutFilter extends AbstractConfigurationFilter {
private static final SingleSignOutHandler HANDLER = new SingleSignOutHandler();
/**
* The name of the artifact parameter. This is used to capture the session identifier.
*/
private String artifactParameterName = "ticket";
private static SessionMappingStorage SESSION_MAPPING_STORAGE = new HashMapBackedSessionMappingStorage();
private final AtomicBoolean handlerInitialized = new AtomicBoolean(false);
@Override
public void init(final FilterConfig filterConfig) throws ServletException {
super.init(filterConfig);
if (!isIgnoreInitConfiguration()) {
setArtifactParameterName(getString(ConfigurationKeys.ARTIFACT_PARAMETER_NAME));
setLogoutParameterName(getString(ConfigurationKeys.LOGOUT_PARAMETER_NAME));
setRelayStateParameterName(getString(ConfigurationKeys.RELAY_STATE_PARAMETER_NAME));
setLogoutCallbackPath(getString(ConfigurationKeys.LOGOUT_CALLBACK_PATH));
HANDLER.setArtifactParameterOverPost(getBoolean(ConfigurationKeys.ARTIFACT_PARAMETER_OVER_POST));
HANDLER.setEagerlyCreateSessions(getBoolean(ConfigurationKeys.EAGERLY_CREATE_SESSIONS));
setArtifactParameterName(getPropertyFromInitParams(filterConfig, "artifactParameterName", "ticket"));
init();
}
public void init() {
CommonUtils.assertNotNull(this.artifactParameterName, "artifactParameterName cannot be null.");
CommonUtils.assertNotNull(SESSION_MAPPING_STORAGE, "sessionMappingStorage cannote be null.");
}
public void setArtifactParameterName(final String artifactParameterName) {
this.artifactParameterName = artifactParameterName;
}
public void doFilter(final ServletRequest servletRequest, final ServletResponse servletResponse, final FilterChain filterChain) throws IOException, ServletException {
final HttpServletRequest request = (HttpServletRequest) servletRequest;
if ("POST".equals(request.getMethod())) {
final String logoutRequest = request.getParameter("logoutRequest");
if (CommonUtils.isNotBlank(logoutRequest)) {
final String sessionIdentifier = XmlUtils.getTextForElement(logoutRequest, "SessionIndex");
if (CommonUtils.isNotBlank(sessionIdentifier)) {
final HttpSession session = SESSION_MAPPING_STORAGE.removeSessionByMappingId(sessionIdentifier);
if (session != null) {
session.invalidate();
}
return;
}
}
} else {
final String artifact = request.getParameter(this.artifactParameterName);
final HttpSession session = request.getSession();
if (CommonUtils.isNotBlank(artifact)) {
SESSION_MAPPING_STORAGE.addSessionById(artifact, session);
}
}
HANDLER.init();
handlerInitialized.set(true);
}
public void setArtifactParameterName(final String name) {
HANDLER.setArtifactParameterName(name);
}
public void setLogoutParameterName(final String name) {
HANDLER.setLogoutParameterName(name);
filterChain.doFilter(servletRequest, servletResponse);
}
public void setRelayStateParameterName(final String name) {
HANDLER.setRelayStateParameterName(name);
}
public void setLogoutCallbackPath(final String logoutCallbackPath) {
HANDLER.setLogoutCallbackPath(logoutCallbackPath);
}
public void setSessionMappingStorage(final SessionMappingStorage storage) {
HANDLER.setSessionMappingStorage(storage);
SESSION_MAPPING_STORAGE = storage;
}
public static SessionMappingStorage getSessionMappingStorage() {
return SESSION_MAPPING_STORAGE;
}
@Override
public void doFilter(final ServletRequest servletRequest, final ServletResponse servletResponse,
final FilterChain filterChain) throws IOException, ServletException {
final HttpServletRequest request = (HttpServletRequest) servletRequest;
final HttpServletResponse response = (HttpServletResponse) servletResponse;
/**
* <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);
}
}
@Override
public void destroy() {
// nothing to do
}
protected static SingleSignOutHandler getSingleSignOutHandler() {
return HANDLER;
}
}

View File

@ -1,333 +0,0 @@
/**
* Licensed to Apereo under one or more contributor license
* agreements. See the NOTICE file distributed with this work
* for additional information regarding copyright ownership.
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at the following location:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jasig.cas.client.session;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.zip.Inflater;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import javax.xml.bind.DatatypeConverter;
import org.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;
import org.slf4j.LoggerFactory;
/**
* Performs CAS single sign-out operations in an API-agnostic fashion.
*
* @author Marvin S. Addison
* @version $Revision$ $Date$
* @since 3.1.12
*
*/
public final class SingleSignOutHandler {
private final static int DECOMPRESSION_FACTOR = 10;
/** Logger instance */
private final Logger logger = LoggerFactory.getLogger(getClass());
/** Mapping of token IDs and session IDs to HTTP sessions */
private SessionMappingStorage sessionMappingStorage = new HashMapBackedSessionMappingStorage();
/** The name of the artifact parameter. This is used to capture the session identifier. */
private String artifactParameterName = Protocol.CAS2.getArtifactParameterName();
/** Parameter name that stores logout request for SLO */
private String logoutParameterName = ConfigurationKeys.LOGOUT_PARAMETER_NAME.getDefaultValue();
/** Parameter name that stores the state of the CAS server webflow for the callback */
private String relayStateParameterName = ConfigurationKeys.RELAY_STATE_PARAMETER_NAME.getDefaultValue();
/** The logout callback path configured at the CAS server, if there is one */
private String logoutCallbackPath;
private boolean artifactParameterOverPost = false;
private boolean eagerlyCreateSessions = true;
private List<String> safeParameters;
private final LogoutStrategy logoutStrategy = isServlet30() ? new Servlet30LogoutStrategy() : new Servlet25LogoutStrategy();
public void setSessionMappingStorage(final SessionMappingStorage storage) {
this.sessionMappingStorage = storage;
}
public void setArtifactParameterOverPost(final boolean artifactParameterOverPost) {
this.artifactParameterOverPost = artifactParameterOverPost;
}
public SessionMappingStorage getSessionMappingStorage() {
return this.sessionMappingStorage;
}
/**
* @param name Name of the authentication token parameter.
*/
public void setArtifactParameterName(final String name) {
this.artifactParameterName = name;
}
/**
* @param name Name of parameter containing CAS logout request message for SLO.
*/
public void setLogoutParameterName(final String name) {
this.logoutParameterName = name;
}
/**
* @param logoutCallbackPath The logout callback path configured at the CAS server.
*/
public void setLogoutCallbackPath(final String logoutCallbackPath) {
this.logoutCallbackPath = logoutCallbackPath;
}
/**
* @param name Name of parameter containing the state of the CAS server webflow.
*/
public void setRelayStateParameterName(final String name) {
this.relayStateParameterName = name;
}
public void setEagerlyCreateSessions(final boolean eagerlyCreateSessions) {
this.eagerlyCreateSessions = eagerlyCreateSessions;
}
/**
* Initializes the component for use.
*/
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.sessionMappingStorage, "sessionMappingStorage cannot be null.");
CommonUtils.assertNotNull(this.relayStateParameterName, "relayStateParameterName cannot be null.");
if (this.artifactParameterOverPost) {
this.safeParameters = Arrays.asList(this.logoutParameterName, this.artifactParameterName);
} else {
this.safeParameters = Collections.singletonList(this.logoutParameterName);
}
}
}
/**
* Determines whether the given request contains an authentication token.
*
* @param request HTTP reqest.
*
* @return True if request contains authentication token, false otherwise.
*/
private boolean isTokenRequest(final HttpServletRequest request) {
return CommonUtils.isNotBlank(CommonUtils.safeGetParameter(request, this.artifactParameterName,
this.safeParameters));
}
/**
* Determines whether the given request is a CAS logout request.
*
* @param request HTTP request.
*
* @return True if request is logout request, false otherwise.
*/
private boolean isLogoutRequest(final HttpServletRequest request) {
if ("POST".equalsIgnoreCase(request.getMethod())) {
return !isMultipartRequest(request)
&& pathEligibleForLogout(request)
&& CommonUtils.isNotBlank(CommonUtils.safeGetParameter(request, this.logoutParameterName,
this.safeParameters));
}
if ("GET".equalsIgnoreCase(request.getMethod())) {
return CommonUtils.isNotBlank(CommonUtils.safeGetParameter(request, this.logoutParameterName, this.safeParameters));
}
return false;
}
private boolean pathEligibleForLogout(final HttpServletRequest request) {
return logoutCallbackPath == null || logoutCallbackPath.equals(getPath(request));
}
private String getPath(final HttpServletRequest request) {
return request.getServletPath() + CommonUtils.nullToEmpty(request.getPathInfo());
}
/**
* Process a request regarding the SLO process: record the session or destroy it.
*
* @param request the incoming HTTP request.
* @param response the HTTP response.
* @return if the request should continue to be processed.
*/
public boolean process(final HttpServletRequest request, final HttpServletResponse response) {
if (isTokenRequest(request)) {
logger.trace("Received a token request");
recordSession(request);
return true;
}
if (isLogoutRequest(request)) {
logger.trace("Received a logout request");
destroySession(request);
return false;
}
logger.trace("Ignoring URI for logout: {}", request.getRequestURI());
return true;
}
/**
* Associates a token request with the current HTTP session by recording the mapping
* in the the configured {@link SessionMappingStorage} container.
*
* @param request HTTP request containing an authentication token.
*/
private void recordSession(final HttpServletRequest request) {
final HttpSession session = request.getSession(this.eagerlyCreateSessions);
if (session == null) {
logger.debug("No session currently exists (and none created). Cannot record session information for single sign out.");
return;
}
final String token = CommonUtils.safeGetParameter(request, this.artifactParameterName, this.safeParameters);
logger.debug("Recording session for token {}", token);
try {
this.sessionMappingStorage.removeBySessionById(session.getId());
} catch (final Exception e) {
// ignore if the session is already marked as invalid. Nothing we can do!
}
sessionMappingStorage.addSessionById(token, session);
}
/**
* Uncompress a logout message (base64 + deflate).
*
* @param originalMessage the original logout message.
* @return the uncompressed logout message.
*/
private String uncompressLogoutMessage(final String originalMessage) {
final byte[] binaryMessage = DatatypeConverter.parseBase64Binary(originalMessage);
Inflater decompresser = null;
try {
// decompress the bytes
decompresser = new Inflater();
decompresser.setInput(binaryMessage);
final byte[] result = new byte[binaryMessage.length * DECOMPRESSION_FACTOR];
final int resultLength = decompresser.inflate(result);
// decode the bytes into a String
return new String(result, 0, resultLength, "UTF-8");
} catch (final Exception e) {
logger.error("Unable to decompress logout message", e);
throw new RuntimeException(e);
} finally {
if (decompresser != null) {
decompresser.end();
}
}
}
/**
* Destroys the current HTTP session for the given CAS logout request.
*
* @param request HTTP request containing a CAS logout message.
*/
private void destroySession(final HttpServletRequest request) {
String logoutMessage = CommonUtils.safeGetParameter(request, this.logoutParameterName, this.safeParameters);
if (CommonUtils.isBlank(logoutMessage)) {
logger.error("Could not locate logout message of the request from {}", this.logoutParameterName);
return;
}
if (!logoutMessage.contains("SessionIndex")) {
logoutMessage = uncompressLogoutMessage(logoutMessage);
}
logger.trace("Logout request:\n{}", logoutMessage);
final String token = XmlUtils.getTextForElement(logoutMessage, "SessionIndex");
if (CommonUtils.isNotBlank(token)) {
final HttpSession session = this.sessionMappingStorage.removeSessionByMappingId(token);
if (session != null) {
final String sessionID = session.getId();
logger.debug("Invalidating session [{}] for token [{}]", sessionID, token);
try {
session.invalidate();
} catch (final IllegalStateException e) {
logger.debug("Error invalidating session.", e);
}
this.logoutStrategy.logout(request);
}
}
}
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 {
@Override
public void logout(final HttpServletRequest request) {
// nothing additional to do here
}
}
private class Servlet30LogoutStrategy implements LogoutStrategy {
@Override
public void logout(final HttpServletRequest request) {
try {
request.logout();
} catch (final ServletException e) {
logger.debug("Error performing request.logout.");
}
}
}
}

View File

@ -1,20 +1,7 @@
/**
* Licensed to Apereo under one or more contributor license
* agreements. See the NOTICE file distributed with this work
* for additional information regarding copyright ownership.
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at the following location:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
/*
* Copyright 2007 The JA-SIG Collaborative. All rights reserved. See license
* distributed with this file and available online at
* http://www.ja-sig.org/products/cas/overview/license/index.html
*/
package org.jasig.cas.client.session;
@ -34,20 +21,18 @@ import javax.servlet.http.HttpSessionListener;
*/
public final class SingleSignOutHttpSessionListener implements HttpSessionListener {
private SessionMappingStorage sessionMappingStorage;
@Override
private SessionMappingStorage SESSION_MAPPING_STORAGE;
public void sessionCreated(final HttpSessionEvent event) {
// nothing to do at the moment
}
@Override
public void sessionDestroyed(final HttpSessionEvent event) {
if (sessionMappingStorage == null) {
sessionMappingStorage = getSessionMappingStorage();
}
if (SESSION_MAPPING_STORAGE == null) {
SESSION_MAPPING_STORAGE = getSessionMappingStorage();
}
final HttpSession session = event.getSession();
sessionMappingStorage.removeBySessionById(session.getId());
SESSION_MAPPING_STORAGE.removeBySessionById(session.getId());
}
/**
@ -57,6 +42,6 @@ public final class SingleSignOutHttpSessionListener implements HttpSessionListen
* @return the SessionMappingStorage
*/
protected static SessionMappingStorage getSessionMappingStorage() {
return SingleSignOutFilter.getSingleSignOutHandler().getSessionMappingStorage();
return SingleSignOutFilter.getSessionMappingStorage();
}
}

View File

@ -1,40 +0,0 @@
/**
* Licensed to Apereo under one or more contributor license
* agreements. See the NOTICE file distributed with this work
* for additional information regarding copyright ownership.
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at the following location:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jasig.cas.client.ssl;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLSession;
/**
* Hostname verifier that performs no host name verification for an SSL peer
* such that all hosts are allowed.
*
* @author Marvin Addison
* @version $Revision$ $Date$
* @since 3.1.10
*/
public final class AnyHostnameVerifier implements HostnameVerifier {
/** {@inheritDoc} */
@Override
public boolean verify(final String hostname, final SSLSession session) {
return true;
}
}

View File

@ -1,46 +0,0 @@
/**
* Licensed to Apereo under one or more contributor license
* agreements. See the NOTICE file distributed with this work
* for additional information regarding copyright ownership.
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at the following location:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jasig.cas.client.ssl;
import java.io.Serializable;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
/**
* A factory to prepare and configure {@link java.net.URLConnection} instances.
*
* @author Misagh Moayyed
* @since 3.3
*/
public interface HttpURLConnectionFactory extends Serializable {
/**
* Receives a {@link URLConnection} instance typically as a result of a {@link URL}
* opening a connection to a remote resource. The received url connection is then
* configured and prepared appropriately depending on its type and is then returned to the caller
* to accommodate method chaining.
*
* @param url The url connection that needs to be configured
* @return The configured {@link HttpURLConnection} instance
*
* @see {@link HttpsURLConnectionFactory}
*/
HttpURLConnection buildHttpURLConnection(final URLConnection url);
}

View File

@ -1,192 +0,0 @@
/**
* Licensed to Apereo under one or more contributor license
* agreements. See the NOTICE file distributed with this work
* for additional information regarding copyright ownership.
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at the following location:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jasig.cas.client.ssl;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URLConnection;
import java.security.KeyStore;
import java.util.Properties;
import javax.net.ssl.*;
import org.jasig.cas.client.util.CommonUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* An implementation of the {@link HttpURLConnectionFactory} whose responsible to configure
* the underlying <i>https</i> connection, if needed, with a given hostname and SSL socket factory based on the
* configuration provided.
*
* @author Misagh Moayyed
* @since 3.3
* @see #setHostnameVerifier(HostnameVerifier)
* @see #setSSLConfiguration(Properties)
*/
public final class HttpsURLConnectionFactory implements HttpURLConnectionFactory {
private static final long serialVersionUID = 1L;
private static final Logger LOGGER = LoggerFactory.getLogger(HttpsURLConnectionFactory.class);
/**
* Hostname verifier used when making an SSL request to the CAS server.
* Defaults to {@link HttpsURLConnection#getDefaultHostnameVerifier()}
*/
private HostnameVerifier hostnameVerifier = HttpsURLConnection.getDefaultHostnameVerifier();
/**
* Properties file that can contains key/trust info for Client Side Certificates
*/
private Properties sslConfiguration = new Properties();
public HttpsURLConnectionFactory() {
}
public HttpsURLConnectionFactory(final HostnameVerifier verifier, final Properties config) {
setHostnameVerifier(verifier);
setSSLConfiguration(config);
}
public final void setSSLConfiguration(final Properties config) {
this.sslConfiguration = config;
}
/**
* Set the host name verifier for the https connection received.
*
* @see AnyHostnameVerifier
* @see RegexHostnameVerifier
* @see WhitelistHostnameVerifier
*/
public final void setHostnameVerifier(final HostnameVerifier verifier) {
this.hostnameVerifier = verifier;
}
@Override
public HttpURLConnection buildHttpURLConnection(final URLConnection url) {
return this.configureHttpsConnectionIfNeeded(url);
}
/**
* Configures the connection with specific settings for secure http connections
* If the connection instance is not a {@link HttpsURLConnection},
* no additional changes will be made and the connection itself is simply returned.
*
* @param conn the http connection
*/
private HttpURLConnection configureHttpsConnectionIfNeeded(final URLConnection conn) {
if (conn instanceof HttpsURLConnection) {
final HttpsURLConnection httpsConnection = (HttpsURLConnection) conn;
final SSLSocketFactory socketFactory = this.createSSLSocketFactory();
if (socketFactory != null) {
httpsConnection.setSSLSocketFactory(socketFactory);
}
if (this.hostnameVerifier != null) {
httpsConnection.setHostnameVerifier(this.hostnameVerifier);
}
}
return (HttpURLConnection) conn;
}
/**
* Creates a {@link SSLSocketFactory} based on the configuration specified
* <p>
* Sample properties file:
* <pre>
* protocol=TLS
* keyStoreType=JKS
* keyStorePath=/var/secure/location/.keystore
* keyStorePass=changeit
* certificatePassword=aGoodPass
* </pre>
* @return the {@link SSLSocketFactory}
*/
private SSLSocketFactory createSSLSocketFactory() {
InputStream keyStoreIS = null;
try {
final SSLContext sslContext = SSLContext.getInstance(this.sslConfiguration.getProperty("protocol", "SSL"));
if (this.sslConfiguration.getProperty("keyStoreType") != null) {
final KeyStore keyStore = KeyStore.getInstance(this.sslConfiguration.getProperty("keyStoreType"));
if (this.sslConfiguration.getProperty("keyStorePath") != null) {
keyStoreIS = new FileInputStream(this.sslConfiguration.getProperty("keyStorePath"));
if (this.sslConfiguration.getProperty("keyStorePass") != null) {
keyStore.load(keyStoreIS, this.sslConfiguration.getProperty("keyStorePass").toCharArray());
LOGGER.debug("Keystore has {} keys", keyStore.size());
final KeyManagerFactory keyManager = KeyManagerFactory.getInstance(this.sslConfiguration
.getProperty("keyManagerType", "SunX509"));
keyManager.init(keyStore, this.sslConfiguration.getProperty("certificatePassword")
.toCharArray());
sslContext.init(keyManager.getKeyManagers(), null, null);
return sslContext.getSocketFactory();
}
}
}
} catch (final Exception e) {
LOGGER.error(e.getMessage(), e);
} finally {
CommonUtils.closeQuietly(keyStoreIS);
}
return null;
}
@Override
public boolean equals(final 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();
}
}

View File

@ -1,56 +0,0 @@
/**
* Licensed to Apereo under one or more contributor license
* agreements. See the NOTICE file distributed with this work
* for additional information regarding copyright ownership.
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at the following location:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
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;
/**
* Validates an SSL peer's hostname using a regular expression that a candidate
* host must match in order to be verified.
*
* @author Marvin Addison
* @version $Revision$ $Date$
* @since 3.1.10
*
*/
public final class RegexHostnameVerifier implements HostnameVerifier, Serializable {
private static final long serialVersionUID = 1L;
/** Allowed hostname pattern */
private final Pattern pattern;
/**
* Creates a new instance using the given regular expression.
*
* @param regex Regular expression describing allowed hosts.
*/
public RegexHostnameVerifier(final String regex) {
this.pattern = Pattern.compile(regex);
}
/** {@inheritDoc} */
@Override
public boolean verify(final String hostname, final SSLSession session) {
return pattern.matcher(hostname).matches();
}
}

View File

@ -1,70 +0,0 @@
/**
* Licensed to Apereo under one or more contributor license
* agreements. See the NOTICE file distributed with this work
* for additional information regarding copyright ownership.
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at the following location:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
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.
*
* @author Marvin Addison
* @version $Revision$ $Date$
* @since 3.1.10
*
*/
public final class WhitelistHostnameVerifier implements HostnameVerifier, Serializable {
private static final long serialVersionUID = 1L;
/** Allowed hosts */
private final String[] allowedHosts;
/**
* Creates a new instance using the given array of allowed hosts.
*
* @param allowed Array of allowed hosts.
*/
public WhitelistHostnameVerifier(final String[] allowed) {
this.allowedHosts = allowed;
}
/**
* Creates a new instance using the given list of allowed hosts.
*
* @param allowedList Comma-separated list of allowed hosts.
*/
public WhitelistHostnameVerifier(final String allowedList) {
this.allowedHosts = allowedList.split(",\\s*");
}
/** {@inheritDoc} */
@Override
public boolean verify(final String hostname, final SSLSession session) {
for (final String allowedHost : this.allowedHosts) {
if (hostname.equalsIgnoreCase(allowedHost)) {
return true;
}
}
return false;
}
}

View File

@ -1,53 +1,41 @@
/**
* Licensed to Apereo under one or more contributor license
* agreements. See the NOTICE file distributed with this work
* for additional information regarding copyright ownership.
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at the following location:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jasig.cas.client.util;
import org.jasig.cas.client.Protocol;
import org.jasig.cas.client.configuration.ConfigurationKeys;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Arrays;
/**
* Abstract filter that contains code that is common to all CAS filters.
* <p>
* The following filter options can be configured (either at the context-level or filter-level).
* <ul>
* <li><code>serverName</code> - the name of the CAS client server, in the format: localhost:8080 or localhost:8443 or localhost or https://localhost:8443</li>
* <li><code>serverName</code> - the name of the CAS server, in the format: localhost:8080 or localhost:8443 or localhost</li>
* <li><code>service</code> - the completely qualified service url, i.e. https://localhost/cas-client/app</li>
* </ul>
* <p>Please note that one of the two above parameters must be set.</p>
*
* @author Scott Battaglia
* @author Misagh Moayyed
* @version $Revision$ $Date$
* @since 3.1
*/
public abstract class AbstractCasFilter extends AbstractConfigurationFilter {
/** Represents the constant for where the assertion will be located in memory. */
public static final String CONST_CAS_ASSERTION = "_const_cas_assertion_";
private final Protocol protocol;
/** Instance of commons logging for logging purposes. */
protected final Log log = LogFactory.getLog(getClass());
/** Defines the parameter to look for for the artifact. */
private String artifactParameterName = "ticket";
/** Defines the parameter to look for for the service. */
private String serviceParameterName = "service";
/** Sets where response.encodeUrl should be called on service urls when constructed. */
private boolean encodeServiceUrl = true;
@ -59,91 +47,64 @@ public abstract class AbstractCasFilter extends AbstractConfigurationFilter {
/** The exact url of the service. */
private String service;
protected AbstractCasFilter(final Protocol protocol) {
this.protocol = protocol;
}
@Override
public final void init(final FilterConfig filterConfig) throws ServletException {
super.init(filterConfig);
if (!isIgnoreInitConfiguration()) {
setServerName(getString(ConfigurationKeys.SERVER_NAME));
setService(getString(ConfigurationKeys.SERVICE));
setEncodeServiceUrl(getBoolean(ConfigurationKeys.ENCODE_SERVICE_URL));
initInternal(filterConfig);
}
setServerName(getPropertyFromInitParams(filterConfig, "serverName", null));
setService(getPropertyFromInitParams(filterConfig, "service", null));
setArtifactParameterName(getPropertyFromInitParams(filterConfig, "artifactParameterName", "ticket"));
setServiceParameterName(getPropertyFromInitParams(filterConfig, "serviceParameterName", "service"));
setEncodeServiceUrl(Boolean.parseBoolean(getPropertyFromInitParams(filterConfig, "encodeServiceUrl", "true")));
initInternal(filterConfig);
init();
}
/** Controls the ordering of filter initialization and checking by defining a method that runs before the init.
* @param filterConfig the original filter configuration.
* @throws ServletException if there is a problem.
*
*/
/** Controls the ordering of filter initialization and checking by defining a method that runs before the init. */
protected void initInternal(final FilterConfig filterConfig) throws ServletException {
// template method
}
/**
* Initialization method. Called by Filter's init method or by Spring. Similar in concept to the InitializingBean interface's
* afterPropertiesSet();
* Initialization method. Called by Filter's init method or by Spring.
*/
public void init() {
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),
"serverName and service cannot both be set. You MUST ONLY set one.");
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.");
}
// empty implementation as most filters won't need this.
@Override
public void destroy() {
public final void destroy() {
// nothing to do
}
protected final String constructServiceUrl(final HttpServletRequest request, final HttpServletResponse response) {
return CommonUtils.constructServiceUrl(request, response, this.service, this.serverName,
this.protocol.getServiceParameterName(),
this.protocol.getArtifactParameterName(), this.encodeServiceUrl);
return CommonUtils.constructServiceUrl(request, response, this.service, this.serverName, this.artifactParameterName, this.encodeServiceUrl);
}
/**
* Note that trailing slashes should not be used in the serverName. As a convenience for this common misconfiguration, we strip them from the provided
* value.
*
* @param serverName the serverName. If this method is called, this should not be null. This AND service should not be both configured.
*/
public final void setServerName(final String serverName) {
if (serverName != null && serverName.endsWith("/")) {
this.serverName = serverName.substring(0, serverName.length() - 1);
logger.info("Eliminated extra slash from serverName [{}]. It is now [{}]", serverName, this.serverName);
} else {
this.serverName = serverName;
}
this.serverName = serverName;
}
public final void setService(final String service) {
this.service = service;
}
public final void setArtifactParameterName(final String artifactParameterName) {
this.artifactParameterName = artifactParameterName;
}
public final void setServiceParameterName(final String serviceParameterName) {
this.serviceParameterName = serviceParameterName;
}
public final void setEncodeServiceUrl(final boolean encodeServiceUrl) {
this.encodeServiceUrl = encodeServiceUrl;
this.encodeServiceUrl = encodeServiceUrl;
}
protected Protocol getProtocol() {
return this.protocol;
public final String getArtifactParameterName() {
return this.artifactParameterName;
}
/**
* Template method to allow you to change how you retrieve the ticket.
*
* @param request the HTTP ServletRequest. CANNOT be NULL.
* @return the ticket if its found, null otherwise.
*/
protected String retrieveTicketFromRequest(final HttpServletRequest request) {
return CommonUtils.safeGetParameter(request, this.protocol.getArtifactParameterName(),
Arrays.asList(this.protocol.getArtifactParameterName()));
public final String getServiceParameterName() {
return this.serviceParameterName;
}
}

View File

@ -1,32 +1,7 @@
/**
* Licensed to Apereo under one or more contributor license
* agreements. See the NOTICE file distributed with this work
* for additional information regarding copyright ownership.
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at the following location:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jasig.cas.client.util;
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;
/**
* Abstracts out the ability to configure the filters from the initial properties provided.
@ -37,46 +12,30 @@ import org.slf4j.LoggerFactory;
*/
public abstract class AbstractConfigurationFilter implements Filter {
private static final String CONFIGURATION_STRATEGY_KEY = "configurationStrategy";
/**
* Retrieves the property from the FilterConfig. First it checks the FilterConfig's initParameters to see if it
* has a value.
* If it does, it returns that, otherwise it trieves the ServletContext's initParameters and returns that value if any.
*
* @param filterConfig the Filter Configuration.
* @param propertyName the property to retrieve.
* @return the property value, following the above conventions. It will always return the more specific value (i.e.
* filter vs. context).
*/
protected final String getPropertyFromInitParams(final FilterConfig filterConfig, final String propertyName, final String defaultValue) {
final String value = filterConfig.getInitParameter(propertyName);
protected final Logger logger = LoggerFactory.getLogger(getClass());
if (CommonUtils.isNotBlank(value)) {
return value;
}
private boolean ignoreInitConfiguration = false;
final String value2 = filterConfig.getServletContext().getInitParameter(propertyName);
private ConfigurationStrategy configurationStrategy;
if (CommonUtils.isNotBlank(value2)) {
return value2;
}
@Override
public void init(final 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());
return defaultValue;
}
protected final boolean getBoolean(final ConfigurationKey<Boolean> configurationKey) {
return this.configurationStrategy.getBoolean(configurationKey);
}
protected final String getString(final ConfigurationKey<String> configurationKey) {
return this.configurationStrategy.getString(configurationKey);
}
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;
}
protected final boolean isIgnoreInitConfiguration() {
return this.ignoreInitConfiguration;
}
}

View File

@ -1,29 +1,17 @@
/**
* Licensed to Apereo under one or more contributor license
* agreements. See the NOTICE file distributed with this work
* for additional information regarding copyright ownership.
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at the following location:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
/*
* Copyright 2007 The JA-SIG Collaborative. All rights reserved. See license
* distributed with this file and available online at
* http://www.ja-sig.org/products/cas/overview/license/index.html
*/
package org.jasig.cas.client.util;
import org.jasig.cas.client.validation.Assertion;
/**
* Static holder that places Assertion in a ThreadLocal.
* Static holder that places Assertion in a threadlocal.
*
* @author Scott Battaglia
* @version $Revision: 11728 $ $Date: 2007-09-26 14:20:43 -0400 (Tue, 26 Sep 2007) $
* @since 3.0
*/
public class AssertionHolder {
@ -31,21 +19,18 @@ public class AssertionHolder {
/**
* ThreadLocal to hold the Assertion for Threads to access.
*/
private static final ThreadLocal<Assertion> threadLocal = new ThreadLocal<Assertion>();
private static final ThreadLocal threadLocal = new ThreadLocal();
/**
* Retrieve the assertion from the ThreadLocal.
*
* @return the Asssertion associated with this thread.
*/
public static Assertion getAssertion() {
return threadLocal.get();
return (Assertion) threadLocal.get();
}
/**
* Add the Assertion to the ThreadLocal.
*
* @param assertion the assertion to add.
*/
public static void setAssertion(final Assertion assertion) {
threadLocal.set(assertion);

View File

@ -1,50 +1,39 @@
/**
* Licensed to Apereo under one or more contributor license
* agreements. See the NOTICE file distributed with this work
* for additional information regarding copyright ownership.
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at the following location:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
/*
* Copyright 2007 The JA-SIG Collaborative. All rights reserved. See license
* distributed with this file and available online at
* http://www.ja-sig.org/products/cas/overview/license/index.html
*/
package org.jasig.cas.client.util;
import java.io.IOException;
import javax.servlet.*;
import org.jasig.cas.client.validation.Assertion;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import org.jasig.cas.client.validation.Assertion;
import java.io.IOException;
/**
* Places the assertion in a ThreadLocal such that other resources can access it that do not have access to the web tier session.
*
* @author Scott Battaglia
* @version $Revision: 11728 $ $Date: 2007-09-26 14:20:43 -0400 (Tue, 26 Sep 2007) $
* @since 3.0
*/
public final class AssertionThreadLocalFilter implements Filter {
@Override
public void init(final FilterConfig filterConfig) throws ServletException {
// nothing to do here
}
@Override
public void doFilter(final ServletRequest servletRequest, final ServletResponse servletResponse,
final FilterChain filterChain) throws IOException, ServletException {
public void doFilter(final ServletRequest servletRequest, final ServletResponse servletResponse, final FilterChain filterChain) throws IOException, ServletException {
final HttpServletRequest request = (HttpServletRequest) servletRequest;
final HttpSession session = request.getSession(false);
final Assertion assertion = (Assertion) (session == null ? request
.getAttribute(AbstractCasFilter.CONST_CAS_ASSERTION) : session
.getAttribute(AbstractCasFilter.CONST_CAS_ASSERTION));
final Assertion assertion = (Assertion) (session != null ? session.getAttribute(AbstractCasFilter.CONST_CAS_ASSERTION) : null);
try {
AssertionHolder.setAssertion(assertion);
@ -54,7 +43,6 @@ public final class AssertionThreadLocalFilter implements Filter {
}
}
@Override
public void destroy() {
// nothing to do
}

View File

@ -1,82 +1,30 @@
/**
* Licensed to Apereo under one or more contributor license
* agreements. See the NOTICE file distributed with this work
* for additional information regarding copyright ownership.
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at the following location:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
/*
* Copyright 2007 The JA-SIG Collaborative. All rights reserved. See license
* distributed with this file and available online at
* http://www.ja-sig.org/products/cas/overview/license/index.html
*/
package org.jasig.cas.client.util;
import org.jasig.cas.client.Protocol;
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;
import org.slf4j.LoggerFactory;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import javax.net.ssl.SSLException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.Closeable;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
* Common utilities so that we don't need to include Commons Lang.
*
* @author Scott Battaglia
* @version $Revision: 11729 $ $Date: 2007-09-26 14:22:30 -0400 (Tue, 26 Sep 2007) $
* @since 3.0
*/
public final class CommonUtils {
private static final Logger LOGGER = LoggerFactory.getLogger(CommonUtils.class);
/**
* Constant representing the ProxyGrantingTicket IOU Request Parameter.
*/
private static final String PARAM_PROXY_GRANTING_TICKET_IOU = "pgtIou";
/**
* Constant representing the ProxyGrantingTicket Request Parameter.
*/
private static final String PARAM_PROXY_GRANTING_TICKET = "pgtId";
private static final HttpURLConnectionFactory DEFAULT_URL_CONNECTION_FACTORY = new HttpsURLConnectionFactory();
private static final String SERVICE_PARAMETER_NAMES;
static {
final Set<String> serviceParameterSet = new HashSet<String>(4);
for (final Protocol protocol : Protocol.values()) {
serviceParameterSet.add(protocol.getServiceParameterName());
}
SERVICE_PARAMETER_NAMES = serviceParameterSet.toString()
.replaceAll("\\[|\\]", "")
.replaceAll("\\s", "");
}
/** Instance of Commons Logging. */
private static final Log LOG = LogFactory.getLog(CommonUtils.class);
private CommonUtils() {
// nothing to do
@ -99,10 +47,10 @@ public final class CommonUtils {
* Check whether the collection is null or empty. If it is, throw an
* exception and display the message.
*
* @param c the collection to check.
* @param c the collecion to check.
* @param message the message to display if the object is null.
*/
public static void assertNotEmpty(final Collection<?> c, final String message) {
public static void assertNotEmpty(final Collection c, final String message) {
assertNotNull(c, message);
if (c.isEmpty()) {
throw new IllegalArgumentException(message);
@ -113,7 +61,7 @@ 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 true.
* @param cond the codition to assert is true.
* @param message the message to display if the condition is not true.
*/
public static void assertTrue(final boolean cond, final String message) {
@ -122,20 +70,6 @@ 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.
*
@ -143,7 +77,7 @@ public final class CommonUtils {
* @return true if its null or length of 0, false otherwise.
*/
public static boolean isEmpty(final String string) {
return string == null || string.isEmpty();
return string == null || string.length() == 0;
}
/**
@ -165,7 +99,7 @@ public final class CommonUtils {
* @return true if its blank, false otherwise.
*/
public static boolean isBlank(final String string) {
return isEmpty(string) || string.trim().isEmpty();
return isEmpty(string) || string.trim().length() == 0;
}
/**
@ -187,561 +121,80 @@ public final class CommonUtils {
* @param serviceUrl the actual service's url.
* @param renew whether we should send renew or not.
* @param gateway where we should send gateway or not.
* @param method the method used by the CAS server to send the user back to the application.
* @return the fully constructed redirect url.
*/
public static String constructRedirectUrl(final String casServerLoginUrl, final String serviceParameterName,
final String serviceUrl, final boolean renew, final boolean gateway, final String method) {
return casServerLoginUrl + (casServerLoginUrl.contains("?") ? "&" : "?") + serviceParameterName + "="
+ urlEncode(serviceUrl) + (renew ? "&renew=true" : "") + (gateway ? "&gateway=true" : "")
+ (method != null ? "&method=" + method : "");
}
/**
* Construct redirect url to a CAS server.
*
* @param casServerLoginUrl the cas server login url
* @param serviceParameterName the service parameter name
* @param serviceUrl the service url
* @param renew the renew
* @param gateway the gateway
* @return the string
*/
public static String constructRedirectUrl(final String casServerLoginUrl, final String serviceParameterName,
final String serviceUrl, final boolean renew, final boolean gateway) {
return constructRedirectUrl(casServerLoginUrl, serviceParameterName, serviceUrl, renew, gateway, null);
}
/**
* Url encode a value using UTF-8 encoding.
*
* @param value the value to encode.
* @return the encoded value.
*/
public static String urlEncode(final String value) {
public static final String constructRedirectUrl(final String casServerLoginUrl, final String serviceParameterName, final String serviceUrl, final boolean renew, final boolean gateway) {
try {
return URLEncoder.encode(value, "UTF-8");
return casServerLoginUrl + "?" + serviceParameterName + "="
+ URLEncoder.encode(serviceUrl, "UTF-8")
+ (renew ? "&renew=true" : "")
+ (gateway ? "&gateway=true" : "");
} catch (final UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
}
public static void readAndRespondToProxyReceptorRequest(final HttpServletRequest request,
final HttpServletResponse response, final ProxyGrantingTicketStorage proxyGrantingTicketStorage)
throws IOException {
final String proxyGrantingTicketIou = request.getParameter(PARAM_PROXY_GRANTING_TICKET_IOU);
final String proxyGrantingTicket = request.getParameter(PARAM_PROXY_GRANTING_TICKET);
if (CommonUtils.isBlank(proxyGrantingTicket) || CommonUtils.isBlank(proxyGrantingTicketIou)) {
response.getWriter().write("");
return;
}
LOGGER.debug("Received proxyGrantingTicketId [{}] for proxyGrantingTicketIou [{}]", proxyGrantingTicket,
proxyGrantingTicketIou);
proxyGrantingTicketStorage.save(proxyGrantingTicketIou, proxyGrantingTicket);
LOGGER.debug("Successfully saved proxyGrantingTicketId [{}] for proxyGrantingTicketIou [{}]",
proxyGrantingTicket, proxyGrantingTicketIou);
response.getWriter().write("<?xml version=\"1.0\"?>");
response.getWriter().write("<casClient:proxySuccess xmlns:casClient=\"http://www.yale.edu/tp/casClient\" />");
}
protected static String findMatchingServerName(final HttpServletRequest request, final String serverName) {
final String[] serverNames = serverName.split(" ");
if (serverNames.length == 0 || serverNames.length == 1) {
return serverName;
}
final String host = request.getHeader("Host");
final String xHost = request.getHeader("X-Forwarded-Host");
final String comparisonHost;
comparisonHost = (xHost != null) ? xHost : host;
if (comparisonHost == null) {
return serverName;
}
for (final String server : serverNames) {
final String lowerCaseServer = server.toLowerCase();
if (lowerCaseServer.contains(comparisonHost)) {
return server;
}
}
return serverNames[0];
}
private static boolean requestIsOnStandardPort(final HttpServletRequest request) {
final int serverPort = request.getServerPort();
return serverPort == 80 || serverPort == 443;
}
/**
* Constructs a service url from the HttpServletRequest or from the given
* serviceUrl. Prefers the serviceUrl provided if both a serviceUrl and a
* serviceName. Compiles a list of all service parameters for supported protocols
* and removes them all from the query string.
*
* @param request the HttpServletRequest
* @param response the HttpServletResponse
* @param service the configured service url (this will be used if not null)
* @param serverNames the server name to use to construct the service url if the service param is empty. Note, prior to CAS Client 3.3, this was a single value.
* As of 3.3, it can be a space-separated value. We keep it as a single value, but will convert it to an array internally to get the matching value. This keeps backward compatability with anything using this public
* method.
* @param artifactParameterName the artifact parameter name to remove (i.e. ticket)
* @param encode whether to encode the url or not (i.e. Jsession).
* @return the service url to use.
*/
@Deprecated
public static String constructServiceUrl(final HttpServletRequest request, final HttpServletResponse response,
final String service, final String serverNames,
final String artifactParameterName, final boolean encode) {
return constructServiceUrl(request, response, service, serverNames, SERVICE_PARAMETER_NAMES
, artifactParameterName, encode);
}
/**
/**
* Constructs a service url from the HttpServletRequest or from the given
* serviceUrl. Prefers the serviceUrl provided if both a serviceUrl and a
* serviceName.
*
* @param request the HttpServletRequest
* @param request the HttpServletRequest
* @param response the HttpServletResponse
* @param service the configured service url (this will be used if not null)
* @param serverNames the server name to use to construct the service url if the service param is empty. Note, prior to CAS Client 3.3, this was a single value.
* As of 3.3, it can be a space-separated value. We keep it as a single value, but will convert it to an array internally to get the matching value. This keeps backward compatability with anything using this public
* method.
* @param serviceParameterName the service parameter name to remove (i.e. service)
* @param artifactParameterName the artifact parameter name to remove (i.e. ticket)
* @param encode whether to encode the url or not (i.e. Jsession).
* @return the service url to use.
*/
public static String constructServiceUrl(final HttpServletRequest request, final HttpServletResponse response,
final String service, final String serverNames, final String serviceParameterName,
final String artifactParameterName, final boolean encode) {
public static final String constructServiceUrl(final HttpServletRequest request,
final HttpServletResponse response, final String service, final String serverName, final String artifactParameterName, final boolean encode) {
if (CommonUtils.isNotBlank(service)) {
return encode ? response.encodeURL(service) : service;
}
final String serverName = findMatchingServerName(request, serverNames);
final URIBuilder originalRequestUrl = new URIBuilder(request.getRequestURL().toString(), encode);
originalRequestUrl.setParameters(request.getQueryString());
final StringBuffer buffer = new StringBuffer();
final URIBuilder builder;
if (!serverName.startsWith("https://") && !serverName.startsWith("http://")) {
final String scheme = request.isSecure() ? "https://" : "http://";
builder = new URIBuilder(scheme + serverName, encode);
} else {
builder = new URIBuilder(serverName, encode);
}
synchronized (buffer) {
if (!serverName.startsWith("https://") && !serverName.startsWith("http://")) {
buffer.append(request.isSecure() ? "https://" : "http://");
}
if (builder.getPort() == -1 && !requestIsOnStandardPort(request)) {
builder.setPort(request.getServerPort());
}
buffer.append(serverName);
buffer.append(request.getRequestURI());
builder.setEncodedPath(builder.getEncodedPath() + request.getRequestURI());
if (CommonUtils.isNotBlank(request.getQueryString())) {
final int location = request.getQueryString().indexOf(
artifactParameterName + "=");
final List<String> serviceParameterNames = Arrays.asList(serviceParameterName.split(","));
if (!serviceParameterNames.isEmpty() && !originalRequestUrl.getQueryParams().isEmpty()) {
for (final URIBuilder.BasicNameValuePair pair : originalRequestUrl.getQueryParams()) {
final String name = pair.getName();
if (!name.equals(artifactParameterName) && !serviceParameterNames.contains(name)) {
if (name.contains("&") || name.contains("=")) {
final URIBuilder encodedParamBuilder = new URIBuilder();
encodedParamBuilder.setParameters(name);
for (final URIBuilder.BasicNameValuePair pair2 : encodedParamBuilder.getQueryParams()) {
final String name2 = pair2.getName();
if (!name2.equals(artifactParameterName) && !serviceParameterNames.contains(name2)) {
builder.addParameter(name2, pair2.getValue());
}
}
} else {
builder.addParameter(name, pair.getValue());
if (location == 0) {
final String returnValue = encode ? response.encodeURL(buffer
.toString()): buffer.toString();
if (LOG.isDebugEnabled()) {
LOG.debug("serviceUrl generated: " + returnValue);
}
return returnValue;
}
buffer.append("?");
if (location == -1) {
buffer.append(request.getQueryString());
} else if (location > 0) {
final int actualLocation = request.getQueryString()
.indexOf("&" + artifactParameterName + "=");
if (actualLocation == -1) {
buffer.append(request.getQueryString());
} else if (actualLocation > 0) {
buffer.append(request.getQueryString().substring(0,
actualLocation));
}
}
}
}
final String result = builder.toString();
final String returnValue = encode ? response.encodeURL(result) : result;
LOGGER.debug("serviceUrl generated: {}", returnValue);
final String returnValue = encode ? response.encodeURL(buffer.toString()) : buffer.toString();
if (LOG.isDebugEnabled()) {
LOG.debug("serviceUrl generated: " + returnValue);
}
return returnValue;
}
/**
* Safe method for retrieving a parameter from the request without disrupting the reader UNLESS the parameter
* actually exists in the query string.
* <p>
* Note, this does not work for POST Requests for "logoutRequest". It works for all other CAS POST requests because the
* parameter is ALWAYS in the GET request.
* <p>
* If we see the "logoutRequest" parameter we MUST treat it as if calling the standard request.getParameter.
* <p>
* Note, that as of 3.3.0, we've made it more generic.
* </p>
*
* @param request the request to check.
* @param parameter the parameter to look for.
* @return the value of the parameter.
*/
public static String safeGetParameter(final HttpServletRequest request, final String parameter,
final List<String> parameters) {
if ("POST".equals(request.getMethod()) && parameters.contains(parameter)) {
LOGGER.debug("safeGetParameter called on a POST HttpServletRequest for Restricted Parameters. Cannot complete check safely. Reverting to standard behavior for this Parameter");
return request.getParameter(parameter);
}
return request.getQueryString() == null || !request.getQueryString().contains(parameter) ? null : request
.getParameter(parameter);
}
public static String safeGetParameter(final HttpServletRequest request, final String parameter) {
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 IOException e) {
throw new RuntimeException(e.getMessage(), 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.
*
* @param constructedUrl the url to contact.
* @param factory connection factory to prepare the URL connection instance
* @param encoding the encoding to use.
* @return the response.
*/
public static String getResponseFromServer(final URL constructedUrl, final HttpURLConnectionFactory factory,
final String encoding) {
HttpURLConnection conn = null;
InputStreamReader in = null;
try {
conn = factory.buildHttpURLConnection(constructedUrl.openConnection());
if (CommonUtils.isEmpty(encoding)) {
in = new InputStreamReader(conn.getInputStream());
} else {
in = new InputStreamReader(conn.getInputStream(), encoding);
}
final StringBuilder builder = new StringBuilder(255);
int byteRead;
while ((byteRead = in.read()) != -1) {
builder.append((char) byteRead);
}
return builder.toString();
} catch (final RuntimeException e) {
throw e;
} catch (final SSLException e) {
LOGGER.error("SSL error getting response from host: {} : Error Message: {}", constructedUrl.getHost(), e.getMessage(), e);
throw new RuntimeException(e);
} catch (final IOException e) {
LOGGER.error("Error getting response from host: [{}] with path: [{}] and protocol: [{}] Error Message: {}",
constructedUrl.getHost(), constructedUrl.getPath(), constructedUrl.getProtocol(), e.getMessage(), e);
throw new RuntimeException(e);
} finally {
closeQuietly(in);
if (conn != null) {
conn.disconnect();
}
}
}
public static ProxyList createProxyList(final String proxies) {
if (CommonUtils.isBlank(proxies)) {
return new ProxyList();
}
final ProxyListEditor editor = new ProxyListEditor();
editor.setAsText(proxies);
return (ProxyList) editor.getValue();
}
/**
* Sends the redirect message and captures the exceptions that we can't possibly do anything with.
*
* @param response the HttpServletResponse. CANNOT be NULL.
* @param url the url to redirect to.
*/
public static void sendRedirect(final HttpServletResponse response, final String url) {
try {
response.sendRedirect(url);
} catch (final IOException e) {
LOGGER.warn(e.getMessage(), e);
}
}
/**
* Unconditionally close a {@link Closeable}. Equivalent to {@link java.io.Closeable#close()}close(), except any exceptions
* will be ignored. This is typically used in finally blocks.
* @param resource the resource to close
*/
public static void closeQuietly(final Closeable resource) {
try {
if (resource != null) {
resource.close();
}
} catch (final IOException e) {
//ignore
}
}
/**
* <p>Converts a String to a boolean (optimised for performance).</p>
*
* <p>{@code 'true'}, {@code 'on'}, {@code 'y'}, {@code 't'} or {@code 'yes'}
* (case insensitive) will return {@code true}. Otherwise,
* {@code false} is returned.</p>
*
* <p>This method performs 4 times faster (JDK1.4) than
* {@code Boolean.valueOf(String)}. However, this method accepts
* 'on' and 'yes', 't', 'y' as true values.
*
* <pre>
* BooleanUtils.toBoolean(null) = false
* BooleanUtils.toBoolean("true") = true
* BooleanUtils.toBoolean("TRUE") = true
* BooleanUtils.toBoolean("tRUe") = true
* BooleanUtils.toBoolean("on") = true
* BooleanUtils.toBoolean("yes") = true
* BooleanUtils.toBoolean("false") = false
* BooleanUtils.toBoolean("x gti") = false
* BooleanUtils.toBooleanObject("y") = true
* BooleanUtils.toBooleanObject("n") = false
* BooleanUtils.toBooleanObject("t") = true
* BooleanUtils.toBooleanObject("f") = false
* </pre>
*
* @param str the String to check
* @return the boolean value of the string, {@code false} if no match or the String is null
*/
public static boolean toBoolean(final String str) {
return toBooleanObject(str) == Boolean.TRUE;
}
/**
* <p>Converts a String to a Boolean.</p>
*
* <p>{@code 'true'}, {@code 'on'}, {@code 'y'}, {@code 't'} or {@code 'yes'}
* (case insensitive) will return {@code true}.
* {@code 'false'}, {@code 'off'}, {@code 'n'}, {@code 'f'} or {@code 'no'}
* (case insensitive) will return {@code false}.
* Otherwise, {@code null} is returned.</p>
*
* <p>NOTE: This returns null and will throw a NullPointerException if autoboxed to a boolean. </p>
*
* <pre>
* // N.B. case is not significant
* BooleanUtils.toBooleanObject(null) = null
* BooleanUtils.toBooleanObject("true") = Boolean.TRUE
* BooleanUtils.toBooleanObject("T") = Boolean.TRUE // i.e. T[RUE]
* BooleanUtils.toBooleanObject("false") = Boolean.FALSE
* BooleanUtils.toBooleanObject("f") = Boolean.FALSE // i.e. f[alse]
* BooleanUtils.toBooleanObject("No") = Boolean.FALSE
* BooleanUtils.toBooleanObject("n") = Boolean.FALSE // i.e. n[o]
* BooleanUtils.toBooleanObject("on") = Boolean.TRUE
* BooleanUtils.toBooleanObject("ON") = Boolean.TRUE
* BooleanUtils.toBooleanObject("off") = Boolean.FALSE
* BooleanUtils.toBooleanObject("oFf") = Boolean.FALSE
* BooleanUtils.toBooleanObject("yes") = Boolean.TRUE
* BooleanUtils.toBooleanObject("Y") = Boolean.TRUE // i.e. Y[ES]
* BooleanUtils.toBooleanObject("blue") = null
* BooleanUtils.toBooleanObject("true ") = null // trailing space (too long)
* BooleanUtils.toBooleanObject("ono") = null // does not match on or no
* </pre>
*
* @param str the String to check; upper and lower case are treated as the same
* @return the Boolean value of the string, {@code null} if no match or {@code null} input
*/
public static Boolean toBooleanObject(final String str) {
// Previously used equalsIgnoreCase, which was fast for interned 'true'.
// Non interned 'true' matched 15 times slower.
//
// Optimisation provides same performance as before for interned 'true'.
// Similar performance for null, 'false', and other strings not length 2/3/4.
// 'true'/'TRUE' match 4 times slower, 'tRUE'/'True' 7 times slower.
if (str == "true") {
return Boolean.TRUE;
}
if (str == null) {
return null;
}
switch (str.length()) {
case 1: {
final char ch0 = str.charAt(0);
if (ch0 == 'y' || ch0 == 'Y' ||
ch0 == 't' || ch0 == 'T') {
return Boolean.TRUE;
}
if (ch0 == 'n' || ch0 == 'N' ||
ch0 == 'f' || ch0 == 'F') {
return Boolean.FALSE;
}
break;
}
case 2: {
final char ch0 = str.charAt(0);
final char ch1 = str.charAt(1);
if ((ch0 == 'o' || ch0 == 'O') &&
(ch1 == 'n' || ch1 == 'N')) {
return Boolean.TRUE;
}
if ((ch0 == 'n' || ch0 == 'N') &&
(ch1 == 'o' || ch1 == 'O')) {
return Boolean.FALSE;
}
break;
}
case 3: {
final char ch0 = str.charAt(0);
final char ch1 = str.charAt(1);
final char ch2 = str.charAt(2);
if ((ch0 == 'y' || ch0 == 'Y') &&
(ch1 == 'e' || ch1 == 'E') &&
(ch2 == 's' || ch2 == 'S')) {
return Boolean.TRUE;
}
if ((ch0 == 'o' || ch0 == 'O') &&
(ch1 == 'f' || ch1 == 'F') &&
(ch2 == 'f' || ch2 == 'F')) {
return Boolean.FALSE;
}
break;
}
case 4: {
final char ch0 = str.charAt(0);
final char ch1 = str.charAt(1);
final char ch2 = str.charAt(2);
final char ch3 = str.charAt(3);
if ((ch0 == 't' || ch0 == 'T') &&
(ch1 == 'r' || ch1 == 'R') &&
(ch2 == 'u' || ch2 == 'U') &&
(ch3 == 'e' || ch3 == 'E')) {
return Boolean.TRUE;
}
break;
}
case 5: {
final char ch0 = str.charAt(0);
final char ch1 = str.charAt(1);
final char ch2 = str.charAt(2);
final char ch3 = str.charAt(3);
final char ch4 = str.charAt(4);
if ((ch0 == 'f' || ch0 == 'F') &&
(ch1 == 'a' || ch1 == 'A') &&
(ch2 == 'l' || ch2 == 'L') &&
(ch3 == 's' || ch3 == 'S') &&
(ch4 == 'e' || ch4 == 'E')) {
return Boolean.FALSE;
}
break;
}
default:
break;
}
return null;
}
/**
* <p>Convert a <code>String</code> to a <code>long</code>, returning a
* default value if the conversion fails.</p>
*
* <p>If the string is <code>null</code>, the default value is returned.</p>
*
* <pre>
* NumberUtils.toLong(null, 1L) = 1L
* NumberUtils.toLong("", 1L) = 1L
* NumberUtils.toLong("1", 0L) = 1L
* </pre>
*
* @param str the string to convert, may be null
* @param defaultValue the default value
* @return the long represented by the string, or the default if conversion fails
*/
public static long toLong(final String str, final long defaultValue) {
if (str == null) {
return defaultValue;
}
try {
return Long.parseLong(str);
} catch (final NumberFormatException nfe) {
return defaultValue;
}
}
/**
* <p>Convert a <code>String</code> to an <code>int</code>, returning a
* default value if the conversion fails.</p>
*
* <p>If the string is <code>null</code>, the default value is returned.</p>
*
* <pre>
* NumberUtils.toInt(null, 1) = 1
* NumberUtils.toInt("", 1) = 1
* NumberUtils.toInt("1", 0) = 1
* </pre>
*
* @param str the string to convert, may be null
* @param defaultValue the default value
* @return the int represented by the string, or the default if conversion fails
*/
public static int toInt(final String str, final int defaultValue) {
if (str == null) {
return defaultValue;
}
try {
return Integer.parseInt(str);
} catch (final NumberFormatException nfe) {
return defaultValue;
}
}
/**
* Returns the string as-is, unless it's <code>null</code>;
* in this case an empty string is returned.
*
* @param string a possibly <code>null</code> string
* @return a non-<code>null</code> string
*/
public static String nullToEmpty(final String string) {
return string == null ? "" : string;
}
/**
* Adds a trailing slash to the given uri, if it doesn't already have one.
*
* @param uri a string that may or may not end with a slash
* @return the same string, except with a slash suffix (if necessary).
*/
public static String addTrailingSlash(final String uri) {
return uri.endsWith("/") ? uri : uri + "/";
}
}

View File

@ -1,29 +1,22 @@
/**
* Licensed to Apereo under one or more contributor license
* agreements. See the NOTICE file distributed with this work
* for additional information regarding copyright ownership.
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at the following location:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
/*
* Copyright 2006 The JA-SIG Collaborative. All rights reserved. See license
* distributed with this file and available online at
* http://www.ja-sig.org/products/cas/overview/license/index.html
*/
package org.jasig.cas.client.util;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import java.io.IOException;
import java.util.Iterator;
import java.util.Map;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* A Delegating Filter looks up a parameter in the request object and matches
@ -31,6 +24,7 @@ import org.slf4j.LoggerFactory;
* the associated filter is executed. Otherwise, the normal chain is executed.
*
* @author Scott Battaglia
* @version $Revision: 11729 $ $Date: 2006-09-26 14:22:30 -0400 (Tue, 26 Sep 2006) $
* @since 3.0
*/
public final class DelegatingFilter implements Filter {
@ -38,7 +32,7 @@ public final class DelegatingFilter implements Filter {
/**
* Instance of Commons Logging.
*/
private final Logger logger = LoggerFactory.getLogger(this.getClass());
private final Log log = LogFactory.getLog(this.getClass());
/**
* The request parameter to look for in the Request object.
@ -48,7 +42,7 @@ public final class DelegatingFilter implements Filter {
/**
* The map of filters to delegate to and the criteria (as key).
*/
private final Map<String, Filter> delegators;
private final Map delegators;
/**
* The default filter to use if there is no match.
@ -61,15 +55,25 @@ public final class DelegatingFilter implements Filter {
*/
private final boolean exactMatch;
public DelegatingFilter(final String requestParameterName, final Map<String, Filter> delegators,
final boolean exactMatch) {
public DelegatingFilter(final String requestParameterName, final Map delegators, final boolean exactMatch) {
this(requestParameterName, delegators, exactMatch, null);
}
public DelegatingFilter(final String requestParameterName, final Map<String, Filter> delegators,
final boolean exactMatch, final Filter defaultFilter) {
CommonUtils.assertNotNull(requestParameterName, "requestParameterName cannot be null.");
CommonUtils.assertTrue(!delegators.isEmpty(), "delegators cannot be empty.");
public DelegatingFilter(final String requestParameterName, final Map delegators, final boolean exactMatch, final Filter defaultFilter) {
CommonUtils.assertNotNull(requestParameterName,
"requestParameterName cannot be null.");
CommonUtils.assertTrue(!delegators.isEmpty(),
"delegators cannot be empty.");
for (final Iterator iter = delegators.keySet().iterator(); iter
.hasNext();) {
final Object object = delegators.get(iter.next());
if (!Filter.class.isAssignableFrom(object.getClass())) {
throw new IllegalArgumentException(
"All value objects in the delegators map must be filters.");
}
}
this.requestParameterName = requestParameterName;
this.delegators = delegators;
@ -77,30 +81,39 @@ public final class DelegatingFilter implements Filter {
this.exactMatch = exactMatch;
}
@Override
public void destroy() {
// nothing to do here
}
@Override
public void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain filterChain)
public void doFilter(final ServletRequest request,
final ServletResponse response, final FilterChain filterChain)
throws IOException, ServletException {
final String parameter = CommonUtils.safeGetParameter((HttpServletRequest) request, this.requestParameterName);
final String parameter = request
.getParameter(this.requestParameterName);
if (CommonUtils.isNotEmpty(parameter)) {
for (final String key : this.delegators.keySet()) {
if ((parameter.equals(key) && this.exactMatch) || (parameter.matches(key) && !this.exactMatch)) {
final Filter filter = this.delegators.get(key);
logger.debug("Match found for parameter [{}] with value [{}]. Delegating to filter [{}]",
this.requestParameterName, parameter, filter.getClass().getName());
for (final Iterator iter = this.delegators.keySet().iterator(); iter
.hasNext();) {
final String key = (String) iter.next();
if ((parameter.equals(key) && this.exactMatch)
|| (parameter.matches(key) && !this.exactMatch)) {
final Filter filter = (Filter) this.delegators.get(key);
if (log.isDebugEnabled()) {
log.debug("Match found for parameter ["
+ this.requestParameterName + "] with value ["
+ parameter + "]. Delegating to filter ["
+ filter.getClass().getName() + "]");
}
filter.doFilter(request, response, filterChain);
return;
}
}
}
logger.debug("No match found for parameter [{}] with value [{}]", this.requestParameterName, parameter);
log.debug("No match found for parameter [" + this.requestParameterName
+ "] with value [" + parameter + "]");
if (this.defaultFilter != null) {
this.defaultFilter.doFilter(request, response, filterChain);
@ -109,7 +122,6 @@ public final class DelegatingFilter implements Filter {
}
}
@Override
public void init(final FilterConfig filterConfig) throws ServletException {
// nothing to do here.
}

View File

@ -1,139 +0,0 @@
/**
* Licensed to Apereo under one or more contributor license
* agreements. See the NOTICE file distributed with this work
* for additional information regarding copyright ownership.
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at the following location:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jasig.cas.client.util;
import java.io.IOException;
import java.util.ArrayList;
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/>
* 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/>
* 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 {
private final Logger logger = LoggerFactory.getLogger(getClass());
private final List<ErrorHolder> errors = new ArrayList<ErrorHolder>();
private String defaultErrorRedirectPage;
@Override
public void destroy() {
// nothing to do here
}
@Override
public void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain filterChain)
throws IOException, ServletException {
final HttpServletResponse httpResponse = (HttpServletResponse) response;
try {
filterChain.doFilter(request, response);
} catch (final Exception e) {
final Throwable t = extractErrorToCompare(e);
ErrorHolder currentMatch = null;
for (final ErrorHolder errorHolder : this.errors) {
if (errorHolder.exactMatch(t)) {
currentMatch = errorHolder;
break;
} else if (errorHolder.inheritanceMatch(t)) {
currentMatch = errorHolder;
}
}
if (currentMatch != null) {
httpResponse.sendRedirect(currentMatch.getUrl());
} else {
httpResponse.sendRedirect(defaultErrorRedirectPage);
}
}
}
/**
* 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;
}
@Override
public void init(final FilterConfig filterConfig) throws ServletException {
this.defaultErrorRedirectPage = filterConfig.getInitParameter("defaultErrorRedirectPage");
final Enumeration<?> enumeration = filterConfig.getInitParameterNames();
while (enumeration.hasMoreElements()) {
final String className = (String) enumeration.nextElement();
try {
if (!className.equals("defaultErrorRedirectPage")) {
this.errors.add(new ErrorHolder(className, filterConfig.getInitParameter(className)));
}
} catch (final ClassNotFoundException e) {
logger.warn("Class [{}] cannot be found in ClassLoader. Ignoring.", className);
}
}
}
protected final class ErrorHolder {
private Class<?> className;
private String url;
protected ErrorHolder(final String className, final String url) throws ClassNotFoundException {
this.className = Class.forName(className);
this.url = url;
}
public boolean exactMatch(final Throwable e) {
return this.className.equals(e.getClass());
}
public boolean inheritanceMatch(final Throwable e) {
return className.isAssignableFrom(e.getClass());
}
public String getUrl() {
return this.url;
}
}
}

View File

@ -1,60 +1,38 @@
/**
* Licensed to Apereo under one or more contributor license
* agreements. See the NOTICE file distributed with this work
* for additional information regarding copyright ownership.
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at the following location:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
/*
* Copyright 2007 The JA-SIG Collaborative. All rights reserved. See license
* distributed with this file and available online at
* http://www.ja-sig.org/products/cas/overview/license/index.html
*/
package org.jasig.cas.client.util;
import java.io.IOException;
import java.security.Principal;
import java.util.Collection;
import javax.servlet.*;
import org.jasig.cas.client.validation.Assertion;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpSession;
import org.jasig.cas.client.authentication.AttributePrincipal;
import org.jasig.cas.client.configuration.ConfigurationKeys;
import org.jasig.cas.client.validation.Assertion;
import java.io.IOException;
import java.security.Principal;
/**
* Implementation of a filter that wraps the normal HttpServletRequest with a
* wrapper that overrides the following methods to provide data from the
* CAS Assertion:
* <ul>
* <li>{@link HttpServletRequest#getUserPrincipal()}</li>
* <li>{@link HttpServletRequest#getRemoteUser()}</li>
* <li>{@link HttpServletRequest#isUserInRole(String)}</li>
* </ul>
* wrapper that overrides the getRemoteUser method to retrieve the user from the
* CAS Assertion.
* <p/>
* This filter needs to be configured in the chain so that it executes after
* both the authentication and the validation filters.
*
* @author Scott Battaglia
* @author Marvin S. Addison
* @version $Revision: 11729 $ $Date: 2007-09-26 14:22:30 -0400 (Tue, 26 Sep 2007) $
* @since 3.0
*/
public final class HttpServletRequestWrapperFilter extends AbstractConfigurationFilter {
public final class HttpServletRequestWrapperFilter implements Filter {
/** Name of the attribute used to answer role membership queries */
private String roleAttribute;
/** Whether or not to ignore case in role membership queries */
private boolean ignoreCase;
@Override
public void destroy() {
// nothing to do
}
@ -64,95 +42,42 @@ public final class HttpServletRequestWrapperFilter extends AbstractConfiguration
* <code>request.getRemoteUser</code> to the underlying Assertion object
* stored in the user session.
*/
@Override
public void doFilter(final ServletRequest servletRequest, final ServletResponse servletResponse,
final FilterChain filterChain) throws IOException, ServletException {
final AttributePrincipal principal = retrievePrincipalFromSessionOrRequest(servletRequest);
public void doFilter(final ServletRequest servletRequest,
final ServletResponse servletResponse, final FilterChain filterChain)
throws IOException, ServletException {
final Principal principal = retrievePrincipalFromSessionOrRequest(servletRequest);
filterChain.doFilter(new CasHttpServletRequestWrapper((HttpServletRequest) servletRequest, principal),
servletResponse);
filterChain.doFilter(new CasHttpServletRequestWrapper(
(HttpServletRequest) servletRequest, principal), servletResponse);
}
protected AttributePrincipal retrievePrincipalFromSessionOrRequest(final ServletRequest servletRequest) {
protected Principal retrievePrincipalFromSessionOrRequest(final ServletRequest servletRequest) {
final HttpServletRequest request = (HttpServletRequest) servletRequest;
final HttpSession session = request.getSession(false);
final Assertion assertion = (Assertion) (session == null ? request
.getAttribute(AbstractCasFilter.CONST_CAS_ASSERTION) : session
.getAttribute(AbstractCasFilter.CONST_CAS_ASSERTION));
final Assertion assertion = (Assertion) (session == null ? request.getAttribute(AbstractCasFilter.CONST_CAS_ASSERTION) : session.getAttribute(AbstractCasFilter.CONST_CAS_ASSERTION));
return assertion == null ? null : assertion.getPrincipal();
}
@Override
public void init(final FilterConfig filterConfig) throws ServletException {
super.init(filterConfig);
this.roleAttribute = getString(ConfigurationKeys.ROLE_ATTRIBUTE);
this.ignoreCase = getBoolean(ConfigurationKeys.IGNORE_CASE);
// nothing to do
}
final class CasHttpServletRequestWrapper extends HttpServletRequestWrapper {
private final AttributePrincipal principal;
private final Principal principal;
CasHttpServletRequestWrapper(final HttpServletRequest request, final AttributePrincipal principal) {
CasHttpServletRequestWrapper(final HttpServletRequest request, final Principal principal) {
super(request);
this.principal = principal;
}
@Override
public Principal getUserPrincipal() {
return this.principal;
}
@Override
public String getRemoteUser() {
return principal != null ? this.principal.getName() : null;
}
@Override
public boolean isUserInRole(final String role) {
if (CommonUtils.isBlank(role)) {
logger.debug("No valid role provided. Returning false.");
return false;
}
if (this.principal == null) {
logger.debug("No Principal in Request. Returning false.");
return false;
}
if (CommonUtils.isBlank(roleAttribute)) {
logger.debug("No Role Attribute Configured. Returning false.");
return false;
}
final Object value = this.principal.getAttributes().get(roleAttribute);
if (value instanceof Collection<?>) {
for (final Object o : (Collection<?>) value) {
if (rolesEqual(role, o)) {
logger.debug("User [{}] is in role [{}]: true", getRemoteUser(), role);
return true;
}
}
}
final boolean isMember = rolesEqual(role, value);
logger.debug("User [{}] is in role [{}]: {}", getRemoteUser(), role, isMember);
return isMember;
}
/**
* Determines whether the given role is equal to the candidate
* role attribute taking into account case sensitivity.
*
* @param given Role under consideration.
* @param candidate Role that the current user possesses.
*
* @return True if roles are equal, false otherwise.
*/
private boolean rolesEqual(final String given, final Object candidate) {
return ignoreCase ? given.equalsIgnoreCase(candidate.toString()) : given.equals(candidate);
return getUserPrincipal().getName();
}
}
}

View File

@ -1,92 +0,0 @@
/**
* Licensed to Apereo under one or more contributor license
* agreements. See the NOTICE file distributed with this work
* for additional information regarding copyright ownership.
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at the following location:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
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
}
}
}

View File

@ -1,83 +0,0 @@
/**
* Licensed to Apereo under one or more contributor license
* agreements. See the NOTICE file distributed with this work
* for additional information regarding copyright ownership.
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at the following location:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
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;
}
@Override
public String getNamespaceURI(final String prefix) {
return namespaceMap.get(prefix);
}
@Override
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;
}
@Override
public Iterator getPrefixes(final String namespaceURI) {
return Collections.singleton(getPrefix(namespaceURI)).iterator();
}
}

View File

@ -1,108 +0,0 @@
/**
* Licensed to Apereo under one or more contributor license
* agreements. See the NOTICE file distributed with this work
* for additional information regarding copyright ownership.
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at the following location:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jasig.cas.client.util;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.openssl.PEMKeyPair;
import org.bouncycastle.openssl.PEMParser;
import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.*;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.PrivateKey;
import java.security.Security;
import java.security.spec.PKCS8EncodedKeySpec;
/**
* Utility class to parse private keys.
*
* @author Jerome LELEU
* @since 3.6.0
*/
public class PrivateKeyUtils {
private static final Logger LOGGER = LoggerFactory.getLogger(PrivateKeyUtils.class);
static {
Security.addProvider(new BouncyCastleProvider());
}
public static PrivateKey createKey(final String path, final String algorithm) {
final PrivateKey key = readPemPrivateKey(path);
if (key == null) {
return readDERPrivateKey(path, algorithm);
} else {
return key;
}
}
private static PrivateKey readPemPrivateKey(final String path) {
LOGGER.debug("Attempting to read as PEM [{}]", path);
final File file = new File(path);
InputStreamReader isr = null;
BufferedReader br = null;
try {
isr = new FileReader(file);
br = new BufferedReader(isr);
final PEMParser pp = new PEMParser(br);
final PEMKeyPair pemKeyPair = (PEMKeyPair) pp.readObject();
final KeyPair kp = new JcaPEMKeyConverter().getKeyPair(pemKeyPair);
return kp.getPrivate();
} catch (final Exception e) {
LOGGER.error("Unable to read key", e);
return null;
} finally {
try {
if (br != null) {
br.close();
}
if (isr != null) {
isr.close();
}
} catch (final IOException e) {}
}
}
private static PrivateKey readDERPrivateKey(final String path, final String algorithm) {
LOGGER.debug("Attempting to read key as DER [{}]", path);
final File file = new File(path);
FileInputStream fis = null;
try {
fis = new FileInputStream(file);
final long byteLength = file.length();
final byte[] bytes = new byte[(int) byteLength];
fis.read(bytes, 0, (int) byteLength);
final PKCS8EncodedKeySpec privSpec = new PKCS8EncodedKeySpec(bytes);
final KeyFactory factory = KeyFactory.getInstance(algorithm);
return factory.generatePrivate(privSpec);
} catch (final Exception e) {
LOGGER.error("Unable to read key", e);
return null;
} finally {
try {
if (fis != null) {
fis.close();
}
} catch (final IOException e) {}
}
}
}

View File

@ -1,183 +0,0 @@
/**
* Licensed to Apereo under one or more contributor license
* agreements. See the NOTICE file distributed with this work
* for additional information regarding copyright ownership.
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at the following location:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jasig.cas.client.util;
import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
/**
* Helper class with reflection utility methods.
*
* @author Marvin S. Addison
* @version $Revision$
* @since 3.1.11
*
*/
public final class ReflectUtils {
private ReflectUtils() {
// private constructor to prevent instanciation.
}
/**
* Attempts to create a class from a String.
* @param className the name of the class to create.
* @return the class. CANNOT be NULL.
* @throws IllegalArgumentException if the className does not exist.
*/
@SuppressWarnings("unchecked")
public static <T> Class<T> loadClass(final String className) throws IllegalArgumentException {
try {
return (Class<T>) Class.forName(className);
} catch (final ClassNotFoundException e) {
throw new IllegalArgumentException(className + " class not found.");
}
}
/**
* Creates a new instance of the given class by passing the given arguments
* to the constructor.
* @param className Name of class to be created.
* @param args Constructor arguments.
* @return New instance of given class.
*/
public static <T> T newInstance(final String className, final Object... args) {
return newInstance(ReflectUtils.<T> loadClass(className), args);
}
/**
* Creates a new instance of the given class by passing the given arguments
* to the constructor.
* @param clazz Class of instance to be created.
* @param args Constructor arguments.
* @return New instance of given class.
*/
public static <T> T newInstance(final Class<T> clazz, final Object... args) {
final Class<?>[] argClasses = new Class[args.length];
for (int i = 0; i < args.length; i++) {
argClasses[i] = args[i].getClass();
}
try {
return clazz.getConstructor(argClasses).newInstance(args);
} catch (final Exception e) {
throw new IllegalArgumentException("Error creating new instance of " + clazz, e);
}
}
/**
* Gets the property descriptor for the named property on the given class.
* @param clazz Class to which property belongs.
* @param propertyName Name of property.
* @return Property descriptor for given property or null if no property with given
* name exists in given class.
*/
public static PropertyDescriptor getPropertyDescriptor(final Class<?> clazz, final String propertyName) {
try {
return getPropertyDescriptor(Introspector.getBeanInfo(clazz), propertyName);
} catch (final IntrospectionException e) {
throw new RuntimeException("Failed getting bean info for " + clazz, e);
}
}
/**
* Gets the property descriptor for the named property from the bean info describing
* a particular class to which property belongs.
* @param info Bean info describing class to which property belongs.
* @param propertyName Name of property.
* @return Property descriptor for given property or null if no property with given
* name exists.
*/
public static PropertyDescriptor getPropertyDescriptor(final BeanInfo info, final String propertyName) {
for (int i = 0; i < info.getPropertyDescriptors().length; i++) {
final PropertyDescriptor pd = info.getPropertyDescriptors()[i];
if (pd.getName().equals(propertyName)) {
return pd;
}
}
return null;
}
/**
* Sets the given property on the target JavaBean using bean instrospection.
* @param propertyName Property to set.
* @param value Property value to set.
* @param target Target java bean on which to set property.
*/
public static void setProperty(final String propertyName, final Object value, final Object target) {
try {
setProperty(propertyName, value, target, Introspector.getBeanInfo(target.getClass()));
} catch (final IntrospectionException e) {
throw new RuntimeException("Failed getting bean info on target JavaBean " + target, e);
}
}
/**
* Sets the given property on the target JavaBean using bean instrospection.
* @param propertyName Property to set.
* @param value Property value to set.
* @param target Target JavaBean on which to set property.
* @param info BeanInfo describing the target JavaBean.
*/
public static void setProperty(final String propertyName, final Object value, final Object target,
final BeanInfo info) {
try {
final PropertyDescriptor pd = getPropertyDescriptor(info, propertyName);
pd.getWriteMethod().invoke(target, value);
} catch (final InvocationTargetException e) {
throw new RuntimeException("Error setting property " + propertyName, e.getCause());
} catch (final Exception e) {
throw new RuntimeException("Error setting property " + propertyName, e);
}
}
/**
* Gets the value of the given declared field on the target object or any of its superclasses.
*
* @param fieldName Name of field to get.
* @param target Target object that possesses field.
*
* @return Field value.
*/
public static Object getField(final String fieldName, final Object target) {
Class<?> clazz = target.getClass();
Field field = null;
do {
try {
field = clazz.getDeclaredField(fieldName);
} catch (final NoSuchFieldException e) {
clazz = clazz.getSuperclass();
}
} while (field == null && clazz != null);
if (field == null) {
throw new IllegalArgumentException(fieldName + " does not exist on " + target);
}
try {
if (!field.isAccessible()) {
field.setAccessible(true);
}
return field.get(target);
} catch (final Exception e) {
throw new IllegalArgumentException("Error getting field " + fieldName, e);
}
}
}

View File

@ -1,109 +0,0 @@
/**
* Licensed to Apereo under one or more contributor license
* agreements. See the NOTICE file distributed with this work
* for additional information regarding copyright ownership.
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at the following location:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
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;
}
@Override
public Object evaluate(final Object o, final QName qName) throws XPathExpressionException {
return get().evaluate(o, qName);
}
@Override
public String evaluate(final Object o) throws XPathExpressionException {
return get().evaluate(o);
}
@Override
public Object evaluate(final InputSource inputSource, final QName qName) throws XPathExpressionException {
return get().evaluate(inputSource, qName);
}
@Override
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 (final XPathExpressionException e) {
throw new IllegalArgumentException("Invalid XPath expression");
}
}
}

View File

@ -1,682 +0,0 @@
/**
* Licensed to Apereo under one or more contributor license
* agreements. See the NOTICE file distributed with this work
* for additional information regarding copyright ownership.
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at the following location:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jasig.cas.client.util;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.Serializable;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URLDecoder;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.regex.Pattern;
/**
* A utility class borrowed from apache http-client to build uris.
*
* @author Misagh Moayyed
* @since 3.4
*/
public final class URIBuilder {
private static final Logger LOGGER = LoggerFactory.getLogger(URIBuilder.class);
private static final Pattern IPV6_STD_PATTERN = Pattern.compile("^[0-9a-fA-F]{1,4}(:[0-9a-fA-F]{1,4}){7}$");
private String scheme;
private String encodedSchemeSpecificPart;
private String encodedAuthority;
private String userInfo;
private String encodedUserInfo;
private String host;
private int port;
private String path;
private String encodedPath;
private String encodedQuery;
private List<BasicNameValuePair> queryParams;
private String query;
private boolean encode;
private String fragment;
private String encodedFragment;
/**
* Constructs an empty instance.
*/
public URIBuilder() {
super();
this.port = -1;
}
public URIBuilder(final boolean encode) {
this();
setEncode(encode);
}
/**
* Construct an instance from the string which must be a valid URI.
*
* @param string a valid URI in string form
* @throws RuntimeException if the input is not a valid URI
*/
public URIBuilder(final String string) {
super();
try {
digestURI(new URI(string));
} catch (final URISyntaxException e) {
throw new RuntimeException(e.getMessage(), e);
}
}
public URIBuilder(final String string, final boolean encode) {
super();
try {
setEncode(encode);
digestURI(new URI(string));
} catch (final URISyntaxException e) {
throw new RuntimeException(e.getMessage(), e);
}
}
/**
* Construct an instance from the provided URI.
*
* @param uri the uri to digest
*/
public URIBuilder(final URI uri) {
super();
digestURI(uri);
}
private List<BasicNameValuePair> parseQuery(final String query) {
try {
final Charset utf8 = Charset.forName("UTF-8");
if (query != null && !query.isEmpty()) {
final List<BasicNameValuePair> list = new ArrayList<BasicNameValuePair>();
final String[] parametersArray = query.split("&");
for (final String parameter : parametersArray) {
final int firstIndex = parameter.indexOf("=");
if (firstIndex != -1) {
final String paramName = parameter.substring(0, firstIndex);
final String decodedParamName = URLDecoder.decode(paramName, utf8.name());
final String paramVal = parameter.substring(firstIndex + 1);
final String decodedParamVal = URLDecoder.decode(paramVal, utf8.name());
list.add(new BasicNameValuePair(decodedParamName, decodedParamVal));
} else {
// Either we do not have a query parameter, or it might be encoded; take it verbaitm
final String[] parameterCombo = parameter.split("=");
if (parameterCombo.length >= 1) {
final String key = URLDecoder.decode(parameterCombo[0], utf8.name());
final String val = parameterCombo.length == 2 ? URLDecoder.decode(parameterCombo[1], utf8.name()) : "";
list.add(new BasicNameValuePair(key, val));
}
}
}
return list;
}
} catch (final UnsupportedEncodingException e) {
LOGGER.error(e.getMessage(), e);
}
return new ArrayList<BasicNameValuePair>();
}
/**
* Builds a {@link URI} instance.
*/
public URI build() {
try {
return new URI(buildString());
} catch (final URISyntaxException e) {
throw new RuntimeException(e);
}
}
private static boolean isIPv6Address(final String input) {
return IPV6_STD_PATTERN.matcher(input).matches();
}
private String buildString() {
final StringBuilder sb = new StringBuilder();
if (this.scheme != null) {
sb.append(this.scheme).append(':');
}
if (this.encodedSchemeSpecificPart != null) {
sb.append(this.encodedSchemeSpecificPart);
} else {
if (this.encodedAuthority != null) {
sb.append("//").append(this.encodedAuthority);
} else if (this.host != null) {
sb.append("//");
if (this.encodedUserInfo != null) {
sb.append(this.encodedUserInfo).append("@");
} else if (this.userInfo != null) {
sb.append(encodeUserInfo(this.userInfo)).append("@");
}
if (isIPv6Address(this.host)) {
sb.append("[").append(this.host).append("]");
} else {
sb.append(this.host);
}
if (this.port >= 0) {
sb.append(":").append(this.port);
}
}
if (this.encodedPath != null) {
sb.append(normalizePath(this.encodedPath));
} else if (this.path != null) {
sb.append(encodePath(normalizePath(this.path)));
}
if (this.encodedQuery != null) {
sb.append("?").append(this.encodedQuery);
} else if (this.queryParams != null && !this.queryParams.isEmpty()) {
sb.append("?").append(encodeUrlForm(this.queryParams));
} else if (this.query != null) {
sb.append("?").append(encodeUric(this.query));
}
}
if (this.encodedFragment != null) {
sb.append("#").append(this.encodedFragment);
} else if (this.fragment != null) {
sb.append("#").append(encodeUric(this.fragment));
}
return sb.toString();
}
public URIBuilder digestURI(final URI uri) {
this.scheme = uri.getScheme();
this.encodedSchemeSpecificPart = uri.getRawSchemeSpecificPart();
this.encodedAuthority = uri.getRawAuthority();
this.host = uri.getHost();
this.port = uri.getPort();
this.encodedUserInfo = uri.getRawUserInfo();
this.userInfo = uri.getUserInfo();
this.encodedPath = uri.getRawPath();
this.path = uri.getPath();
this.encodedQuery = uri.getRawQuery();
this.queryParams = parseQuery(uri.getRawQuery());
this.encodedFragment = uri.getRawFragment();
this.fragment = uri.getFragment();
return this;
}
private String encodeUserInfo(final String userInfo) {
return this.encode ? CommonUtils.urlEncode(userInfo) : userInfo;
}
private String encodePath(final String path) {
return this.encode ? CommonUtils.urlEncode(path) : path;
}
private String encodeUrlForm(final List<BasicNameValuePair> params) {
final StringBuilder result = new StringBuilder();
for (final BasicNameValuePair parameter : params) {
final String encodedName = this.encode ? CommonUtils.urlEncode(parameter.getName()) : parameter.getName();
final String encodedValue = this.encode ? CommonUtils.urlEncode(parameter.getValue()) : parameter.getValue();
if (result.length() > 0) {
result.append("&");
}
result.append(encodedName);
if (encodedValue != null) {
result.append("=");
result.append(encodedValue);
}
}
return result.toString();
}
private String encodeUric(final String fragment) {
return this.encode ? CommonUtils.urlEncode(fragment) : fragment;
}
public URIBuilder setEncode(final boolean encode) {
this.encode = encode;
return this;
}
/**
* Sets URI scheme.
*/
public URIBuilder setScheme(final String scheme) {
this.scheme = scheme;
return this;
}
/**
* Sets URI user info. The value is expected to be unescaped and may contain non ASCII
* characters.
*/
public URIBuilder setUserInfo(final String userInfo) {
this.userInfo = userInfo;
this.encodedSchemeSpecificPart = null;
this.encodedAuthority = null;
this.encodedUserInfo = null;
return this;
}
/**
* Sets URI user info as a combination of username and password. These values are expected to
* be unescaped and may contain non ASCII characters.
*/
public URIBuilder setUserInfo(final String username, final String password) {
return setUserInfo(username + ':' + password);
}
/**
* Sets URI host.
*/
public URIBuilder setHost(final String host) {
this.host = host;
this.encodedSchemeSpecificPart = null;
this.encodedAuthority = null;
return this;
}
/**
* Sets URI port.
*/
public URIBuilder setPort(final int port) {
this.port = port < 0 ? -1 : port;
this.encodedSchemeSpecificPart = null;
this.encodedAuthority = null;
return this;
}
/**
* Sets URI path. The value is expected to be unescaped and may contain non ASCII characters.
*/
public URIBuilder setPath(final String path) {
this.path = path;
this.encodedSchemeSpecificPart = null;
this.encodedPath = null;
return this;
}
public URIBuilder setEncodedPath(final String path) {
this.encodedPath = path;
this.encodedSchemeSpecificPart = null;
return this;
}
/**
* Removes URI query.
*/
public URIBuilder removeQuery() {
this.queryParams = null;
this.query = null;
this.encodedQuery = null;
this.encodedSchemeSpecificPart = null;
return this;
}
/**
* Sets URI query parameters. The parameter name / values are expected to be unescaped
* and may contain non ASCII characters.
* <p>
* Please note query parameters and custom query component are mutually exclusive. This method
* will remove custom query if present.
* </p>
*/
public URIBuilder setParameters(final List<BasicNameValuePair> nvps) {
this.queryParams = new ArrayList<BasicNameValuePair>();
this.queryParams.addAll(nvps);
this.encodedQuery = null;
this.encodedSchemeSpecificPart = null;
this.query = null;
return this;
}
public URIBuilder setParameters(final String queryParameters) {
this.queryParams = new ArrayList<BasicNameValuePair>();
this.queryParams.addAll(parseQuery(queryParameters));
this.encodedQuery = null;
this.encodedSchemeSpecificPart = null;
this.query = null;
return this;
}
/**
* Adds URI query parameters. The parameter name / values are expected to be unescaped
* and may contain non ASCII characters.
* <p>
* Please note query parameters and custom query component are mutually exclusive. This method
* will remove custom query if present.
* </p>
*/
public URIBuilder addParameters(final List<BasicNameValuePair> nvps) {
if (this.queryParams == null || this.queryParams.isEmpty()) {
this.queryParams = new ArrayList<BasicNameValuePair>();
}
this.queryParams.addAll(nvps);
this.encodedQuery = null;
this.encodedSchemeSpecificPart = null;
this.query = null;
return this;
}
/**
* Sets URI query parameters. The parameter name / values are expected to be unescaped
* and may contain non ASCII characters.
* <p>
* Please note query parameters and custom query component are mutually exclusive. This method
* will remove custom query if present.
* </p>
*/
public URIBuilder setParameters(final BasicNameValuePair... nvps) {
if (this.queryParams == null) {
this.queryParams = new ArrayList<BasicNameValuePair>();
} else {
this.queryParams.clear();
}
for (final BasicNameValuePair nvp : nvps) {
this.queryParams.add(nvp);
}
this.encodedQuery = null;
this.encodedSchemeSpecificPart = null;
this.query = null;
return this;
}
/**
* Adds parameter to URI query. The parameter name and value are expected to be unescaped
* and may contain non ASCII characters.
* <p>
* Please note query parameters and custom query component are mutually exclusive. This method
* will remove custom query if present.
* </p>
*/
public URIBuilder addParameter(final String param, final String value) {
if (this.queryParams == null) {
this.queryParams = new ArrayList<BasicNameValuePair>();
}
this.queryParams.add(new BasicNameValuePair(param, value));
this.encodedQuery = null;
this.encodedSchemeSpecificPart = null;
this.query = null;
return this;
}
/**
* Sets parameter of URI query overriding existing value if set. The parameter name and value
* are expected to be unescaped and may contain non ASCII characters.
* <p>
* Please note query parameters and custom query component are mutually exclusive. This method
* will remove custom query if present.
* </p>
*/
public URIBuilder setParameter(final String param, final String value) {
if (this.queryParams == null) {
this.queryParams = new ArrayList<BasicNameValuePair>();
}
if (!this.queryParams.isEmpty()) {
for (final Iterator<BasicNameValuePair> it = this.queryParams.iterator(); it.hasNext(); ) {
final BasicNameValuePair nvp = it.next();
if (nvp.getName().equals(param)) {
it.remove();
}
}
}
this.queryParams.add(new BasicNameValuePair(param, value));
this.encodedQuery = null;
this.encodedSchemeSpecificPart = null;
this.query = null;
return this;
}
/**
* Clears URI query parameters.
*/
public URIBuilder clearParameters() {
this.queryParams = null;
this.encodedQuery = null;
this.encodedSchemeSpecificPart = null;
return this;
}
/**
* Sets custom URI query. The value is expected to be unescaped and may contain non ASCII
* characters.
* <p>
* Please note query parameters and custom query component are mutually exclusive. This method
* will remove query parameters if present.
* </p>
*/
public URIBuilder setCustomQuery(final String query) {
this.query = query;
this.encodedQuery = null;
this.encodedSchemeSpecificPart = null;
this.queryParams = null;
return this;
}
/**
* Sets URI fragment. The value is expected to be unescaped and may contain non ASCII
* characters.
*/
public URIBuilder setFragment(final String fragment) {
this.fragment = fragment;
this.encodedFragment = null;
return this;
}
public URIBuilder setEncodedFragment(final String fragment) {
this.fragment = null;
this.encodedFragment = fragment;
return this;
}
public URIBuilder setEncodedQuery(final String query) {
this.query = null;
this.encodedFragment = query;
return this;
}
public boolean isAbsolute() {
return this.scheme != null;
}
public boolean isOpaque() {
return this.path == null;
}
public String getScheme() {
return this.scheme;
}
public String getUserInfo() {
return this.userInfo;
}
public String getHost() {
return this.host;
}
public int getPort() {
return this.port;
}
public String getPath() {
return this.path;
}
public String getEncodedPath() {
return this.encodedPath;
}
public List<BasicNameValuePair> getQueryParams() {
if (this.queryParams != null) {
return new ArrayList<BasicNameValuePair>(this.queryParams);
}
return new ArrayList<BasicNameValuePair>();
}
public String getFragment() {
return this.fragment;
}
@Override
public String toString() {
return buildString();
}
private static String normalizePath(final String path) {
String s = path;
if (s == null) {
return null;
}
int n = 0;
for (; n < s.length(); n++) {
if (s.charAt(n) != '/') {
break;
}
}
if (n > 1) {
s = s.substring(n - 1);
}
return s;
}
@Override
public boolean equals(final Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
final URIBuilder that = (URIBuilder) o;
if (port != that.port) return false;
if (encode != that.encode) return false;
if (scheme != null ? !scheme.equals(that.scheme) : that.scheme != null) return false;
if (encodedSchemeSpecificPart != null ? !encodedSchemeSpecificPart.equals(that.encodedSchemeSpecificPart) : that.encodedSchemeSpecificPart != null)
return false;
if (encodedAuthority != null ? !encodedAuthority.equals(that.encodedAuthority) : that.encodedAuthority != null)
return false;
if (userInfo != null ? !userInfo.equals(that.userInfo) : that.userInfo != null) return false;
if (encodedUserInfo != null ? !encodedUserInfo.equals(that.encodedUserInfo) : that.encodedUserInfo != null)
return false;
if (host != null ? !host.equals(that.host) : that.host != null) return false;
if (path != null ? !path.equals(that.path) : that.path != null) return false;
if (encodedPath != null ? !encodedPath.equals(that.encodedPath) : that.encodedPath != null) return false;
if (encodedQuery != null ? !encodedQuery.equals(that.encodedQuery) : that.encodedQuery != null) return false;
if (queryParams != null ? !queryParams.equals(that.queryParams) : that.queryParams != null) return false;
if (query != null ? !query.equals(that.query) : that.query != null) return false;
if (fragment != null ? !fragment.equals(that.fragment) : that.fragment != null) return false;
return !(encodedFragment != null ? !encodedFragment.equals(that.encodedFragment) : that.encodedFragment != null);
}
@Override
public int hashCode() {
int result = scheme != null ? scheme.hashCode() : 0;
result = 31 * result + (encodedSchemeSpecificPart != null ? encodedSchemeSpecificPart.hashCode() : 0);
result = 31 * result + (encodedAuthority != null ? encodedAuthority.hashCode() : 0);
result = 31 * result + (userInfo != null ? userInfo.hashCode() : 0);
result = 31 * result + (encodedUserInfo != null ? encodedUserInfo.hashCode() : 0);
result = 31 * result + (host != null ? host.hashCode() : 0);
result = 31 * result + port;
result = 31 * result + (path != null ? path.hashCode() : 0);
result = 31 * result + (encodedPath != null ? encodedPath.hashCode() : 0);
result = 31 * result + (encodedQuery != null ? encodedQuery.hashCode() : 0);
result = 31 * result + (queryParams != null ? queryParams.hashCode() : 0);
result = 31 * result + (query != null ? query.hashCode() : 0);
result = 31 * result + (encode ? 1 : 0);
result = 31 * result + (fragment != null ? fragment.hashCode() : 0);
result = 31 * result + (encodedFragment != null ? encodedFragment.hashCode() : 0);
return result;
}
public static class BasicNameValuePair implements Cloneable, Serializable {
private static final long serialVersionUID = -6437800749411518984L;
private final String name;
private final String value;
/**
* Default Constructor taking a name and a value. The value may be null.
*
* @param name The name.
* @param value The value.
*/
public BasicNameValuePair(final String name, final String value) {
super();
this.name = name;
this.value = value;
}
public String getName() {
return this.name;
}
public String getValue() {
return this.value;
}
@Override
public String toString() {
// don't call complex default formatting for a simple toString
if (this.value == null) {
return name;
}
final int len = this.name.length() + 1 + this.value.length();
final StringBuilder buffer = new StringBuilder(len);
buffer.append(this.name);
buffer.append("=");
buffer.append(this.value);
return buffer.toString();
}
@Override
public boolean equals(final Object object) {
if (this == object) {
return true;
}
if (object == null) {
return false;
}
if (object instanceof BasicNameValuePair) {
final BasicNameValuePair that = (BasicNameValuePair) object;
return this.name.equals(that.name)
&& this.value.equals(that.value);
}
return false;
}
@Override
public int hashCode() {
return 133 * this.name.hashCode() * this.value.hashCode();
}
@Override
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
}

View File

@ -1,44 +1,28 @@
/**
* Licensed to Apereo under one or more contributor license
* agreements. See the NOTICE file distributed with this work
* for additional information regarding copyright ownership.
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at the following location:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
/*
* Copyright 2007 The JA-SIG Collaborative. All rights reserved. See license
* distributed with this file and available online at
* http://www.ja-sig.org/products/cas/overview/license/index.html
*/
package org.jasig.cas.client.util;
import java.io.StringReader;
import java.util.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;
import org.xml.sax.helpers.XMLReaderFactory;
import javax.xml.XMLConstants;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParserFactory;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.List;
/**
* Common utilities for easily parsing XML without duplicating logic.
*
* @author Scott Battaglia
* @version $Revision: 11729 $ $Date: 2007-09-26 14:22:30 -0400 (Tue, 26 Sep 2007) $
* @since 3.0
*/
public final class XmlUtils {
@ -46,37 +30,7 @@ public final class XmlUtils {
/**
* Static instance of Commons Logging.
*/
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);
features.put("http://apache.org/xml/features/disallow-doctype-decl", true);
for (final Map.Entry<String, Boolean> entry : features.entrySet()) {
try {
factory.setFeature(entry.getKey(), entry.getValue());
} catch (final ParserConfigurationException e) {
LOGGER.warn("Failed setting XML feature {}: {}", entry.getKey(), e);
}
}
factory.setExpandEntityReferences(false);
factory.setNamespaceAware(true);
try {
return factory.newDocumentBuilder().parse(new InputSource(new StringReader(xml)));
} catch (final Exception e) {
throw new RuntimeException("XML parsing error: " + e);
}
}
private final static Log LOG = LogFactory.getLog(XmlUtils.class);
/**
* Get an instance of an XML reader from the XMLReaderFactory.
@ -85,20 +39,12 @@ public final class XmlUtils {
*/
public static XMLReader getXmlReader() {
try {
final SAXParserFactory factory = SAXParserFactory.newInstance();
factory.setNamespaceAware(true);
factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
factory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
factory.setFeature("http://xml.org/sax/features/external-general-entities", false);
factory.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
return factory.newSAXParser().getXMLReader();
} catch (final Exception e) {
return XMLReaderFactory.createXMLReader();
} catch (final SAXException e) {
throw new RuntimeException("Unable to create XMLReader", e);
}
}
/**
* Retrieve the text for a group of elements. Each text element is an entry
* in a list.
@ -108,35 +54,36 @@ public final class XmlUtils {
* @param element the element to look for
* @return the list of text from the elements.
*/
public static List<String> getTextForElements(final String xmlAsString, final String element) {
final List<String> elements = new ArrayList<String>(2);
public static List getTextForElements(final String xmlAsString,
final String element) {
final List elements = new ArrayList(2);
final XMLReader reader = getXmlReader();
final DefaultHandler handler = new DefaultHandler() {
private boolean foundElement = false;
private StringBuilder buffer = new StringBuilder();
private StringBuffer buffer = new StringBuffer();
@Override
public void startElement(final String uri, final String localName, final String qName,
final Attributes attributes) throws SAXException {
public void startElement(final String uri, final String localName,
final String qName, final Attributes attributes)
throws SAXException {
if (localName.equals(element)) {
this.foundElement = true;
}
}
@Override
public void endElement(final String uri, final String localName, final String qName) throws SAXException {
public void endElement(final String uri, final String localName,
final String qName) throws SAXException {
if (localName.equals(element)) {
this.foundElement = false;
elements.add(this.buffer.toString());
this.buffer = new StringBuilder();
this.buffer = new StringBuffer();
}
}
@Override
public void characters(final char[] ch, final int start, final int length) throws SAXException {
public void characters(char[] ch, int start, int length)
throws SAXException {
if (this.foundElement) {
this.buffer.append(ch, start, length);
}
@ -149,7 +96,7 @@ public final class XmlUtils {
try {
reader.parse(new InputSource(new StringReader(xmlAsString)));
} catch (final Exception e) {
LOGGER.error(e.getMessage(), e);
LOG.error(e, e);
return null;
}
@ -164,33 +111,34 @@ public final class XmlUtils {
* @param element the element to look for
* @return the text value of the element.
*/
public static String getTextForElement(final String xmlAsString, final String element) {
public static String getTextForElement(final String xmlAsString,
final String element) {
final XMLReader reader = getXmlReader();
final StringBuilder builder = new StringBuilder();
final StringBuffer buffer = new StringBuffer();
final DefaultHandler handler = new DefaultHandler() {
private boolean foundElement = false;
@Override
public void startElement(final String uri, final String localName, final String qName,
final Attributes attributes) throws SAXException {
public void startElement(final String uri, final String localName,
final String qName, final Attributes attributes)
throws SAXException {
if (localName.equals(element)) {
this.foundElement = true;
}
}
@Override
public void endElement(final String uri, final String localName, final String qName) throws SAXException {
public void endElement(final String uri, final String localName,
final String qName) throws SAXException {
if (localName.equals(element)) {
this.foundElement = false;
}
}
@Override
public void characters(final char[] ch, final int start, final int length) throws SAXException {
public void characters(char[] ch, int start, int length)
throws SAXException {
if (this.foundElement) {
builder.append(ch, start, length);
buffer.append(ch, start, length);
}
}
};
@ -201,10 +149,10 @@ public final class XmlUtils {
try {
reader.parse(new InputSource(new StringReader(xmlAsString)));
} catch (final Exception e) {
LOGGER.error(e.getMessage(), e);
LOG.error(e, e);
return null;
}
return builder.toString();
return buffer.toString();
}
}

View File

@ -1,23 +1,3 @@
<!--
Licensed to Apereo under one or more contributor license
agreements. See the NOTICE file distributed with this work
for additional information regarding copyright ownership.
Apereo licenses this file to you under the Apache License,
Version 2.0 (the "License"); you may not use this file
except in compliance with the License. You may obtain a
copy of the License at the following location:
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->
<html>
<body>
<p>The validation package includes interfaces for validating Tickets, as well as the common implementations.</p>

View File

@ -1,25 +1,15 @@
/**
* Licensed to Apereo under one or more contributor license
* agreements. See the NOTICE file distributed with this work
* for additional information regarding copyright ownership.
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at the following location:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
/*
* Copyright 2007 The JA-SIG Collaborative. All rights reserved. See license
* distributed with this file and available online at
* http://www.ja-sig.org/products/cas/overview/license/index.html
*/
package org.jasig.cas.client.validation;
import java.net.URL;
import org.jasig.cas.client.util.CommonUtils;
import java.net.HttpURLConnection;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;
/**
* Abstract class that knows the protocol for validating a CAS ticket.
@ -37,8 +27,31 @@ public abstract class AbstractCasProtocolUrlBasedTicketValidator extends Abstrac
/**
* Retrieves the response from the server by opening a connection and merely reading the response.
*/
@Override
protected final String retrieveResponseFromServer(final URL validationUrl, final String ticket) {
return CommonUtils.getResponseFromServer(validationUrl, getURLConnectionFactory(), getEncoding());
HttpURLConnection connection = null;
try {
connection = (HttpURLConnection) validationUrl.openConnection();
final BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
String line;
final StringBuffer stringBuffer = new StringBuffer(255);
synchronized (stringBuffer) {
while ((line = in.readLine()) != null) {
stringBuffer.append(line);
stringBuffer.append("\n");
}
return stringBuffer.toString();
}
} catch (final IOException e) {
log.error(e,e);
return null;
} finally {
if (connection != null) {
connection.disconnect();
}
}
}
}

View File

@ -1,49 +1,31 @@
/**
* Licensed to Apereo under one or more contributor license
* agreements. See the NOTICE file distributed with this work
* for additional information regarding copyright ownership.
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at the following location:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
/*
* Copyright 2007 The JA-SIG Collaborative. All rights reserved. See license
* distributed with this file and available online at
* http://www.ja-sig.org/products/cas/overview/license/index.html
*/
package org.jasig.cas.client.validation;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Properties;
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;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* The filter that handles all the work of validating ticket requests.
* <p>
* This filter can be configured with the following values:
* <ul>
* <li><code>redirectAfterValidation</code> - redirect the CAS client to the same URL without the ticket.
* (default: true, Will be forced to false when {@link #useSession} is false.)</li>
* <li><code>redirectAfterValidation</code> - redirect the CAS client to the same URL without the ticket.</li>
* <li><code>exceptionOnValidationFailure</code> - throw an exception if the validation fails. Otherwise, continue
* processing. (default: true)</li>
* <li><code>useSession</code> - store any of the useful information in a session attribute. (default: true)</li>
* <li><code>hostnameVerifier</code> - name of class implementing a {@link HostnameVerifier}.</li>
* <li><code>hostnameVerifierConfig</code> - name of configuration class (constructor argument of verifier).</li>
* processing.</li>
* <li><code>useSession</code> - store any of the useful information in a session attribute.</li>
* </ul>
*
* @author Scott Battaglia
@ -60,89 +42,31 @@ public abstract class AbstractTicketValidationFilter extends AbstractCasFilter {
* successful validation to remove the ticket parameter from the query
* string.
*/
private boolean redirectAfterValidation = true;
private boolean redirectAfterValidation = false;
/** Determines whether an exception is thrown when there is a ticket validation failure. */
private boolean exceptionOnValidationFailure = false;
private boolean exceptionOnValidationFailure = true;
/**
* Specify whether the Assertion should be stored in a session
* attribute {@link AbstractCasFilter#CONST_CAS_ASSERTION}.
*/
private boolean useSession = true;
protected AbstractTicketValidationFilter(final Protocol protocol) {
super(protocol);
}
/**
* Template method to return the appropriate validator.
*
* @param filterConfig the FilterConfiguration that may be needed to construct a validator.
* @return the ticket validator.
*/
protected TicketValidator getTicketValidator(final FilterConfig filterConfig) {
protected TicketValidator getTicketValidator(FilterConfig filterConfig) {
return this.ticketValidator;
}
/**
* Gets the ssl config to use for HTTPS connections
* if one is configured for this filter.
* @return Properties that can contains key/trust info for Client Side Certificates
*/
protected Properties getSSLConfig() {
final Properties properties = new Properties();
final String fileName = getString(ConfigurationKeys.SSL_CONFIG_FILE);
if (fileName != null) {
FileInputStream fis = null;
try {
fis = new FileInputStream(fileName);
properties.load(fis);
logger.trace("Loaded {} entries from {}", properties.size(), fileName);
} catch (final IOException ioe) {
logger.error(ioe.getMessage(), ioe);
} finally {
CommonUtils.closeQuietly(fis);
}
}
return properties;
}
/**
* Gets the configured {@link HostnameVerifier} to use for HTTPS connections
* if one is configured for this filter.
* @return Instance of specified host name verifier or null if none specified.
*/
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);
} else {
return ReflectUtils.newInstance(className);
}
}
return null;
}
@Override
protected void initInternal(final FilterConfig filterConfig) throws ServletException {
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.");
setRedirectAfterValidation(false);
}
setTicketValidator(getTicketValidator(filterConfig));
super.initInternal(filterConfig);
setExceptionOnValidationFailure(Boolean.parseBoolean(getPropertyFromInitParams(filterConfig, "exceptionOnValidationFailure", "true")));
setRedirectAfterValidation(Boolean.parseBoolean(getPropertyFromInitParams(filterConfig, "redirectAfterValidation", "false")));
setUseSession(Boolean.parseBoolean(getPropertyFromInitParams(filterConfig, "useSession", "true")));
setTicketValidator(getTicketValidator(filterConfig));
}
@Override
public void init() {
super.init();
CommonUtils.assertNotNull(this.ticketValidator, "ticketValidator cannot be null.");
@ -158,8 +82,7 @@ public abstract class AbstractTicketValidationFilter extends AbstractCasFilter {
* @throws IOException if there is an I/O problem
* @throws ServletException if there is a servlet problem.
*/
protected boolean preFilter(final ServletRequest servletRequest, final ServletResponse servletResponse,
final FilterChain filterChain) throws IOException, ServletException {
protected boolean preFilter(final ServletRequest servletRequest, final ServletResponse servletResponse, final FilterChain filterChain) throws IOException, ServletException {
return true;
}
@ -172,9 +95,8 @@ public abstract class AbstractTicketValidationFilter extends AbstractCasFilter {
* @param response the HttpServletResponse.
* @param assertion the successful Assertion from the server.
*/
protected void onSuccessfulValidation(final HttpServletRequest request, final HttpServletResponse response,
final Assertion assertion) {
// nothing to do here.
protected void onSuccessfulValidation(final HttpServletRequest request, final HttpServletResponse response, final Assertion assertion) {
// nothing to do here.
}
/**
@ -188,9 +110,7 @@ public abstract class AbstractTicketValidationFilter extends AbstractCasFilter {
// nothing to do here.
}
@Override
public final void doFilter(final ServletRequest servletRequest, final ServletResponse servletResponse,
final FilterChain filterChain) throws IOException, ServletException {
public final void doFilter(final ServletRequest servletRequest, final ServletResponse servletResponse, final FilterChain filterChain) throws IOException, ServletException {
if (!preFilter(servletRequest, servletResponse, filterChain)) {
return;
@ -198,40 +118,44 @@ public abstract class AbstractTicketValidationFilter extends AbstractCasFilter {
final HttpServletRequest request = (HttpServletRequest) servletRequest;
final HttpServletResponse response = (HttpServletResponse) servletResponse;
final String ticket = retrieveTicketFromRequest(request);
final String ticket = request.getParameter(getArtifactParameterName());
if (CommonUtils.isNotBlank(ticket)) {
logger.debug("Attempting to validate ticket: {}", ticket);
if (log.isDebugEnabled()) {
log.debug("Attempting to validate ticket: " + ticket);
}
try {
final Assertion assertion = this.ticketValidator.validate(ticket,
constructServiceUrl(request, response));
final Assertion assertion = this.ticketValidator.validate(
ticket, constructServiceUrl(request,
response));
logger.debug("Successfully authenticated user: {}", assertion.getPrincipal().getName());
if (log.isDebugEnabled()) {
log.debug("Successfully authenticated user: "
+ assertion.getPrincipal().getName());
}
request.setAttribute(CONST_CAS_ASSERTION, assertion);
if (this.useSession) {
request.getSession().setAttribute(CONST_CAS_ASSERTION, assertion);
request.getSession().setAttribute(CONST_CAS_ASSERTION,
assertion);
}
onSuccessfulValidation(request, response, assertion);
if (this.redirectAfterValidation) {
logger.debug("Redirecting after successful ticket validation.");
response.sendRedirect(constructServiceUrl(request, response));
return;
}
} catch (final TicketValidationException e) {
logger.debug(e.getMessage(), e);
response.setStatus(HttpServletResponse.SC_FORBIDDEN);
log.warn(e, e);
onFailedValidation(request, response);
if (this.exceptionOnValidationFailure) {
throw new ServletException(e);
}
}
response.sendError(HttpServletResponse.SC_FORBIDDEN, e.getMessage());
if (this.redirectAfterValidation) {
response.sendRedirect(response
.encodeRedirectURL(constructServiceUrl(request, response)));
return;
}
}
@ -241,8 +165,8 @@ public abstract class AbstractTicketValidationFilter extends AbstractCasFilter {
}
public final void setTicketValidator(final TicketValidator ticketValidator) {
this.ticketValidator = ticketValidator;
}
this.ticketValidator = ticketValidator;
}
public final void setRedirectAfterValidation(final boolean redirectAfterValidation) {
this.redirectAfterValidation = redirectAfterValidation;

View File

@ -1,50 +1,35 @@
/**
* Licensed to Apereo under one or more contributor license
* agreements. See the NOTICE file distributed with this work
* for additional information regarding copyright ownership.
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at the following location:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
/*
* Copyright 2007 The JA-SIG Collaborative. All rights reserved. See license
* distributed with this file and available online at
* http://www.ja-sig.org/products/cas/overview/license/index.html
*/
package org.jasig.cas.client.validation;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jasig.cas.client.util.CommonUtils;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import org.jasig.cas.client.ssl.HttpURLConnectionFactory;
import org.jasig.cas.client.ssl.HttpsURLConnectionFactory;
import org.jasig.cas.client.util.CommonUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Abstract validator implementation for tickets that must be validated against a server.
*
* @author Scott Battaglia
* @version $Revision$ $Date$
* @since 3.1
*/
public abstract class AbstractUrlBasedTicketValidator implements TicketValidator {
protected final Logger logger = LoggerFactory.getLogger(getClass());
/**
* URLConnection factory instance to use when making validation requests to the CAS server.
* Defaults to {@link HttpsURLConnectionFactory}
* Commons Logging instance.
*/
private HttpURLConnectionFactory urlConnectionFactory = new HttpsURLConnectionFactory();
protected final Log log = LogFactory.getLog(getClass());
/**
* Prefix for the CAS server. Should be everything up to the url endpoint, including the /.
@ -58,21 +43,14 @@ public abstract class AbstractUrlBasedTicketValidator implements TicketValidator
*/
private boolean renew;
/**
* A map containing custom parameters to pass to the validation url.
*/
private Map<String, String> customParameters;
private String encoding;
/**
* Constructs a new TicketValidator with the casServerUrlPrefix.
*
* @param casServerUrlPrefix the location of the CAS server.
*/
protected AbstractUrlBasedTicketValidator(final String casServerUrlPrefix) {
CommonUtils.assertNotNull(casServerUrlPrefix, "casServerUrlPrefix cannot be null.");
this.casServerUrlPrefix = CommonUtils.addTrailingSlash(casServerUrlPrefix);
this.casServerUrlPrefix = casServerUrlPrefix;
CommonUtils.assertNotNull(this.casServerUrlPrefix, "casServerUrlPrefix cannot be null.");
}
/**
@ -80,7 +58,7 @@ public abstract class AbstractUrlBasedTicketValidator implements TicketValidator
*
* @param urlParameters the map containing the parameters.
*/
protected void populateUrlAttributeMap(final Map<String, String> urlParameters) {
protected void populateUrlAttributeMap(final Map urlParameters) {
// nothing to do
}
@ -90,7 +68,6 @@ public abstract class AbstractUrlBasedTicketValidator implements TicketValidator
*/
protected abstract String getUrlSuffix();
/**
* Constructs the URL to send the validation request to.
*
@ -99,48 +76,41 @@ public abstract class AbstractUrlBasedTicketValidator implements TicketValidator
* @return the fully constructed URL.
*/
protected final String constructValidationUrl(final String ticket, final String serviceUrl) {
final Map<String, String> urlParameters = new HashMap<String, String>();
final Map urlParameters = new HashMap();
logger.debug("Placing URL parameters in map.");
urlParameters.put("ticket", ticket);
urlParameters.put("service", serviceUrl);
urlParameters.put("service", encodeUrl(serviceUrl));
if (this.renew) {
urlParameters.put("renew", "true");
}
logger.debug("Calling template URL attribute map.");
populateUrlAttributeMap(urlParameters);
logger.debug("Loading custom parameters from configuration.");
if (this.customParameters != null) {
urlParameters.putAll(this.customParameters);
}
final String suffix = getUrlSuffix();
final StringBuilder buffer = new StringBuilder(urlParameters.size() * 10 + this.casServerUrlPrefix.length()
+ suffix.length() + 1);
final StringBuffer buffer = new StringBuffer(urlParameters.size()*10 + this.casServerUrlPrefix.length() + suffix.length() +1);
int i = 0;
synchronized (buffer) {
buffer.append(this.casServerUrlPrefix);
buffer.append("/");
buffer.append(suffix);
buffer.append(this.casServerUrlPrefix);
buffer.append(suffix);
for (final Map.Entry<String, String> entry : urlParameters.entrySet()) {
final String key = entry.getKey();
final String value = entry.getValue();
if (value != null) {
for (final Iterator iter = urlParameters.entrySet().iterator(); iter.hasNext();) {
buffer.append(i++ == 0 ? "?" : "&");
buffer.append(key);
buffer.append("=");
final String encodedValue = encodeUrl(value);
buffer.append(encodedValue);
final Map.Entry entry = (Map.Entry) iter.next();
final String key = (String) entry.getKey();
final String value = (String) entry.getValue();
if (value != null) {
buffer.append(key);
buffer.append("=");
buffer.append(value);
}
}
return buffer.toString();
}
return buffer.toString();
}
/**
@ -150,10 +120,10 @@ public abstract class AbstractUrlBasedTicketValidator implements TicketValidator
* @return the encoded url, or the original url if "UTF-8" character encoding could not be found.
*/
protected final String encodeUrl(final String url) {
if (url == null) {
return null;
}
if (url == null) {
return null;
}
try {
return URLEncoder.encode(url, "UTF-8");
} catch (final UnsupportedEncodingException e) {
@ -181,60 +151,24 @@ public abstract class AbstractUrlBasedTicketValidator implements TicketValidator
protected abstract String retrieveResponseFromServer(URL validationUrl, String ticket);
@Override
public final Assertion validate(final String ticket, final String service) throws TicketValidationException {
public Assertion validate(final String ticket, final String service) throws TicketValidationException {
final String validationUrl = constructValidationUrl(ticket, service);
logger.debug("Constructing validation url: {}", validationUrl);
try {
logger.debug("Retrieving response from server.");
final String serverResponse = retrieveResponseFromServer(new URL(validationUrl), ticket);
if (serverResponse == null) {
throw new TicketValidationException("The CAS server returned no response.");
}
logger.debug("Server response: {}", serverResponse);
return parseResponseFromServer(serverResponse);
} catch (final MalformedURLException e) {
throw new TicketValidationException(e);
}
}
public final void setRenew(final boolean renew) {
public void setRenew(final boolean renew) {
this.renew = renew;
}
public final void setCustomParameters(final Map<String, String> customParameters) {
this.customParameters = customParameters;
}
public final void setEncoding(final String encoding) {
this.encoding = encoding;
}
protected final String getEncoding() {
return this.encoding;
}
protected final boolean isRenew() {
return this.renew;
}
protected final String getCasServerUrlPrefix() {
return this.casServerUrlPrefix;
}
protected final Map<String, String> getCustomParameters() {
return this.customParameters;
}
protected HttpURLConnectionFactory getURLConnectionFactory() {
return this.urlConnectionFactory;
}
public void setURLConnectionFactory(final HttpURLConnectionFactory urlConnectionFactory) {
this.urlConnectionFactory = urlConnectionFactory;
}
}
}

View File

@ -1,27 +1,15 @@
/**
* Licensed to Apereo under one or more contributor license
* agreements. See the NOTICE file distributed with this work
* for additional information regarding copyright ownership.
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at the following location:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
/*
* Copyright 2007 The JA-SIG Collaborative. All rights reserved. See license
* distributed with this file and available online at
* http://www.ja-sig.org/products/cas/overview/license/index.html
*/
package org.jasig.cas.client.validation;
import org.jasig.cas.client.authentication.AttributePrincipal;
import java.io.Serializable;
import java.util.Date;
import java.util.Map;
import org.jasig.cas.client.authentication.AttributePrincipal;
/**
* Represents a response to a validation request.
@ -46,20 +34,12 @@ public interface Assertion extends Serializable {
*/
Date getValidUntilDate();
/**
* The date the authentication actually occurred on. If its unable to be determined, it should be set to the current
* time.
*
* @return the authentication date, or the current time if it can't be determined.
*/
Date getAuthenticationDate();
/**
* The key/value pairs associated with this assertion.
*
* @return the map of attributes.
*/
Map<String, Object> getAttributes();
Map getAttributes();
/**
* The principal for which this assertion is valid.
@ -67,12 +47,4 @@ public interface Assertion extends Serializable {
* @return the principal.
*/
AttributePrincipal getPrincipal();
/**
* Determines whether an Assertion is considered usable or not. A naive implementation may just check the date validity.
*
* @return true if its valid, false otherwise.
* @since 3.3.0 (though in 3.3.0, no one actually calls this)
*/
boolean isValid();
}

View File

@ -1,30 +1,18 @@
/**
* Licensed to Apereo under one or more contributor license
* agreements. See the NOTICE file distributed with this work
* for additional information regarding copyright ownership.
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at the following location:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
/*
* Copyright 2007 The JA-SIG Collaborative. All rights reserved. See license
* distributed with this file and available online at
* http://www.ja-sig.org/products/cas/overview/license/index.html
*/
package org.jasig.cas.client.validation;
import java.util.Collections;
import java.util.Date;
import java.util.Map;
import org.jasig.cas.client.authentication.AttributePrincipal;
import org.jasig.cas.client.authentication.AttributePrincipalImpl;
import org.jasig.cas.client.util.CommonUtils;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
/**
* Concrete Implementation of the {@link Assertion}.
*
@ -36,18 +24,16 @@ import org.jasig.cas.client.util.CommonUtils;
public final class AssertionImpl implements Assertion {
/** Unique Id for serialization. */
private static final long serialVersionUID = -7767943925833639221L;
private static final long serialVersionUID = -7767943925833639221L;
/** The date from which the assertion is valid. */
/** The date from which the assertion is valid. */
private final Date validFromDate;
/** The date the assertion is valid until. */
private final Date validUntilDate;
private final Date authenticationDate;
/** Map of key/value pairs associated with this assertion. I.e. authentication type. */
private final Map<String, Object> attributes;
private final Map attributes;
/** The principal for which this assertion is valid for. */
private final AttributePrincipal principal;
@ -58,16 +44,16 @@ public final class AssertionImpl implements Assertion {
* @param name the name of the principal for which this assertion is valid.
*/
public AssertionImpl(final String name) {
this(new AttributePrincipalImpl(name));
this(new AttributePrincipalImpl(name));
}
/**
* Creates a new Assertion with the supplied Principal.
* Creates a new Assrtion with the supplied Principal.
*
* @param principal the Principal to associate with the Assertion.
*/
public AssertionImpl(final AttributePrincipal principal) {
this(principal, Collections.<String, Object> emptyMap());
this(principal, new HashMap());
}
/**
@ -76,64 +62,41 @@ public final class AssertionImpl implements Assertion {
* @param principal the Principal to associate with the Assertion.
* @param attributes the key/value pairs for this attribute.
*/
public AssertionImpl(final AttributePrincipal principal, final Map<String, Object> attributes) {
this(principal, new Date(), null, new Date(), attributes);
public AssertionImpl(final AttributePrincipal principal, final Map attributes) {
this(principal, new Date(), null, attributes);
}
/**
* Creates a new Assertion with the supplied principal, Assertion attributes, and start and valid until dates.
* Creats a new Assertion with the supplied principal, Assertion attributes, and start and valid until dates.
*
* @param principal the Principal to associate with the Assertion.
* @param validFromDate when the assertion is valid from.
* @param validUntilDate when the assertion is valid to.
* @param attributes the key/value pairs for this attribute.
*/
public AssertionImpl(final AttributePrincipal principal, final Date validFromDate, final Date validUntilDate,
final Date authenticationDate, final Map<String, Object> attributes) {
public AssertionImpl(final AttributePrincipal principal, final Date validFromDate, final Date validUntilDate, final Map attributes) {
this.principal = principal;
this.validFromDate = validFromDate;
this.validUntilDate = validUntilDate;
this.attributes = attributes;
this.authenticationDate = authenticationDate;
CommonUtils.assertNotNull(this.principal, "principal cannot be null.");
CommonUtils.assertNotNull(this.validFromDate, "validFromDate cannot be null.");
CommonUtils.assertNotNull(this.attributes, "attributes cannot be null.");
}
@Override
public Date getAuthenticationDate() {
return this.authenticationDate;
}
@Override
public Date getValidFromDate() {
return this.validFromDate;
}
@Override
public Date getValidUntilDate() {
return this.validUntilDate;
}
@Override
public Map<String, Object> getAttributes() {
public Map getAttributes() {
return this.attributes;
}
@Override
public AttributePrincipal getPrincipal() {
return this.principal;
}
@Override
public boolean isValid() {
if (this.validFromDate == null) {
return true;
}
final Date now = new Date();
return (this.validFromDate.before(now) || this.validFromDate.equals(now))
&& (this.validUntilDate == null || this.validUntilDate.after(now) || this.validUntilDate.equals(now));
}
}

View File

@ -1,55 +1,27 @@
/**
* Licensed to Apereo under one or more contributor license
* agreements. See the NOTICE file distributed with this work
* for additional information regarding copyright ownership.
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at the following location:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
/*
* Copyright 2007 The JA-SIG Collaborative. All rights reserved. See license
* distributed with this file and available online at
* http://www.ja-sig.org/products/cas/overview/license/index.html
*/
package org.jasig.cas.client.validation;
import javax.servlet.FilterConfig;
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 creates a Cas10TicketValidator.
* Implementation of AbstractTicketValidatorFilter that instanciates a Cas10TicketValidator.
* <p>Deployers can provide the "casServerPrefix" and the "renew" attributes via the standard context or filter init
* parameters.
*
*
* @author Scott Battaglia
* @version $Revision$ $Date$
* @since 3.1
*/
public class Cas10TicketValidationFilter extends AbstractTicketValidationFilter {
public Cas10TicketValidationFilter() {
super(Protocol.CAS1);
}
@Override
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(getString(ConfigurationKeys.ENCODING));
final String casUrlServerPrefix = getPropertyFromInitParams(filterConfig, "casUrlServerPrefix", null);
final Cas10TicketValidator validator = new Cas10TicketValidator(casUrlServerPrefix);
validator.setRenew(Boolean.parseBoolean(getPropertyFromInitParams(filterConfig, "renew", "false")));
return validator;
}

View File

@ -1,20 +1,7 @@
/**
* Licensed to Apereo under one or more contributor license
* agreements. See the NOTICE file distributed with this work
* for additional information regarding copyright ownership.
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at the following location:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
/*
* Copyright 2007 The JA-SIG Collaborative. All rights reserved. See license
* distributed with this file and available online at
* http://www.ja-sig.org/products/cas/overview/license/index.html
*/
package org.jasig.cas.client.validation;
@ -35,19 +22,18 @@ public final class Cas10TicketValidator extends AbstractCasProtocolUrlBasedTicke
super(casServerUrlPrefix);
}
@Override
protected String getUrlSuffix() {
return "validate";
}
@Override
protected Assertion parseResponseFromServer(final String response) throws TicketValidationException {
if (!response.startsWith("yes")) {
throw new TicketValidationException("CAS Server could not validate ticket.");
}
try {
final BufferedReader reader = new BufferedReader(new StringReader(response));
final BufferedReader reader = new BufferedReader(new StringReader(
response));
reader.readLine();
final String name = reader.readLine();

View File

@ -1,157 +1,66 @@
/**
* Licensed to Apereo under one or more contributor license
* agreements. See the NOTICE file distributed with this work
* for additional information regarding copyright ownership.
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at the following location:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
/*
* Copyright 2007 The JA-SIG Collaborative. All rights reserved. See license
* distributed with this file and available online at
* http://www.ja-sig.org/products/cas/overview/license/index.html
*/
package org.jasig.cas.client.validation;
import java.io.IOException;
import java.security.PrivateKey;
import java.util.*;
import javax.servlet.*;
import org.jasig.cas.client.proxy.Cas20ProxyRetriever;
import org.jasig.cas.client.proxy.ProxyGrantingTicketStorage;
import org.jasig.cas.client.proxy.ProxyGrantingTicketStorageImpl;
import org.jasig.cas.client.util.CommonUtils;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import 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.PrivateKeyUtils;
import org.jasig.cas.client.util.ReflectUtils;
import static org.jasig.cas.client.configuration.ConfigurationKeys.*;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* Creates either a CAS20ProxyTicketValidator or a CAS20ServiceTicketValidator depending on whether any of the
* proxy parameters are set.
* <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 Scott Battaglia
* @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[]{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(), RELAY_STATE_PARAMETER_NAME.getName(), METHOD.getName(), PRIVATE_KEY_PATH.getName(), PRIVATE_KEY_ALGORITHM.getName()
};
/**
* Constant representing the ProxyGrantingTicket IOU Request Parameter.
*/
private static final String PARAM_PROXY_GRANTING_TICKET_IOU = "pgtIou";
/**
* The URL to send to the CAS server as the URL that will process proxying requests on the CAS client.
* Constant representing the ProxyGrantingTicket Request Parameter.
*/
private static final String PARAM_PROXY_GRANTING_TICKET = "pgtId";
/**
* The URL to send to the CAS server as the URL that will process proxying requests on the CAS client.
*/
private String proxyReceptorUrl;
private Timer timer;
private TimerTask timerTask;
private int millisBetweenCleanUps;
protected Class<? extends Cas20ServiceTicketValidator> defaultServiceTicketValidatorClass;
protected Class<? extends Cas20ProxyTicketValidator> defaultProxyTicketValidatorClass;
private PrivateKey privateKey;
/**
* Storage location of ProxyGrantingTickets and Proxy Ticket IOUs.
*/
private ProxyGrantingTicketStorage proxyGrantingTicketStorage = new ProxyGrantingTicketStorageImpl();
public Cas20ProxyReceivingTicketValidationFilter() {
this(Protocol.CAS2);
this.defaultServiceTicketValidatorClass = Cas20ServiceTicketValidator.class;
this.defaultProxyTicketValidatorClass = Cas20ProxyTicketValidator.class;
}
protected Cas20ProxyReceivingTicketValidationFilter(final Protocol protocol) {
super(protocol);
}
@Override
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 = getString(ConfigurationKeys.CIPHER_ALGORITHM);
final String secretKey = getString(ConfigurationKeys.SECRET_KEY);
p.setCipherAlgorithm(cipherAlgorithm);
try {
if (secretKey != null) {
p.setSecretKey(secretKey);
}
} catch (final Exception e) {
throw new RuntimeException(e);
}
}
}
this.millisBetweenCleanUps = getInt(ConfigurationKeys.MILLIS_BETWEEN_CLEAN_UPS);
this.privateKey = buildPrivateKey(getString(PRIVATE_KEY_PATH), getString(PRIVATE_KEY_ALGORITHM));
super.initInternal(filterConfig);
setProxyReceptorUrl(getPropertyFromInitParams(filterConfig, "proxyReceptorUrl", null));
}
@Override
public void init() {
super.init();
CommonUtils.assertNotNull(this.proxyGrantingTicketStorage, "proxyGrantingTicketStorage cannot be null.");
if (this.timer == null) {
this.timer = new Timer(true);
}
if (this.timerTask == null) {
this.timerTask = new CleanUpTimerTask(this.proxyGrantingTicketStorage);
}
this.timer.schedule(this.timerTask, this.millisBetweenCleanUps, this.millisBetweenCleanUps);
}
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 (T) ReflectUtils.newInstance(ticketValidatorClass, casServerUrlPrefix);
}
public static PrivateKey buildPrivateKey(final String keyPath, final String keyAlgorithm) {
if (keyPath != null) {
return PrivateKeyUtils.createKey(keyPath, keyAlgorithm);
}
return null;
}
/**
@ -160,64 +69,43 @@ public class Cas20ProxyReceivingTicketValidationFilter extends AbstractTicketVal
* @param filterConfig the Filter Configuration object.
* @return a fully constructed TicketValidator.
*/
@Override
protected final TicketValidator getTicketValidator(final FilterConfig filterConfig) {
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 String allowAnyProxy = getPropertyFromInitParams(filterConfig, "acceptAnyProxy", null);
final String allowedProxyChains = getPropertyFromInitParams(filterConfig, "allowedProxyChains", null);
final String casServerUrlPrefix = getPropertyFromInitParams(filterConfig, "casServerUrlPrefix", null);
final Cas20ServiceTicketValidator validator;
if (allowAnyProxy || CommonUtils.isNotBlank(allowedProxyChains)) {
final Cas20ProxyTicketValidator v = createNewTicketValidator(ticketValidatorClass, casServerUrlPrefix,
this.defaultProxyTicketValidatorClass);
v.setAcceptAnyProxy(allowAnyProxy);
v.setAllowedProxyChains(CommonUtils.createProxyList(allowedProxyChains));
if (CommonUtils.isNotBlank(allowAnyProxy) || CommonUtils.isNotBlank(allowedProxyChains)) {
final Cas20ProxyTicketValidator v = new Cas20ProxyTicketValidator(casServerUrlPrefix);
v.setAcceptAnyProxy(Boolean.parseBoolean(allowAnyProxy));
v.setAllowedProxyChains(constructListOfProxies(allowedProxyChains));
validator = v;
} else {
validator = createNewTicketValidator(ticketValidatorClass, casServerUrlPrefix,
this.defaultServiceTicketValidatorClass);
validator = new Cas20ServiceTicketValidator(casServerUrlPrefix);
}
validator.setProxyCallbackUrl(getString(ConfigurationKeys.PROXY_CALLBACK_URL));
validator.setProxyCallbackUrl(getPropertyFromInitParams(filterConfig, "proxyCallbackUrl", null));
validator.setProxyGrantingTicketStorage(this.proxyGrantingTicketStorage);
final HttpURLConnectionFactory factory = new HttpsURLConnectionFactory(getHostnameVerifier(),
getSSLConfig());
validator.setURLConnectionFactory(factory);
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(); ) {
final String s = (String) e.nextElement();
if (!params.contains(s)) {
additionalParameters.put(s, filterConfig.getInitParameter(s));
}
}
validator.setPrivateKey(this.privateKey);
validator.setCustomParameters(additionalParameters);
validator.setProxyRetriever(new Cas20ProxyRetriever(casServerUrlPrefix));
validator.setRenew(Boolean.parseBoolean(getPropertyFromInitParams(filterConfig, "renew", "false")));
return validator;
}
@Override
public void destroy() {
super.destroy();
this.timer.cancel();
protected final List constructListOfProxies(final String proxies) {
if (CommonUtils.isBlank(proxies)) {
return new ArrayList();
}
final String[] splitProxies = proxies.split("\n");
final List items = Arrays.asList(splitProxies);
final ProxyListPropertyEditor editor = new ProxyListPropertyEditor();
editor.setValue(items);
return (List) editor.getValue();
}
/**
* This processes the ProxyReceptor request before the ticket validation code executes.
*/
@Override
protected final boolean preFilter(final ServletRequest servletRequest, final ServletResponse servletResponse,
final FilterChain filterChain) throws IOException, ServletException {
protected final boolean preFilter(final ServletRequest servletRequest, final ServletResponse servletResponse, final FilterChain filterChain) throws IOException, ServletException {
final HttpServletRequest request = (HttpServletRequest) servletRequest;
final HttpServletResponse response = (HttpServletResponse) servletResponse;
final String requestUri = request.getRequestURI();
@ -226,13 +114,29 @@ public class Cas20ProxyReceivingTicketValidationFilter extends AbstractTicketVal
return true;
}
try {
CommonUtils.readAndRespondToProxyReceptorRequest(request, response, this.proxyGrantingTicketStorage);
} catch (final RuntimeException e) {
logger.error(e.getMessage(), e);
throw e;
final String proxyGrantingTicketIou = request
.getParameter(PARAM_PROXY_GRANTING_TICKET_IOU);
final String proxyGrantingTicket = request
.getParameter(PARAM_PROXY_GRANTING_TICKET);
if (CommonUtils.isBlank(proxyGrantingTicket)
|| CommonUtils.isBlank(proxyGrantingTicketIou)) {
response.getWriter().write("");
return false;
}
if (log.isDebugEnabled()) {
log.debug("Received proxyGrantingTicketId ["
+ proxyGrantingTicket + "] for proxyGrantingTicketIou ["
+ proxyGrantingTicketIou + "]");
}
this.proxyGrantingTicketStorage.save(proxyGrantingTicketIou,
proxyGrantingTicket);
response.getWriter().write("<?xml version=\"1.0\"?>");
response.getWriter().write("<casClient:proxySuccess xmlns:casClient=\"http://www.yale.edu/tp/casClient\" />");
return false;
}
@ -240,19 +144,7 @@ public class Cas20ProxyReceivingTicketValidationFilter extends AbstractTicketVal
this.proxyReceptorUrl = proxyReceptorUrl;
}
public void setProxyGrantingTicketStorage(final ProxyGrantingTicketStorage storage) {
this.proxyGrantingTicketStorage = storage;
}
public void setTimer(final Timer timer) {
this.timer = timer;
}
public void setTimerTask(final TimerTask timerTask) {
this.timerTask = timerTask;
}
public void setMillisBetweenCleanUps(final int millisBetweenCleanUps) {
this.millisBetweenCleanUps = millisBetweenCleanUps;
public final void setProxyGrantingTicketStorage(final ProxyGrantingTicketStorage proxyGrantingTicketStorage) {
this.proxyGrantingTicketStorage = proxyGrantingTicketStorage;
}
}

View File

@ -1,118 +1,62 @@
/**
* Licensed to Apereo under one or more contributor license
* agreements. See the NOTICE file distributed with this work
* for additional information regarding copyright ownership.
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at the following location:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
/*
* Copyright 2007 The JA-SIG Collaborative. All rights reserved. See license
* distributed with this file and available online at
* http://www.ja-sig.org/products/cas/overview/license/index.html
*/
package org.jasig.cas.client.validation;
import java.util.Arrays;
import java.util.List;
import org.jasig.cas.client.util.XmlUtils;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
/**
* Extension to the traditional Service Ticket validation that will validate service tickets and proxy tickets.
*
* @author Scott Battaglia
* @version $Revision$ $Date$
* @since 3.1
*/
public class Cas20ProxyTicketValidator extends Cas20ServiceTicketValidator {
public final class Cas20ProxyTicketValidator extends Cas20ServiceTicketValidator {
private boolean acceptAnyProxy;
/** This should be a list of an array of Strings */
private ProxyList allowedProxyChains = new ProxyList();
/** Allows for an empty chain of proxy callback urls. **/
private boolean allowEmptyProxyChain = true;
private List allowedProxyChains = new ArrayList();
public Cas20ProxyTicketValidator(final String casServerUrlPrefix) {
super(casServerUrlPrefix);
}
protected final ProxyList getAllowedProxyChains() {
return this.allowedProxyChains;
}
@Override
protected String getUrlSuffix() {
return "proxyValidate";
}
@Override
protected void customParseResponse(final String response, final Assertion assertion)
throws TicketValidationException {
final List<String> proxies = parseProxiesFromResponse(response);
protected void customParseResponse(final String response, final Assertion assertion) throws TicketValidationException {
final List proxies = XmlUtils.getTextForElements(response, "proxy");
final String[] proxiedList = (String[]) proxies.toArray(new String[proxies.size()]);
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()) {
logger.debug("Found an empty proxy chain, permitted by client configuration");
if (proxies == null || proxies.isEmpty() || this.acceptAnyProxy) {
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;
for (Iterator iter = this.allowedProxyChains.iterator(); iter.hasNext();) {
if (Arrays.equals(proxiedList, (String[]) iter.next())) {
return;
}
}
final String[] proxiedList = proxies.toArray(new String[proxies.size()]);
if (this.allowedProxyChains.contains(proxiedList)) {
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());
}
protected List<String> parseProxiesFromResponse(final String response) {
return XmlUtils.getTextForElements(response, "proxy");
}
public final void setAcceptAnyProxy(final boolean acceptAnyProxy) {
public void setAcceptAnyProxy(final boolean acceptAnyProxy) {
this.acceptAnyProxy = acceptAnyProxy;
}
public final void setAllowedProxyChains(final ProxyList allowedProxyChains) {
public void setAllowedProxyChains(final List allowedProxyChains) {
this.allowedProxyChains = allowedProxyChains;
}
protected final boolean isAcceptAnyProxy() {
return this.acceptAnyProxy;
}
protected final boolean isAllowEmptyProxyChain() {
return this.allowEmptyProxyChain;
}
/**
* Set to determine whether empty proxy chains are allowed.
* @see #customParseResponse(String, Assertion)
* @param allowEmptyProxyChain whether to allow empty proxy chains or not. True if so, false otherwise.
*/
public final void setAllowEmptyProxyChain(final boolean allowEmptyProxyChain) {
this.allowEmptyProxyChain = allowEmptyProxyChain;
}
}

View File

@ -0,0 +1,44 @@
/*
* Copyright 2007 The JA-SIG Collaborative. All rights reserved. See license
* distributed with this file and available online at
* http://www.ja-sig.org/products/cas/overview/license/index.html
*/
package org.jasig.cas.client.validation;
import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.beans.PropertyEditor;
import java.beans.SimpleBeanInfo;
import org.springframework.beans.propertyeditors.CustomBooleanEditor;
/**
* BeanInfo support for using this class with Spring. Configures a ProxyListPropertyEditor to be used with the
* Cas20ProxyTicketValidator when Spring is used to configure the CAS client.
*
* @author Scott Battaglia
* @version $Revision$ $Date$
* @since 3.1
*/
public final class Cas20ProxyTicketValidatorBeanInfo extends SimpleBeanInfo {
public PropertyDescriptor[] getPropertyDescriptors() {
try {
final PropertyDescriptor descriptor = new PropertyDescriptor("allowedProxyChains", Cas20ProxyTicketValidator.class, null, "setAllowedProxyChains") {
public PropertyEditor createPropertyEditor(final Object bean) {
return new ProxyListPropertyEditor();
}
};
final PropertyDescriptor acceptAnyProxy = new PropertyDescriptor("acceptAnyProxy", Cas20ProxyTicketValidator.class, null, "setAcceptAnyProxy") {
public PropertyEditor createPropertyEditor(final Object bean) {
return new CustomBooleanEditor(true);
}
};
return new PropertyDescriptor[] {descriptor, acceptAnyProxy};
} catch (final IntrospectionException e) {
throw new RuntimeException(e);
}
}
}

View File

@ -1,31 +1,10 @@
/**
* Licensed to Apereo under one or more contributor license
* agreements. See the NOTICE file distributed with this work
* for additional information regarding copyright ownership.
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at the following location:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
/*
* Copyright 2007 The JA-SIG Collaborative. All rights reserved. See license
* distributed with this file and available online at
* http://www.ja-sig.org/products/cas/overview/license/index.html
*/
package org.jasig.cas.client.validation;
import java.io.StringReader;
import java.security.PrivateKey;
import java.util.*;
import javax.crypto.Cipher;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.apache.commons.codec.binary.Base64;
import org.jasig.cas.client.authentication.AttributePrincipal;
import org.jasig.cas.client.authentication.AttributePrincipalImpl;
import org.jasig.cas.client.proxy.Cas20ProxyRetriever;
@ -33,23 +12,18 @@ import org.jasig.cas.client.proxy.ProxyGrantingTicketStorage;
import org.jasig.cas.client.proxy.ProxyRetriever;
import org.jasig.cas.client.util.CommonUtils;
import org.jasig.cas.client.util.XmlUtils;
import 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 java.util.Map;
/**
* Implementation of the TicketValidator that will validate Service Tickets in compliance with the CAS 2.
*
* @author Scott Battaglia
* @version $Revision$ $Date$
* @since 3.1
*/
public class Cas20ServiceTicketValidator extends AbstractCasProtocolUrlBasedTicketValidator {
public static final String PGT_ATTRIBUTE = "proxyGrantingTicket";
private static final String PGTIOU_PREFIX = "PGTIOU-";
/** The CAS 2.0 protocol proxy callback url. */
private String proxyCallbackUrl;
@ -59,9 +33,6 @@ public class Cas20ServiceTicketValidator extends AbstractCasProtocolUrlBasedTick
/** Implementation of the proxy retriever. */
private ProxyRetriever proxyRetriever;
/** Private key for decryption */
private PrivateKey privateKey;
/**
* Constructs an instance of the CAS 2.0 Service Ticket Validator with the supplied
* CAS server url prefix.
@ -70,7 +41,7 @@ public class Cas20ServiceTicketValidator extends AbstractCasProtocolUrlBasedTick
*/
public Cas20ServiceTicketValidator(final String casServerUrlPrefix) {
super(casServerUrlPrefix);
this.proxyRetriever = new Cas20ProxyRetriever(casServerUrlPrefix, getEncoding(), getURLConnectionFactory());
this.proxyRetriever = new Cas20ProxyRetriever(casServerUrlPrefix);
}
/**
@ -78,40 +49,37 @@ public class Cas20ServiceTicketValidator extends AbstractCasProtocolUrlBasedTick
*
* @param urlParameters the Map containing the existing parameters to send to the server.
*/
@Override
protected final void populateUrlAttributeMap(final Map<String, String> urlParameters) {
urlParameters.put("pgtUrl", this.proxyCallbackUrl);
protected final void populateUrlAttributeMap(final Map urlParameters) {
urlParameters.put("pgtUrl", encodeUrl(this.proxyCallbackUrl));
}
@Override
protected String getUrlSuffix() {
return "serviceValidate";
}
@Override
protected Assertion parseResponseFromServer(final String response) throws TicketValidationException {
final String error = parseAuthenticationFailureFromResponse(response);
protected final Assertion parseResponseFromServer(final String response) throws TicketValidationException {
final String error = XmlUtils.getTextForElement(response,
"authenticationFailure");
if (CommonUtils.isNotBlank(error)) {
throw new TicketValidationException(error);
}
final String principal = parsePrincipalFromResponse(response);
final String proxyGrantingTicket = retrieveProxyGrantingTicket(response);
final String principal = XmlUtils.getTextForElement(response, "user");
final String proxyGrantingTicketIou = XmlUtils.getTextForElement(
response, "proxyGrantingTicket");
final String proxyGrantingTicket = this.proxyGrantingTicketStorage != null ? this.proxyGrantingTicketStorage.retrieve(proxyGrantingTicketIou) : null;
if (CommonUtils.isEmpty(principal)) {
throw new TicketValidationException("No principal was found in the response from the CAS server.");
}
final Assertion assertion;
final Map<String, Object> attributes = extractCustomAttributes(response);
if (CommonUtils.isNotBlank(proxyGrantingTicket)) {
attributes.remove(PGT_ATTRIBUTE);
final AttributePrincipal attributePrincipal = new AttributePrincipalImpl(principal, attributes,
proxyGrantingTicket, this.proxyRetriever);
final AttributePrincipal attributePrincipal = new AttributePrincipalImpl(principal, proxyGrantingTicket, this.proxyRetriever);
assertion = new AssertionImpl(attributePrincipal);
} else {
assertion = new AssertionImpl(new AttributePrincipalImpl(principal, attributes));
assertion = new AssertionImpl(principal);
}
customParseResponse(response, assertion);
@ -119,87 +87,6 @@ public class Cas20ServiceTicketValidator extends AbstractCasProtocolUrlBasedTick
return assertion;
}
protected String retrieveProxyGrantingTicket(final String response) {
final List<String> values = XmlUtils.getTextForElements(response, PGT_ATTRIBUTE);
for (final String value : values) {
if (value != null) {
if (value.startsWith(PGTIOU_PREFIX)) {
return retrieveProxyGrantingTicketFromStorage(value);
} else {
return retrieveProxyGrantingTicketViaEncryption(value);
}
}
}
return null;
}
protected String retrieveProxyGrantingTicketFromStorage(final String pgtIou) {
if (this.proxyGrantingTicketStorage != null) {
return this.proxyGrantingTicketStorage.retrieve(pgtIou);
}
return null;
}
protected String retrieveProxyGrantingTicketViaEncryption(final String encryptedPgt) {
if (this.privateKey != null) {
try {
final Cipher cipher = Cipher.getInstance(privateKey.getAlgorithm());
final byte[] cred64 = new Base64().decode(encryptedPgt);
cipher.init(Cipher.DECRYPT_MODE, privateKey);
final byte[] cipherData = cipher.doFinal(cred64);
final String pgt = new String(cipherData);
logger.debug("Decrypted PGT: {}", pgt);
return pgt;
} catch (final Exception e) {
logger.error("Unable to decrypt PGT", e);
}
}
return null;
}
protected String parsePrincipalFromResponse(final String response) {
return XmlUtils.getTextForElement(response, "user");
}
protected String parseAuthenticationFailureFromResponse(final String response) {
return XmlUtils.getTextForElement(response, "authenticationFailure");
}
/**
* Default attribute parsing of attributes that look like the following:
* &lt;cas:attributes&gt;
* &lt;cas:attribute1&gt;value&lt;/cas:attribute1&gt;
* &lt;cas:attribute2&gt;value&lt;/cas:attribute2&gt;
* &lt;/cas:attributes&gt;
* <p>
*
* Attributes look like following also parsed correctly:
* &lt;cas:attributes&gt;&lt;cas:attribute1&gt;value&lt;/cas:attribute1&gt;&lt;cas:attribute2&gt;value&lt;/cas:attribute2&gt;&lt;/cas:attributes&gt;
* <p>
*
* This code is here merely for sample/demonstration purposes for those wishing to modify the CAS2 protocol. You'll
* probably want a more robust implementation or to use SAML 1.1
*
* @param xml the XML to parse.
* @return the map of attributes.
*/
protected Map<String, Object> extractCustomAttributes(final String xml) {
final SAXParserFactory spf = SAXParserFactory.newInstance();
spf.setNamespaceAware(true);
spf.setValidating(false);
try {
final SAXParser saxParser = spf.newSAXParser();
final XMLReader xmlReader = saxParser.getXMLReader();
final CustomAttributeHandler handler = new CustomAttributeHandler();
xmlReader.setContentHandler(handler);
xmlReader.parse(new InputSource(new StringReader(xml)));
return handler.getAttributes();
} catch (final Exception e) {
logger.error(e.getMessage(), e);
return Collections.emptyMap();
}
}
/**
* Template method if additional custom parsing (such as Proxying) needs to be done.
*
@ -207,8 +94,7 @@ public class Cas20ServiceTicketValidator extends AbstractCasProtocolUrlBasedTick
* @param assertion the partially constructed assertion.
* @throws TicketValidationException if there is a problem constructing the Assertion.
*/
protected void customParseResponse(final String response, final Assertion assertion)
throws TicketValidationException {
protected void customParseResponse(final String response, final Assertion assertion) throws TicketValidationException {
// nothing to do
}
@ -222,88 +108,5 @@ public class Cas20ServiceTicketValidator extends AbstractCasProtocolUrlBasedTick
public final void setProxyRetriever(final ProxyRetriever proxyRetriever) {
this.proxyRetriever = proxyRetriever;
}
protected final String getProxyCallbackUrl() {
return this.proxyCallbackUrl;
}
protected final ProxyGrantingTicketStorage getProxyGrantingTicketStorage() {
return this.proxyGrantingTicketStorage;
}
protected final ProxyRetriever getProxyRetriever() {
return this.proxyRetriever;
}
private class CustomAttributeHandler extends DefaultHandler {
private Map<String, Object> attributes;
private boolean foundAttributes;
private String currentAttribute;
private StringBuilder value;
@Override
public void startDocument() throws SAXException {
this.attributes = new HashMap<String, Object>();
}
@Override
public void startElement(final String namespaceURI, final String localName, final String qName,
final Attributes attributes) throws SAXException {
if ("attributes".equals(localName)) {
this.foundAttributes = true;
} else if (this.foundAttributes) {
this.value = new StringBuilder();
this.currentAttribute = localName;
}
}
@Override
public void characters(final char[] chars, final int start, final int length) throws SAXException {
if (this.currentAttribute != null) {
value.append(chars, start, length);
}
}
@Override
public void endElement(final String namespaceURI, final String localName, final String qName)
throws SAXException {
if ("attributes".equals(localName)) {
this.foundAttributes = false;
this.currentAttribute = null;
} else if (this.foundAttributes) {
final Object o = this.attributes.get(this.currentAttribute);
if (o == null) {
this.attributes.put(this.currentAttribute, this.value.toString());
} else {
final List<Object> items;
if (o instanceof List) {
items = (List<Object>) o;
} else {
items = new LinkedList<Object>();
items.add(o);
this.attributes.put(this.currentAttribute, items);
}
items.add(this.value.toString());
}
}
}
public Map<String, Object> getAttributes() {
return this.attributes;
}
}
public PrivateKey getPrivateKey() {
return privateKey;
}
public void setPrivateKey(final PrivateKey privateKey) {
this.privateKey = privateKey;
}
}
}

View File

@ -1,40 +0,0 @@
/**
* Licensed to Apereo under one or more contributor license
* agreements. See the NOTICE file distributed with this work
* for additional information regarding copyright ownership.
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at the following location:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
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;
}
}

View File

@ -1,37 +0,0 @@
/**
* Licensed to Apereo under one or more contributor license
* agreements. See the NOTICE file distributed with this work
* for additional information regarding copyright ownership.
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at the following location:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
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";
}
}

View File

@ -1,90 +0,0 @@
/**
* Licensed to Apereo under one or more contributor license
* agreements. See the NOTICE file distributed with this work
* for additional information regarding copyright ownership.
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at the following location:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jasig.cas.client.validation;
import org.jasig.cas.client.util.XmlUtils;
import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
/**
* Service tickets validation service for the CAS protocol v3.
*
* @author Jerome Leleu
* @since 3.4.0
*/
public class Cas30ServiceTicketValidator extends Cas20ServiceTicketValidator {
public Cas30ServiceTicketValidator(final String casServerUrlPrefix) {
super(casServerUrlPrefix);
}
@Override
protected String getUrlSuffix() {
return "p3/serviceValidate";
}
/**
* Custom attribute extractor that will account for inlined CAS attributes. Useful when CAS is acting as
* as SAML 2 IdP and returns SAML attributes with names that contains namespaces.
*
* @param xml the XML to parse.
* @return - Map of attributes
*/
@Override
protected Map<String, Object> extractCustomAttributes(final String xml) {
final Document document = XmlUtils.newDocument(xml);
// Check if attributes are inlined. If not return default super method results
final NodeList attributeList = document.getElementsByTagName("cas:attribute");
if (attributeList.getLength() == 0) {
return super.extractCustomAttributes(xml);
}
final HashMap<String, Object> attributes = new HashMap<String, Object>();
for (int i = 0; i < attributeList.getLength(); i++) {
final Node casAttributeNode = attributeList.item(i);
final NamedNodeMap nodeAttributes = casAttributeNode.getAttributes();
final String name = nodeAttributes.getNamedItem("name").getNodeValue();
final String value = nodeAttributes.getNamedItem("value").getTextContent();
final Object mapValue = attributes.get(name);
if (mapValue != null) {
if (mapValue instanceof List) {
((List) mapValue).add(value);
} else {
final LinkedList<Object> list = new LinkedList<Object>();
list.add(mapValue);
list.add(value);
attributes.put(name, list);
}
} else {
attributes.put(name, value);
}
}
return attributes;
}
}

View File

@ -1,20 +1,7 @@
/**
* Licensed to Apereo under one or more contributor license
* agreements. See the NOTICE file distributed with this work
* for additional information regarding copyright ownership.
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at the following location:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
/*
* Copyright 2007 The JA-SIG Collaborative. All rights reserved. See license
* distributed with this file and available online at
* http://www.ja-sig.org/products/cas/overview/license/index.html
*/
package org.jasig.cas.client.validation;
@ -28,11 +15,11 @@ package org.jasig.cas.client.validation;
public final class InvalidProxyChainTicketValidationException extends TicketValidationException {
/**
* Unique Id for Serialization
*/
private static final long serialVersionUID = -7736653266370691534L;
* Unique Id for Serialization
*/
private static final long serialVersionUID = -7736653266370691534L;
/**
/**
* Constructs an exception with the supplied message.
* @param string the supplied message.
*/

View File

@ -1,101 +0,0 @@
/**
* Licensed to Apereo under one or more contributor license
* agreements. See the NOTICE file distributed with this work
* for additional information regarding copyright ownership.
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at the following location:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jasig.cas.client.validation;
import java.util.ArrayList;
import java.util.List;
import org.jasig.cas.client.authentication.ExactUrlPatternMatcherStrategy;
import org.jasig.cas.client.authentication.RegexUrlPatternMatcherStrategy;
import org.jasig.cas.client.authentication.UrlPatternMatcherStrategy;
import org.jasig.cas.client.util.CommonUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Holding class for the proxy list to make Spring configuration easier.
*
* @author Scott Battaglia
* @version $Revision$ $Date$
* @since 3.1.3
*/
public final class ProxyList {
private final Logger logger = LoggerFactory.getLogger(getClass());
private final List<List<UrlPatternMatcherStrategy>> proxyChains;
public ProxyList(final List<String[]> proxyChains) {
CommonUtils.assertNotNull(proxyChains, "List of proxy chains cannot be null.");
this.proxyChains = new ArrayList<List<UrlPatternMatcherStrategy>>();
for (final String[] list : proxyChains) {
final List<UrlPatternMatcherStrategy> chain = new ArrayList<UrlPatternMatcherStrategy>();
for (final String item : list) {
if (item.startsWith("^")) {
chain.add(new RegexUrlPatternMatcherStrategy(item));
} else {
chain.add(new ExactUrlPatternMatcherStrategy(item));
}
}
this.proxyChains.add(chain);
}
}
public ProxyList() {
this(new ArrayList<String[]>());
}
public boolean contains(final String[] proxiedList) {
StringBuilder loggingOutput;
for (final List<UrlPatternMatcherStrategy> proxyChain : this.proxyChains) {
loggingOutput = new StringBuilder();
if (proxyChain.size() == proxiedList.length) {
for (int linkIndex = 0; linkIndex < proxyChain.size(); linkIndex++) {
final String linkToTest = proxiedList[linkIndex];
loggingOutput.append(linkToTest);
if (proxyChain.get(linkIndex).matches(linkToTest)) {
//If we are at the last link, we found a good proxyChain.
if (linkIndex == proxyChain.size() - 1) {
logger.info("Proxy chain matched: {}", loggingOutput.toString());
return true;
}
} else {
logger.warn("Proxy chain did not match at {}. Skipping to next allowedProxyChain", loggingOutput.toString());
break;
}
loggingOutput.append("->");
}
}
}
logger.warn("No proxy chain matched the allowedProxyChains list.");
return false;
}
public String toString() {
return this.proxyChains.toString();
}
}

View File

@ -1,63 +0,0 @@
/**
* Licensed to Apereo under one or more contributor license
* agreements. See the NOTICE file distributed with this work
* for additional information regarding copyright ownership.
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at the following location:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jasig.cas.client.validation;
import java.beans.PropertyEditorSupport;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.List;
import org.jasig.cas.client.util.CommonUtils;
/**
* Convert a String-formatted list of acceptable proxies to an array.
*
* @author Scott Battaglia
* @version $Revision$ $Date$
* @since 3.1
*
*/
public final class ProxyListEditor extends PropertyEditorSupport {
@Override
public void setAsText(final String text) throws IllegalArgumentException {
final BufferedReader reader = new BufferedReader(new StringReader(text));
final List<String[]> proxyChains = new ArrayList<String[]>();
try {
String line;
while ((line = reader.readLine()) != null) {
if (CommonUtils.isNotBlank(line)) {
proxyChains.add(line.trim().split(" "));
}
}
} catch (final IOException e) {
// ignore this
} finally {
try {
reader.close();
} catch (final IOException e) {
// nothing to do
}
}
setValue(new ProxyList(proxyChains));
}
}

View File

@ -0,0 +1,50 @@
/*
* Copyright 2007 The JA-SIG Collaborative. All rights reserved. See license
* distributed with this file and available online at
* http://www.ja-sig.org/products/cas/overview/license/index.html
*/
package org.jasig.cas.client.validation;
import java.beans.PropertyEditorSupport;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.List;
import org.jasig.cas.client.util.CommonUtils;
/**
* Convert a String-formatted list of acceptable proxies to an array.
*
* @author Scott Battaglia
* @version $Revision$ $Date$
* @since 3.1
*
*/
public final class ProxyListPropertyEditor extends PropertyEditorSupport {
public void setAsText(final String text) throws IllegalArgumentException {
final BufferedReader reader = new BufferedReader(new StringReader(text));
final List proxyChains = new ArrayList();
try {
String line;
while ((line = reader.readLine()) != null) {
if (CommonUtils.isNotBlank(line)) {
proxyChains.add(line.trim().split(" "));
}
}
} catch (final IOException e) {
// ignore this
} finally {
try {
reader.close();
} catch (final IOException e) {
// nothing to do
}
}
setValue(proxyChains);
}
}

View File

@ -0,0 +1,33 @@
/*
* Copyright 2007 The JA-SIG Collaborative. All rights reserved. See license
* distributed with this file and available online at
* http://www.ja-sig.org/products/cas/overview/license/index.html
*/
package org.jasig.cas.client.validation;
import javax.servlet.FilterConfig;
/**
* Implementation of TicketValidationFilter that can instanciate a SAML 1.1 Ticket Validator.
* <p>
* Deployers can provide the "casServerUrlPrefix" and "tolerance" properties of the Saml11TicketValidator via the
* context or filter init parameters.
*
* @author Scott Battaglia
* @version $Revision$ $Date$
* @since 3.1
*/
public class Saml11TicketValidationFilter extends AbstractTicketValidationFilter {
public Saml11TicketValidationFilter() {
setArtifactParameterName("SAMLart");
setServiceParameterName("TARGET");
}
protected final TicketValidator getTicketValidator(final FilterConfig filterConfig) {
final Saml11TicketValidator validator = new Saml11TicketValidator(getPropertyFromInitParams(filterConfig, "casServerUrlPrefix", null));
final String tolerance = getPropertyFromInitParams(filterConfig, "tolerance", "1000");
validator.setTolerance(Long.parseLong(tolerance));
return validator;
}
}

View File

@ -0,0 +1,204 @@
/*
* Copyright 2007 The JA-SIG Collaborative. All rights reserved. See license
* distributed with this file and available online at
* http://www.ja-sig.org/products/cas/overview/license/index.html
*/
package org.jasig.cas.client.validation;
import org.jasig.cas.client.authentication.AttributePrincipal;
import org.jasig.cas.client.authentication.AttributePrincipalImpl;
import org.opensaml.*;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.*;
/**
* TicketValidator that can understand validating a SAML artifact. This includes the SOAP request/response.
*
* @author Scott Battaglia
* @version $Revision$ $Date$
* @since 3.1
*/
public final class Saml11TicketValidator extends AbstractUrlBasedTicketValidator {
/** Time tolerance to allow for time drifting. */
private long tolerance = 1000L;
public Saml11TicketValidator(final String casServerUrlPrefix) {
super(casServerUrlPrefix);
}
protected String getUrlSuffix() {
return "samlValidate";
}
protected void populateUrlAttributeMap(final Map urlParameters) {
final String service = (String) urlParameters.get("service");
urlParameters.remove("service");
urlParameters.remove("ticket");
urlParameters.put("TARGET", service);
}
protected Assertion parseResponseFromServer(final String response) throws TicketValidationException {
try {
final SAMLResponse samlResponse = new SAMLResponse(new ByteArrayInputStream(response.getBytes()));
if (!samlResponse.getAssertions().hasNext()) {
throw new TicketValidationException("No assertions found.");
}
for (final Iterator iter = samlResponse.getAssertions(); iter.hasNext();) {
final SAMLAssertion assertion = (SAMLAssertion) iter.next();
if (!isValidAssertion(assertion)) {
continue;
}
final SAMLAuthenticationStatement authenticationStatement = getSAMLAuthenticationStatement(assertion);
if (authenticationStatement == null) {
throw new TicketValidationException("No AuthentiationStatement found in SAML Assertion.");
}
final SAMLSubject subject = authenticationStatement.getSubject();
if (subject == null) {
throw new TicketValidationException("No Subject found in SAML Assertion.");
}
final SAMLAttribute[] attributes = getAttributesFor(assertion, subject);
final Map personAttributes = new HashMap();
for (int i = 0; i < attributes.length; i++) {
final SAMLAttribute samlAttribute = attributes[i];
final List values = getValuesFrom(samlAttribute);
personAttributes.put(samlAttribute.getName(), values.size() == 1 ? values.get(0) : values);
}
final AttributePrincipal principal = new AttributePrincipalImpl(subject.getNameIdentifier().getName(), personAttributes);
final Map authenticationAttributes = new HashMap();
authenticationAttributes.put("samlAuthenticationStatement::authMethod", authenticationStatement.getAuthMethod());
final Assertion casAssertion = new AssertionImpl(principal, authenticationAttributes);
return casAssertion;
}
} catch (final SAMLException e) {
throw new TicketValidationException(e);
}
throw new TicketValidationException("No valid assertions from the SAML response found.");
}
private boolean isValidAssertion(final SAMLAssertion assertion) {
final Date notBefore = assertion.getNotBefore();
final Date notOnOrAfter = assertion.getNotOnOrAfter();
if (assertion.getNotBefore() == null || assertion.getNotOnOrAfter() == null) {
log.debug("Assertion has no bounding dates. Will not process.");
return false;
}
final long currentTime = new Date().getTime();
if (currentTime + tolerance < notBefore.getTime()) {
log.debug("skipping assertion that's not yet valid...");
return false;
}
if (notOnOrAfter.getTime() <= currentTime - tolerance) {
log.debug("skipping expired assertion...");
return false;
}
return true;
}
private SAMLAuthenticationStatement getSAMLAuthenticationStatement(final SAMLAssertion assertion) {
for (final Iterator iter = assertion.getStatements(); iter.hasNext();) {
final SAMLStatement statement = (SAMLStatement) iter.next();
if (statement instanceof SAMLAuthenticationStatement) {
return (SAMLAuthenticationStatement) statement;
}
}
return null;
}
private SAMLAttribute[] getAttributesFor(final SAMLAssertion assertion, final SAMLSubject subject) {
final List attributes = new ArrayList();
for (final Iterator iter = assertion.getStatements(); iter.hasNext();) {
final SAMLStatement statement = (SAMLStatement) iter.next();
if (statement instanceof SAMLAttributeStatement) {
final SAMLAttributeStatement attributeStatement = (SAMLAttributeStatement) statement;
// used because SAMLSubject does not implement equals
if (subject.getNameIdentifier().getName().equals(attributeStatement.getSubject().getNameIdentifier().getName())) {
for (final Iterator iter2 = attributeStatement.getAttributes(); iter2.hasNext();)
attributes.add(iter2.next());
}
}
}
return (SAMLAttribute[]) attributes.toArray(new SAMLAttribute[attributes.size()]);
}
private List getValuesFrom(final SAMLAttribute attribute) {
final List list = new ArrayList();
for (final Iterator iter = attribute.getValues(); iter.hasNext();) {
list.add(iter.next());
}
return list;
}
protected String retrieveResponseFromServer(final URL validationUrl, final String ticket) {
final String MESSAGE_TO_SEND = "<SOAP-ENV:Envelope xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\"><SOAP-ENV:Header/><SOAP-ENV:Body><samlp:Request xmlns:samlp=\"urn:oasis:names:tc:SAML:1.0:protocol\" MajorVersion=\"1\" MinorVersion=\"1\" RequestID=\"_192.168.16.51.1024506224022\" IssueInstant=\"2002-06-19T17:03:44.022Z\">"
+ "<samlp:AssertionArtifact>" + ticket
+ "</samlp:AssertionArtifact></samlp:Request></SOAP-ENV:Body></SOAP-ENV:Envelope>";
HttpURLConnection conn = null;
try {
conn = (HttpURLConnection) validationUrl.openConnection();
conn.setRequestMethod("POST");
conn.setRequestProperty("Content-Length", Integer.toString(MESSAGE_TO_SEND.length()));
conn.setRequestProperty("SOAPAction", "http://www.oasis-open.org/committees/security");
conn.setUseCaches(false);
conn.setDoInput(true);
conn.setDoOutput(true);
final DataOutputStream out = new DataOutputStream(conn.getOutputStream());
out.writeBytes(MESSAGE_TO_SEND);
out.flush();
out.close();
final BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
final StringBuffer buffer = new StringBuffer(256);
synchronized (buffer) {
String line;
while ((line = in.readLine()) != null) {
buffer.append(line);
}
return buffer.toString();
}
} catch (final IOException e) {
throw new RuntimeException(e);
} finally {
if (conn != null) {
conn.disconnect();
}
}
}
public void setTolerance(final long tolerance) {
this.tolerance = tolerance;
}
}

View File

@ -1,20 +1,7 @@
/**
* Licensed to Apereo under one or more contributor license
* agreements. See the NOTICE file distributed with this work
* for additional information regarding copyright ownership.
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at the following location:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
/*
* Copyright 2007 The JA-SIG Collaborative. All rights reserved. See license
* distributed with this file and available online at
* http://www.ja-sig.org/products/cas/overview/license/index.html
*/
package org.jasig.cas.client.validation;
@ -28,11 +15,11 @@ package org.jasig.cas.client.validation;
public class TicketValidationException extends Exception {
/**
* Unique Id for Serialization
*/
private static final long serialVersionUID = -7036248720402711806L;
* Unique Id for Serialization
*/
private static final long serialVersionUID = -7036248720402711806L;
/**
/**
* Constructs an exception with the supplied message.
*
* @param string the message

View File

@ -1,20 +1,7 @@
/**
* Licensed to Apereo under one or more contributor license
* agreements. See the NOTICE file distributed with this work
* for additional information regarding copyright ownership.
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at the following location:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
/*
* Copyright 2007 The JA-SIG Collaborative. All rights reserved. See license
* distributed with this file and available online at
* http://www.ja-sig.org/products/cas/overview/license/index.html
*/
package org.jasig.cas.client.validation;

View File

@ -1,35 +0,0 @@
/**
* Licensed to Apereo under one or more contributor license
* agreements. See the NOTICE file distributed with this work
* for additional information regarding copyright ownership.
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at the following location:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jasig.cas.client.validation.json;
import org.jasig.cas.client.validation.Cas30ProxyReceivingTicketValidationFilter;
/**
* Creates either a Cas30JsonServiceTicketValidator to validate tickets.
*
* @author Misagh Moayyed
*/
public class Cas30JsonProxyReceivingTicketValidationFilter extends Cas30ProxyReceivingTicketValidationFilter {
public Cas30JsonProxyReceivingTicketValidationFilter() {
super();
this.defaultServiceTicketValidatorClass = Cas30JsonServiceTicketValidator.class;
this.defaultProxyTicketValidatorClass = Cas30JsonProxyTicketValidator.class;
}
}

View File

@ -1,61 +0,0 @@
/**
* Licensed to Apereo under one or more contributor license
* agreements. See the NOTICE file distributed with this work
* for additional information regarding copyright ownership.
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at the following location:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jasig.cas.client.validation.json;
import org.jasig.cas.client.validation.Assertion;
import org.jasig.cas.client.validation.Cas30ProxyTicketValidator;
import org.jasig.cas.client.validation.TicketValidationException;
import java.util.Collections;
import java.util.List;
/**
* This is {@link Cas30JsonProxyTicketValidator} that attempts to parse the CAS validation response
* as JSON. Very similar to {@link Cas30JsonServiceTicketValidator}, it also honors proxies as the name suggests.
*
* @author Misagh Moayyed
*/
public class Cas30JsonProxyTicketValidator extends Cas30ProxyTicketValidator {
public Cas30JsonProxyTicketValidator(final String casServerUrlPrefix) {
super(casServerUrlPrefix);
setCustomParameters(Collections.singletonMap("format", "JSON"));
}
@Override
protected Assertion parseResponseFromServer(final String response) throws TicketValidationException {
try {
final TicketValidationJsonResponse json = new JsonValidationResponseParser().parse(response);
return json.getAssertion(getProxyGrantingTicketStorage(), getProxyRetriever());
} catch (final Exception e) {
logger.warn("Unable parse the JSON response");
return super.parseResponseFromServer(response);
}
}
@Override
protected List<String> parseProxiesFromResponse(final String response) {
try {
final TicketValidationJsonResponse json = new JsonValidationResponseParser().parse(response);
return json.getServiceResponse().getAuthenticationSuccess().getProxies();
} catch (final Exception e) {
logger.warn("Unable to locate proxies from the JSON response", e);
return super.parseProxiesFromResponse(response);
}
}
}

Some files were not shown because too many files have changed in this diff Show More