first blood
This commit is contained in:
commit
41db46a834
8
.gitignore
vendored
Normal file
8
.gitignore
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
.*
|
||||
!.gitignore
|
||||
!.gitkeep
|
||||
*.iml
|
||||
*/src/main/resources/application.properties
|
||||
*/src/main/resources/log4j2.xml
|
||||
target/
|
||||
bin/
|
92
INSTALL.txt
Normal file
92
INSTALL.txt
Normal file
@ -0,0 +1,92 @@
|
||||
JA-SIG Central Authentication Service
|
||||
Quick Installation Guide
|
||||
----------------------------------
|
||||
|
||||
This guide is meant to be a quickstart for you configure and install CAS
|
||||
as quickly and easily as possible. If you need more information,
|
||||
you can check the CAS website at
|
||||
|
||||
http://www.ja-sig.org/products/cas/
|
||||
|
||||
and you can subscribe to the CAS mailing list by visiting:
|
||||
|
||||
http://www.ja-sig.org/products/cas/community/lists/
|
||||
|
||||
Quick Demo
|
||||
----------
|
||||
|
||||
The following steps will deploy the included demo of CAS. Start here if
|
||||
you're new to CAS and want to see it in action. These steps assume
|
||||
you will be using Tomcat as your servlet container.
|
||||
|
||||
|
||||
Quick Demo
|
||||
----------
|
||||
|
||||
The following steps will deploy the included demo of CAS. Start here if
|
||||
you're new to CAS and want to see it in action. These steps assume
|
||||
you will be using Tomcat as your servlet container.
|
||||
|
||||
1. copy modules/cas-server-webapp-VERSION.war to Tomcat's webapps/ directory
|
||||
|
||||
2. start Tomcat
|
||||
|
||||
3. access the CAS login page by opening up a web browser and visiting:
|
||||
|
||||
http://hostname:8080/cas-server-webapp-VERSION/login (see note below)
|
||||
|
||||
You should see the CAS login page asking you for your username and
|
||||
password. The default authentication plugin accepts NetID=password.
|
||||
Enter in an identical value for NetID and password and click LOGIN.
|
||||
If everything is set up correctly, you should see a page stating that
|
||||
you've successfully logged into CAS. Congratulations!
|
||||
|
||||
Note: this URL assumes that port 8080 is not blocked by a firewall,
|
||||
and Tomcat is configured to listen on that port (it is by default).
|
||||
Since we are only testing CAS, this configuration uses http for transport
|
||||
rather than https -- this is not something you would do in production.
|
||||
|
||||
Customization
|
||||
-------------
|
||||
|
||||
After you've gotten CAS working, one of the first things you will want
|
||||
to do is create your own skin.
|
||||
|
||||
There is one skin included with CAS; Its called "default" If you look in cas-server-webapp/src/main/webapp/WEB-INF/view/jsp/default/ui,
|
||||
you will see that a skin is made up of the following files:
|
||||
|
||||
casConfirmView.jsp displayed when the user is warned before being
|
||||
redirected to the service
|
||||
casGenericSuccess.jsp displayed when the user has been logged in without
|
||||
providing a service to be redirected to
|
||||
casLoginView.jsp the login form itself
|
||||
casLogoutView.jsp displayed when the user has been logged out
|
||||
serviceErrorView.jsp used in conjunction with the service registry feature,
|
||||
displayed when the service the user is trying to
|
||||
access is not allowed to use CAS. Note that this
|
||||
feature is not enabled by default, in which case
|
||||
all services are able to use CAS.
|
||||
|
||||
Steps for creating a custom skin
|
||||
--------------------------------
|
||||
Edit each of the pages to appear as you want them. Take care when
|
||||
you're editing these pages not to change any of the forms or logic tags
|
||||
unless you're sure you know what you're doing. If you need to include
|
||||
a css file, put it in cas-server-webapp/src/main/webapp/themes/default/cas.css and reference it
|
||||
with the following link tag:
|
||||
|
||||
<link rel="stylesheet" href="<spring:theme code="css" />" type="text/css"
|
||||
media="all" />
|
||||
|
||||
The "<spring:theme code="css" />" will be replaced with the appropriate
|
||||
URL to that directory.
|
||||
|
||||
Documentation
|
||||
---------------------------------
|
||||
Documentation for CAS can be found in the CAS User Manual:
|
||||
http://www.ja-sig.org/wiki/display/CASUM/Home
|
||||
|
||||
--------------------------
|
||||
Author: Drew Mazurek
|
||||
Version: $Revision$ $Date$
|
||||
Since: 3.0
|
11
README.md
Normal file
11
README.md
Normal file
@ -0,0 +1,11 @@
|
||||
cas-server-3.5.2
|
||||
================
|
||||
|
||||
对于JasigCAS 3.5.2版本进行简化,只保留基本的功能,用JDBC方式验证,并使用Metronic模板美化界面,以达到可以直接在项目中使用的目的。
|
||||
|
||||
关于代码改动内容,很早之前写过一篇文章,如下;
|
||||
http://blog.csdn.net/puma_dong/article/details/11564309
|
||||
|
||||
cas的java客户端也进行了小调整,让登陆之后自动返回到登陆之前的页面,不再使用p:service定义的值,并有一个客户端配置单点登陆的例子,如下:
|
||||
|
||||
https://github.com/pumadong/cas-client-3.2.1
|
139
assembly.xml
Normal file
139
assembly.xml
Normal file
@ -0,0 +1,139 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
|
||||
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.
|
||||
|
||||
-->
|
||||
<assembly
|
||||
xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">
|
||||
<id>release</id>
|
||||
<formats>
|
||||
<format>zip</format>
|
||||
<format>tar.gz</format>
|
||||
</formats>
|
||||
<includeBaseDirectory>true</includeBaseDirectory>
|
||||
<fileSets>
|
||||
<fileSet>
|
||||
<lineEnding>unix</lineEnding>
|
||||
<useDefaultExcludes>true</useDefaultExcludes>
|
||||
<directory>${basedir}</directory>
|
||||
<outputDirectory></outputDirectory>
|
||||
<includes>
|
||||
<include>*.xml</include>
|
||||
<include>*.txt</include>
|
||||
</includes>
|
||||
</fileSet>
|
||||
</fileSets>
|
||||
<moduleSets>
|
||||
<moduleSet>
|
||||
<includes></includes>
|
||||
<excludes>
|
||||
<exclude>cas-server-webapp</exclude>
|
||||
</excludes>
|
||||
<sources>
|
||||
<fileSets>
|
||||
<fileSet>
|
||||
<directory>src</directory>
|
||||
<outputDirectory>src</outputDirectory>
|
||||
<lineEnding>unix</lineEnding>
|
||||
<useDefaultExcludes>true</useDefaultExcludes>
|
||||
<includes>
|
||||
<include>**/*.java</include>
|
||||
<include>**/*.xml</include>
|
||||
<include>**/*.properties</include>
|
||||
<include>**/*.jsp</include>
|
||||
<include>**/*.css</include>
|
||||
<include>**/*.jsp</include>
|
||||
<include>**/*.html</include>
|
||||
<include>**/*.txt</include>
|
||||
<include>**/*.js</include>
|
||||
<include>**/*.conf</include>
|
||||
<include>**/*.crt</include>
|
||||
<include>**/*.crl</include>
|
||||
</includes>
|
||||
</fileSet>
|
||||
|
||||
<fileSet>
|
||||
<directory>src</directory>
|
||||
<outputDirectory>src</outputDirectory>
|
||||
<includes>
|
||||
<include>**/*.gif</include>
|
||||
<include>**/*.ico</include>
|
||||
<include>**/*.key</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>
|
||||
|
||||
<includeModuleDirectory>true</includeModuleDirectory>
|
||||
<useDefaultExcludes>true</useDefaultExcludes>
|
||||
</sources>
|
||||
<binaries>
|
||||
<outputDirectory>modules</outputDirectory>
|
||||
<includeDependencies>false</includeDependencies>
|
||||
<unpack>false</unpack>
|
||||
<includes />
|
||||
</binaries>
|
||||
</moduleSet>
|
||||
|
||||
<moduleSet>
|
||||
<includes>
|
||||
<include>cas-server-webapp</include>
|
||||
</includes>
|
||||
<sources>
|
||||
<fileSets>
|
||||
<fileSet>
|
||||
<lineEnding>unix</lineEnding>
|
||||
<useDefaultExcludes>true</useDefaultExcludes>
|
||||
<includes>
|
||||
<include>*.xml</include>
|
||||
</includes>
|
||||
</fileSet>
|
||||
</fileSets>
|
||||
<includeModuleDirectory>true</includeModuleDirectory>
|
||||
<useDefaultExcludes>true</useDefaultExcludes>
|
||||
</sources>
|
||||
<binaries>
|
||||
<outputDirectory>modules</outputDirectory>
|
||||
<includeDependencies>false</includeDependencies>
|
||||
<unpack>false</unpack>
|
||||
<outputFileNameMapping>cas.war</outputFileNameMapping>
|
||||
<includes />
|
||||
</binaries>
|
||||
</moduleSet>
|
||||
</moduleSets>
|
||||
</assembly>
|
255
cas-server-core/pom.xml
Normal file
255
cas-server-core/pom.xml
Normal file
@ -0,0 +1,255 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
~ 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.
|
||||
-->
|
||||
|
||||
<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>
|
||||
<artifactId>cas-server</artifactId>
|
||||
<groupId>org.jasig.cas</groupId>
|
||||
<version>3.5.2-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.jasig.cas</groupId>
|
||||
<artifactId>cas-server-core</artifactId>
|
||||
<name>Jasig CAS Core</name>
|
||||
<description>CAS core</description>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>log4j</groupId>
|
||||
<artifactId>log4j</artifactId>
|
||||
<version>${log4j.version}</version>
|
||||
<type>jar</type>
|
||||
<scope>compile</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>javax.mail</groupId>
|
||||
<artifactId>mail</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>javax.jms</groupId>
|
||||
<artifactId>jms</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>com.sun.jdmk</groupId>
|
||||
<artifactId>jmxtools</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>com.sun.jmx</groupId>
|
||||
<artifactId>jmxri</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.github.inspektr</groupId>
|
||||
<artifactId>inspektr-audit</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.jasig.service.persondir</groupId>
|
||||
<artifactId>person-directory-impl</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>commons-codec</groupId>
|
||||
<artifactId>commons-codec</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>jdom</groupId>
|
||||
<artifactId>jdom</artifactId>
|
||||
<version>1.0</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-orm</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-jdbc</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-core</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-beans</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-webmvc</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-context-support</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-tx</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-context</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-core</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.hsqldb</groupId>
|
||||
<artifactId>hsqldb</artifactId>
|
||||
<version>2.0.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.hibernate</groupId>
|
||||
<artifactId>hibernate-validator</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.hibernate</groupId>
|
||||
<artifactId>hibernate-core</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.hibernate</groupId>
|
||||
<artifactId>hibernate-entitymanager</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>javassist</groupId>
|
||||
<artifactId>javassist</artifactId>
|
||||
<scope>test</scope>
|
||||
<version>3.12.1.GA</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.santuario</groupId>
|
||||
<artifactId>xmlsec</artifactId>
|
||||
<version>1.4.3</version>
|
||||
<scope>runtime</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>commons-logging</groupId>
|
||||
<artifactId>commons-logging</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.opensaml</groupId>
|
||||
<artifactId>opensaml</artifactId>
|
||||
<version>2.5.1-1</version>
|
||||
<scope>compile</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>log4j-over-slf4j</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>joda-time</groupId>
|
||||
<artifactId>joda-time</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>javax.xml</groupId>
|
||||
<artifactId>xmldsig</artifactId>
|
||||
<version>1.0</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.perf4j</groupId>
|
||||
<artifactId>perf4j</artifactId>
|
||||
<version>${perf4j.version}</version>
|
||||
<classifier>log4jonly</classifier>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.webflow</groupId>
|
||||
<artifactId>spring-webflow</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>commons-jexl</groupId>
|
||||
<artifactId>commons-jexl</artifactId>
|
||||
<scope>runtime</scope>
|
||||
<type>jar</type>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>commons-io</groupId>
|
||||
<artifactId>commons-io</artifactId>
|
||||
<version>${commons.io.version}</version>
|
||||
<scope>compile</scope>
|
||||
<type>jar</type>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>joda-time</groupId>
|
||||
<artifactId>joda-time</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.opensymphony.quartz</groupId>
|
||||
<artifactId>quartz</artifactId>
|
||||
<version>1.6.1</version>
|
||||
<scope>test</scope>
|
||||
<type>jar</type>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.github.inspektr</groupId>
|
||||
<artifactId>inspektr-support-spring</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
48
cas-server-core/src/main/java/org/jasig/cas/CasVersion.java
Normal file
48
cas-server-core/src/main/java/org/jasig/cas/CasVersion.java
Normal file
@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Licensed to Jasig under one or more contributor license
|
||||
* agreements. See the NOTICE file distributed with this work
|
||||
* for additional information regarding copyright ownership.
|
||||
* Jasig licenses this file to you under the Apache License,
|
||||
* Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a
|
||||
* copy of the License at the following location:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
package org.jasig.cas;
|
||||
|
||||
/**
|
||||
* Class that exposes the CAS version. Fetches the "Implementation-Version"
|
||||
* manifest attribute from the jar file.
|
||||
*
|
||||
* @author Dmitriy Kopylenko
|
||||
* @version $Revision$ $Date$
|
||||
* @since 3.0
|
||||
*/
|
||||
public final class CasVersion {
|
||||
|
||||
/**
|
||||
* Private constructor for CasVersion. You should not be able to instanciate
|
||||
* this class.
|
||||
*/
|
||||
private CasVersion() {
|
||||
// this class is not instantiable
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the full CAS version string.
|
||||
*
|
||||
* @see java.lang.Package#getImplementationVersion
|
||||
*/
|
||||
public static String getVersion() {
|
||||
return CasVersion.class.getPackage().getImplementationVersion();
|
||||
}
|
||||
}
|
@ -0,0 +1,120 @@
|
||||
/*
|
||||
* Licensed to Jasig under one or more contributor license
|
||||
* agreements. See the NOTICE file distributed with this work
|
||||
* for additional information regarding copyright ownership.
|
||||
* Jasig licenses this file to you under the Apache License,
|
||||
* Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a
|
||||
* copy of the License at the following location:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.jasig.cas;
|
||||
|
||||
import org.jasig.cas.authentication.principal.Credentials;
|
||||
import org.jasig.cas.authentication.principal.Service;
|
||||
import org.jasig.cas.ticket.TicketException;
|
||||
import org.jasig.cas.validation.Assertion;
|
||||
|
||||
/**
|
||||
* CAS viewed as a set of services to generate and validate Tickets.
|
||||
* <p>
|
||||
* This is the interface between a Web HTML, Web Services, RMI, or any other
|
||||
* request processing layer and the CAS Service viewed as a mechanism to
|
||||
* generate, store, validate, and retrieve Tickets containing Authentication
|
||||
* information. The features of the request processing layer (the HttpXXX
|
||||
* Servlet objects) are not visible here or in any modules behind this layer. In
|
||||
* theory, a standalone application could call these methods directly as a
|
||||
* private authentication service.
|
||||
* </p>
|
||||
*
|
||||
* @author William G. Thompson, Jr.
|
||||
* @author Dmitry Kopylenko
|
||||
* @author Scott Battaglia
|
||||
* @version $Revision$ $Date$
|
||||
* @since 3.0
|
||||
* <p>
|
||||
* This is a published and supported CAS Server 3 API.
|
||||
* </p>
|
||||
*/
|
||||
public interface CentralAuthenticationService {
|
||||
|
||||
/**
|
||||
* Create a TicketGrantingTicket based on opaque credentials supplied by the
|
||||
* caller.
|
||||
*
|
||||
* @param credentials The credentials to create the ticket for
|
||||
* @return The String identifier of the ticket (may not be null).
|
||||
* @throws TicketException if ticket cannot be created
|
||||
*/
|
||||
String createTicketGrantingTicket(Credentials credentials)
|
||||
throws TicketException;
|
||||
|
||||
/**
|
||||
* Grant a ServiceTicket for a Service.
|
||||
*
|
||||
* @param ticketGrantingTicketId Proof of prior authentication.
|
||||
* @param service The target service of the ServiceTicket.
|
||||
* @return the ServiceTicket for target Service.
|
||||
* @throws TicketException if the ticket could not be created.
|
||||
*/
|
||||
String grantServiceTicket(String ticketGrantingTicketId, Service service)
|
||||
throws TicketException;
|
||||
|
||||
/**
|
||||
* Grant a ServiceTicket for a Service *if* the principal resolved from the
|
||||
* credentials matches the principal associated with the
|
||||
* TicketGrantingTicket.
|
||||
*
|
||||
* @param ticketGrantingTicketId Proof of prior authentication.
|
||||
* @param service The target service of the ServiceTicket.
|
||||
* @param credentials the Credentials to present to receive the
|
||||
* ServiceTicket
|
||||
* @return the ServiceTicket for target Service.
|
||||
* @throws TicketException if the ticket could not be created.
|
||||
*/
|
||||
String grantServiceTicket(final String ticketGrantingTicketId,
|
||||
final Service service, final Credentials credentials)
|
||||
throws TicketException;
|
||||
|
||||
/**
|
||||
* Validate a ServiceTicket for a particular Service.
|
||||
*
|
||||
* @param serviceTicketId Proof of prior authentication.
|
||||
* @param service Service wishing to validate a prior authentication.
|
||||
* @return ServiceTicket if valid for the service
|
||||
* @throws TicketException if there was an error validating the ticket.
|
||||
*/
|
||||
Assertion validateServiceTicket(final String serviceTicketId,
|
||||
final Service service) throws TicketException;
|
||||
|
||||
/**
|
||||
* Destroy a TicketGrantingTicket. This has the effect of invalidating any
|
||||
* Ticket that was derived from the TicketGrantingTicket being destroyed.
|
||||
*
|
||||
* @param ticketGrantingTicketId the id of the ticket we want to destroy
|
||||
*/
|
||||
void destroyTicketGrantingTicket(final String ticketGrantingTicketId);
|
||||
|
||||
/**
|
||||
* Delegate a TicketGrantingTicket to a Service for proxying authentication
|
||||
* to other Services.
|
||||
*
|
||||
* @param serviceTicketId The service ticket that will delegate to a
|
||||
* TicketGrantingTicket
|
||||
* @param credentials The credentials of the service that wishes to have a
|
||||
* TicketGrantingTicket delegated to it.
|
||||
* @return TicketGrantingTicket that can grant ServiceTickets that proxy
|
||||
* authentication.
|
||||
* @throws TicketException if there was an error creating the ticket
|
||||
*/
|
||||
String delegateTicketGrantingTicket(final String serviceTicketId,
|
||||
final Credentials credentials) throws TicketException;
|
||||
}
|
@ -0,0 +1,563 @@
|
||||
/*
|
||||
* Licensed to Jasig under one or more contributor license
|
||||
* agreements. See the NOTICE file distributed with this work
|
||||
* for additional information regarding copyright ownership.
|
||||
* Jasig licenses this file to you under the Apache License,
|
||||
* Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a
|
||||
* copy of the License at the following location:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.jasig.cas;
|
||||
|
||||
import com.github.inspektr.audit.annotation.Audit;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.jasig.cas.authentication.Authentication;
|
||||
import org.jasig.cas.authentication.AuthenticationManager;
|
||||
import org.jasig.cas.authentication.MutableAuthentication;
|
||||
import org.jasig.cas.authentication.handler.AuthenticationException;
|
||||
import org.jasig.cas.authentication.principal.Credentials;
|
||||
import org.jasig.cas.authentication.principal.PersistentIdGenerator;
|
||||
import org.jasig.cas.authentication.principal.Principal;
|
||||
import org.jasig.cas.authentication.principal.Service;
|
||||
import org.jasig.cas.authentication.principal.ShibbolethCompatiblePersistentIdGenerator;
|
||||
import org.jasig.cas.authentication.principal.SimplePrincipal;
|
||||
import org.jasig.cas.services.RegisteredService;
|
||||
import org.jasig.cas.services.ServicesManager;
|
||||
import org.jasig.cas.services.UnauthorizedProxyingException;
|
||||
import org.jasig.cas.services.UnauthorizedServiceException;
|
||||
import org.jasig.cas.services.UnauthorizedSsoServiceException;
|
||||
import org.jasig.cas.ticket.ExpirationPolicy;
|
||||
import org.jasig.cas.ticket.InvalidTicketException;
|
||||
import org.jasig.cas.ticket.ServiceTicket;
|
||||
import org.jasig.cas.ticket.TicketCreationException;
|
||||
import org.jasig.cas.ticket.TicketException;
|
||||
import org.jasig.cas.ticket.TicketGrantingTicket;
|
||||
import org.jasig.cas.ticket.TicketGrantingTicketImpl;
|
||||
import org.jasig.cas.ticket.TicketValidationException;
|
||||
import org.jasig.cas.ticket.registry.TicketRegistry;
|
||||
import org.jasig.cas.util.UniqueTicketIdGenerator;
|
||||
import org.jasig.cas.validation.Assertion;
|
||||
import org.jasig.cas.validation.ImmutableAssertionImpl;
|
||||
import org.perf4j.aop.Profiled;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Concrete implementation of a CentralAuthenticationService, and also the
|
||||
* central, organizing component of CAS's internal implementation.
|
||||
* <p>
|
||||
* This class is threadsafe.
|
||||
* <p>
|
||||
* This class has the following properties that must be set:
|
||||
* <ul>
|
||||
* <li> <code>ticketRegistry</code> - The Ticket Registry to maintain the list
|
||||
* of available tickets.</li>
|
||||
* <li> <code>serviceTicketRegistry</code> - Provides an alternative to configure separate registries for TGTs and ST in order to store them
|
||||
* in different locations (i.e. long term memory or short-term)</li>
|
||||
* <li> <code>authenticationManager</code> - The service that will handle
|
||||
* authentication.</li>
|
||||
* <li> <code>ticketGrantingTicketUniqueTicketIdGenerator</code> - Plug in to
|
||||
* generate unique secure ids for TicketGrantingTickets.</li>
|
||||
* <li> <code>serviceTicketUniqueTicketIdGenerator</code> - Plug in to
|
||||
* generate unique secure ids for ServiceTickets.</li>
|
||||
* <li> <code>ticketGrantingTicketExpirationPolicy</code> - The expiration
|
||||
* policy for TicketGrantingTickets.</li>
|
||||
* <li> <code>serviceTicketExpirationPolicy</code> - The expiration policy for
|
||||
* ServiceTickets.</li>
|
||||
* </ul>
|
||||
*
|
||||
* @author William G. Thompson, Jr.
|
||||
* @author Scott Battaglia
|
||||
* @author Dmitry Kopylenko
|
||||
* @version $Revision: 1.16 $ $Date: 2007/04/24 18:11:36 $
|
||||
* @since 3.0
|
||||
*/
|
||||
public final class CentralAuthenticationServiceImpl implements CentralAuthenticationService {
|
||||
|
||||
/** Log instance for logging events, info, warnings, errors, etc. */
|
||||
private final Logger log = LoggerFactory.getLogger(this.getClass());
|
||||
|
||||
/** TicketRegistry for storing and retrieving tickets as needed. */
|
||||
@NotNull
|
||||
private TicketRegistry ticketRegistry;
|
||||
|
||||
/** New Ticket Registry for storing and retrieving services tickets. Can point to the same one as the ticketRegistry variable. */
|
||||
@NotNull
|
||||
private TicketRegistry serviceTicketRegistry;
|
||||
|
||||
/**
|
||||
* AuthenticationManager for authenticating credentials for purposes of
|
||||
* obtaining tickets.
|
||||
*/
|
||||
@NotNull
|
||||
private AuthenticationManager authenticationManager;
|
||||
|
||||
/**
|
||||
* UniqueTicketIdGenerator to generate ids for TicketGrantingTickets
|
||||
* created.
|
||||
*/
|
||||
@NotNull
|
||||
private UniqueTicketIdGenerator ticketGrantingTicketUniqueTicketIdGenerator;
|
||||
|
||||
/** Map to contain the mappings of service->UniqueTicketIdGenerators */
|
||||
@NotNull
|
||||
private Map<String, UniqueTicketIdGenerator> uniqueTicketIdGeneratorsForService;
|
||||
|
||||
/** Expiration policy for ticket granting tickets. */
|
||||
@NotNull
|
||||
private ExpirationPolicy ticketGrantingTicketExpirationPolicy;
|
||||
|
||||
/** ExpirationPolicy for Service Tickets. */
|
||||
@NotNull
|
||||
private ExpirationPolicy serviceTicketExpirationPolicy;
|
||||
|
||||
/** Implementation of Service Manager */
|
||||
@NotNull
|
||||
private ServicesManager servicesManager;
|
||||
|
||||
/** Encoder to generate PseudoIds. */
|
||||
@NotNull
|
||||
private PersistentIdGenerator persistentIdGenerator = new ShibbolethCompatiblePersistentIdGenerator();
|
||||
|
||||
/**
|
||||
* Implementation of destoryTicketGrantingTicket expires the ticket provided
|
||||
* and removes it from the TicketRegistry.
|
||||
*
|
||||
* @throws IllegalArgumentException if the TicketGrantingTicket ID is null.
|
||||
*/
|
||||
@Audit(
|
||||
action="TICKET_GRANTING_TICKET_DESTROYED",
|
||||
actionResolverName="DESTROY_TICKET_GRANTING_TICKET_RESOLVER",
|
||||
resourceResolverName="DESTROY_TICKET_GRANTING_TICKET_RESOURCE_RESOLVER")
|
||||
@Profiled(tag = "DESTROY_TICKET_GRANTING_TICKET",logFailuresSeparately = false)
|
||||
@Transactional(readOnly = false)
|
||||
public void destroyTicketGrantingTicket(final String ticketGrantingTicketId) {
|
||||
Assert.notNull(ticketGrantingTicketId);
|
||||
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Removing ticket [" + ticketGrantingTicketId + "] from registry.");
|
||||
}
|
||||
final TicketGrantingTicket ticket = (TicketGrantingTicket) this.ticketRegistry.getTicket(ticketGrantingTicketId, TicketGrantingTicket.class);
|
||||
|
||||
if (ticket == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Ticket found. Expiring and then deleting.");
|
||||
}
|
||||
ticket.expire();
|
||||
this.ticketRegistry.deleteTicket(ticketGrantingTicketId);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws IllegalArgumentException if TicketGrantingTicket ID, Credentials
|
||||
* or Service are null.
|
||||
*/
|
||||
@Audit(
|
||||
action="SERVICE_TICKET",
|
||||
actionResolverName="GRANT_SERVICE_TICKET_RESOLVER",
|
||||
resourceResolverName="GRANT_SERVICE_TICKET_RESOURCE_RESOLVER")
|
||||
@Profiled(tag="GRANT_SERVICE_TICKET", logFailuresSeparately = false)
|
||||
@Transactional(readOnly = false)
|
||||
public String grantServiceTicket(final String ticketGrantingTicketId, final Service service, final Credentials credentials) throws TicketException {
|
||||
|
||||
Assert.notNull(ticketGrantingTicketId, "ticketGrantingticketId cannot be null");
|
||||
Assert.notNull(service, "service cannot be null");
|
||||
|
||||
final TicketGrantingTicket ticketGrantingTicket;
|
||||
ticketGrantingTicket = (TicketGrantingTicket) this.ticketRegistry.getTicket(ticketGrantingTicketId, TicketGrantingTicket.class);
|
||||
|
||||
if (ticketGrantingTicket == null) {
|
||||
throw new InvalidTicketException();
|
||||
}
|
||||
|
||||
synchronized (ticketGrantingTicket) {
|
||||
if (ticketGrantingTicket.isExpired()) {
|
||||
this.ticketRegistry.deleteTicket(ticketGrantingTicketId);
|
||||
throw new InvalidTicketException();
|
||||
}
|
||||
}
|
||||
|
||||
final RegisteredService registeredService = this.servicesManager
|
||||
.findServiceBy(service);
|
||||
|
||||
if (registeredService == null || !registeredService.isEnabled()) {
|
||||
log.warn("ServiceManagement: Unauthorized Service Access. Service [" + service.getId() + "] not found in Service Registry.");
|
||||
throw new UnauthorizedServiceException();
|
||||
}
|
||||
|
||||
if (!registeredService.isSsoEnabled() && credentials == null
|
||||
&& ticketGrantingTicket.getCountOfUses() > 0) {
|
||||
log.warn("ServiceManagement: Service Not Allowed to use SSO. Service [" + service.getId() + "]");
|
||||
throw new UnauthorizedSsoServiceException();
|
||||
}
|
||||
|
||||
//CAS-1019
|
||||
final List<Authentication> authns = ticketGrantingTicket.getChainedAuthentications();
|
||||
if(authns.size() > 1) {
|
||||
if (!registeredService.isAllowedToProxy()) {
|
||||
final String message = String.format("ServiceManagement: Service Attempted to Proxy, but is not allowed. Service: [%s] | Registered Service: [%s]", service.getId(), registeredService.toString());
|
||||
log.warn(message);
|
||||
throw new UnauthorizedProxyingException(message);
|
||||
}
|
||||
}
|
||||
|
||||
if (credentials != null) {
|
||||
try {
|
||||
final Authentication authentication = this.authenticationManager
|
||||
.authenticate(credentials);
|
||||
final Authentication originalAuthentication = ticketGrantingTicket.getAuthentication();
|
||||
|
||||
if (!(authentication.getPrincipal().equals(originalAuthentication.getPrincipal()) && authentication.getAttributes().equals(originalAuthentication.getAttributes()))) {
|
||||
throw new TicketCreationException();
|
||||
}
|
||||
} catch (final AuthenticationException e) {
|
||||
throw new TicketCreationException(e);
|
||||
}
|
||||
}
|
||||
|
||||
// this code is a bit brittle by depending on the class name. Future versions (i.e. CAS4 will know inherently how to identify themselves)
|
||||
final UniqueTicketIdGenerator serviceTicketUniqueTicketIdGenerator = this.uniqueTicketIdGeneratorsForService
|
||||
.get(service.getClass().getName());
|
||||
|
||||
final ServiceTicket serviceTicket = ticketGrantingTicket
|
||||
.grantServiceTicket(serviceTicketUniqueTicketIdGenerator
|
||||
.getNewTicketId(ServiceTicket.PREFIX), service,
|
||||
this.serviceTicketExpirationPolicy, credentials != null);
|
||||
|
||||
this.serviceTicketRegistry.addTicket(serviceTicket);
|
||||
|
||||
if (log.isInfoEnabled()) {
|
||||
final List<Authentication> authentications = serviceTicket.getGrantingTicket().getChainedAuthentications();
|
||||
final String formatString = "Granted %s ticket [%s] for service [%s] for user [%s]";
|
||||
final String type;
|
||||
final String principalId = authentications.get(authentications.size()-1).getPrincipal().getId();
|
||||
|
||||
if (authentications.size() == 1) {
|
||||
type = "service";
|
||||
|
||||
} else {
|
||||
type = "proxy";
|
||||
}
|
||||
|
||||
log.info(String.format(formatString, type, serviceTicket.getId(), service.getId(), principalId));
|
||||
}
|
||||
|
||||
return serviceTicket.getId();
|
||||
}
|
||||
|
||||
@Audit(
|
||||
action="SERVICE_TICKET",
|
||||
actionResolverName="GRANT_SERVICE_TICKET_RESOLVER",
|
||||
resourceResolverName="GRANT_SERVICE_TICKET_RESOURCE_RESOLVER")
|
||||
@Profiled(tag = "GRANT_SERVICE_TICKET",logFailuresSeparately = false)
|
||||
@Transactional(readOnly = false)
|
||||
public String grantServiceTicket(final String ticketGrantingTicketId,
|
||||
final Service service) throws TicketException {
|
||||
return this.grantServiceTicket(ticketGrantingTicketId, service, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws IllegalArgumentException if the ServiceTicketId or the
|
||||
* Credentials are null.
|
||||
*/
|
||||
@Audit(
|
||||
action="PROXY_GRANTING_TICKET",
|
||||
actionResolverName="GRANT_PROXY_GRANTING_TICKET_RESOLVER",
|
||||
resourceResolverName="GRANT_PROXY_GRANTING_TICKET_RESOURCE_RESOLVER")
|
||||
@Profiled(tag="GRANT_PROXY_GRANTING_TICKET",logFailuresSeparately = false)
|
||||
@Transactional(readOnly = false)
|
||||
public String delegateTicketGrantingTicket(final String serviceTicketId,
|
||||
final Credentials credentials) throws TicketException {
|
||||
|
||||
Assert.notNull(serviceTicketId, "serviceTicketId cannot be null");
|
||||
Assert.notNull(credentials, "credentials cannot be null");
|
||||
|
||||
try {
|
||||
final Authentication authentication = this.authenticationManager
|
||||
.authenticate(credentials);
|
||||
|
||||
final ServiceTicket serviceTicket;
|
||||
serviceTicket = (ServiceTicket) this.serviceTicketRegistry.getTicket(serviceTicketId, ServiceTicket.class);
|
||||
|
||||
if (serviceTicket == null || serviceTicket.isExpired()) {
|
||||
throw new InvalidTicketException();
|
||||
}
|
||||
|
||||
final RegisteredService registeredService = this.servicesManager
|
||||
.findServiceBy(serviceTicket.getService());
|
||||
|
||||
if (registeredService == null || !registeredService.isEnabled()
|
||||
|| !registeredService.isAllowedToProxy()) {
|
||||
log.warn("ServiceManagement: Service Attempted to Proxy, but is not allowed. Service: [" + serviceTicket.getService().getId() + "]");
|
||||
throw new UnauthorizedProxyingException();
|
||||
}
|
||||
|
||||
final TicketGrantingTicket ticketGrantingTicket = serviceTicket
|
||||
.grantTicketGrantingTicket(
|
||||
this.ticketGrantingTicketUniqueTicketIdGenerator
|
||||
.getNewTicketId(TicketGrantingTicket.PREFIX),
|
||||
authentication, this.ticketGrantingTicketExpirationPolicy);
|
||||
|
||||
this.ticketRegistry.addTicket(ticketGrantingTicket);
|
||||
|
||||
return ticketGrantingTicket.getId();
|
||||
} catch (final AuthenticationException e) {
|
||||
throw new TicketCreationException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws IllegalArgumentException if the ServiceTicketId or the Service
|
||||
* are null.
|
||||
*/
|
||||
@Audit(
|
||||
action="SERVICE_TICKET_VALIDATE",
|
||||
actionResolverName="VALIDATE_SERVICE_TICKET_RESOLVER",
|
||||
resourceResolverName="VALIDATE_SERVICE_TICKET_RESOURCE_RESOLVER")
|
||||
@Profiled(tag="VALIDATE_SERVICE_TICKET",logFailuresSeparately = false)
|
||||
@Transactional(readOnly = false)
|
||||
public Assertion validateServiceTicket(final String serviceTicketId, final Service service) throws TicketException {
|
||||
Assert.notNull(serviceTicketId, "serviceTicketId cannot be null");
|
||||
Assert.notNull(service, "service cannot be null");
|
||||
|
||||
final ServiceTicket serviceTicket = (ServiceTicket) this.serviceTicketRegistry.getTicket(serviceTicketId, ServiceTicket.class);
|
||||
|
||||
final RegisteredService registeredService = this.servicesManager.findServiceBy(service);
|
||||
|
||||
if (registeredService == null || !registeredService.isEnabled()) {
|
||||
log.warn("ServiceManagement: Service does not exist is not enabled, and thus not allowed to validate tickets. Service: [" + service.getId() + "]");
|
||||
throw new UnauthorizedServiceException("Service not allowed to validate tickets.");
|
||||
}
|
||||
|
||||
if (serviceTicket == null) {
|
||||
log.info("ServiceTicket [" + serviceTicketId + "] does not exist.");
|
||||
throw new InvalidTicketException();
|
||||
}
|
||||
|
||||
try {
|
||||
synchronized (serviceTicket) {
|
||||
if (serviceTicket.isExpired()) {
|
||||
log.info("ServiceTicket [" + serviceTicketId + "] has expired.");
|
||||
throw new InvalidTicketException();
|
||||
}
|
||||
|
||||
if (!serviceTicket.isValidFor(service)) {
|
||||
log.error("ServiceTicket [" + serviceTicketId + "] with service [" + serviceTicket.getService().getId() + " does not match supplied service [" + service + "]");
|
||||
throw new TicketValidationException(serviceTicket.getService());
|
||||
}
|
||||
}
|
||||
|
||||
final List<Authentication> chainedAuthenticationsList = serviceTicket.getGrantingTicket().getChainedAuthentications();
|
||||
final Authentication authentication = chainedAuthenticationsList.get(chainedAuthenticationsList.size() - 1);
|
||||
final Principal principal = authentication.getPrincipal();
|
||||
|
||||
final String principalId = determinePrincipalIdForRegisteredService(principal, registeredService, serviceTicket);
|
||||
final Authentication authToUse;
|
||||
|
||||
if (!registeredService.isIgnoreAttributes()) {
|
||||
final Map<String, Object> attributes = new HashMap<String, Object>();
|
||||
|
||||
for (final String attribute : registeredService.getAllowedAttributes()) {
|
||||
final Object value = principal.getAttributes().get(attribute);
|
||||
|
||||
if (value != null) {
|
||||
attributes.put(attribute, value);
|
||||
}
|
||||
}
|
||||
|
||||
final Principal modifiedPrincipal = new SimplePrincipal(principalId, attributes);
|
||||
final MutableAuthentication mutableAuthentication = new MutableAuthentication(
|
||||
modifiedPrincipal, authentication.getAuthenticatedDate());
|
||||
mutableAuthentication.getAttributes().putAll(
|
||||
authentication.getAttributes());
|
||||
mutableAuthentication.getAuthenticatedDate().setTime(
|
||||
authentication.getAuthenticatedDate().getTime());
|
||||
authToUse = mutableAuthentication;
|
||||
} else {
|
||||
final Principal modifiedPrincipal = new SimplePrincipal(principalId, principal.getAttributes());
|
||||
authToUse = new MutableAuthentication(modifiedPrincipal, authentication.getAuthenticatedDate());
|
||||
}
|
||||
|
||||
final List<Authentication> authentications = new ArrayList<Authentication>();
|
||||
|
||||
for (int i = 0; i < chainedAuthenticationsList.size() - 1; i++) {
|
||||
authentications.add(serviceTicket.getGrantingTicket().getChainedAuthentications().get(i));
|
||||
}
|
||||
authentications.add(authToUse);
|
||||
|
||||
return new ImmutableAssertionImpl(authentications, serviceTicket.getService(), serviceTicket.isFromNewLogin());
|
||||
} finally {
|
||||
if (serviceTicket.isExpired()) {
|
||||
this.serviceTicketRegistry.deleteTicket(serviceTicketId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the principal id to use for a {@link RegisteredService} using the following rules:
|
||||
*
|
||||
* <ul>
|
||||
* <li> If the service is marked to allow anonymous access, a persistent id is returned. </li>
|
||||
* <li> If the attribute name matches {@link RegisteredService#DEFAULT_USERNAME_ATTRIBUTE}, then the default principal id is returned.</li>
|
||||
* <li>If the service is set to ignore attributes, or the username attribute exists in the allowed attributes for the service,
|
||||
* the corresponding attribute value will be returned.
|
||||
* </li>
|
||||
* <li>Otherwise, the default principal's id is returned as the username attribute with an additional warning.</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param principal The principal object to be validated and constructed
|
||||
* @param registeredService Requesting service for which a principal is being validated.
|
||||
* @param serviceTicket An instance of the service ticket used for validation
|
||||
*
|
||||
* @return The principal id to use for the requesting registered service
|
||||
*/
|
||||
private String determinePrincipalIdForRegisteredService(final Principal principal, final RegisteredService registeredService,
|
||||
final ServiceTicket serviceTicket) {
|
||||
String principalId = null;
|
||||
final String serviceUsernameAttribute = registeredService.getUsernameAttribute();
|
||||
|
||||
if (registeredService.isAnonymousAccess()) {
|
||||
principalId = this.persistentIdGenerator.generate(principal, serviceTicket.getService());
|
||||
} else if (StringUtils.isBlank(serviceUsernameAttribute)) {
|
||||
principalId = principal.getId();
|
||||
} else {
|
||||
if ((registeredService.isIgnoreAttributes() || registeredService.getAllowedAttributes().contains(serviceUsernameAttribute)) &&
|
||||
principal.getAttributes().containsKey(serviceUsernameAttribute)) {
|
||||
principalId = principal.getAttributes().get(registeredService.getUsernameAttribute()).toString();
|
||||
} else {
|
||||
principalId = principal.getId();
|
||||
final Object[] errorLogParameters = new Object[] { principalId, registeredService.getUsernameAttribute(),
|
||||
principal.getAttributes(), registeredService.getServiceId(), principalId };
|
||||
log.warn("Principal [{}] did not have attribute [{}] among attributes [{}] so CAS cannot "
|
||||
+ "provide on the validation response the user attribute the registered service [{}] expects. "
|
||||
+ "CAS will instead return the default username attribute [{}]", errorLogParameters);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
log.debug("Principal id to return for service [{}] is [{}]. The default principal id is [{}].",
|
||||
new Object[] {registeredService.getName(), principal.getId(), principalId});
|
||||
return principalId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws IllegalArgumentException if the credentials are null.
|
||||
*/
|
||||
@Audit(
|
||||
action="TICKET_GRANTING_TICKET",
|
||||
actionResolverName="CREATE_TICKET_GRANTING_TICKET_RESOLVER",
|
||||
resourceResolverName="CREATE_TICKET_GRANTING_TICKET_RESOURCE_RESOLVER")
|
||||
@Profiled(tag = "CREATE_TICKET_GRANTING_TICKET", logFailuresSeparately = false)
|
||||
@Transactional(readOnly = false)
|
||||
public String createTicketGrantingTicket(final Credentials credentials) throws TicketCreationException {
|
||||
Assert.notNull(credentials, "credentials cannot be null");
|
||||
|
||||
try {
|
||||
final Authentication authentication = this.authenticationManager
|
||||
.authenticate(credentials);
|
||||
|
||||
final TicketGrantingTicket ticketGrantingTicket = new TicketGrantingTicketImpl(
|
||||
this.ticketGrantingTicketUniqueTicketIdGenerator
|
||||
.getNewTicketId(TicketGrantingTicket.PREFIX),
|
||||
authentication, this.ticketGrantingTicketExpirationPolicy);
|
||||
|
||||
this.ticketRegistry.addTicket(ticketGrantingTicket);
|
||||
return ticketGrantingTicket.getId();
|
||||
} catch (final AuthenticationException e) {
|
||||
throw new TicketCreationException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to set the TicketRegistry.
|
||||
*
|
||||
* @param ticketRegistry the TicketRegistry to set.
|
||||
*/
|
||||
public void setTicketRegistry(final TicketRegistry ticketRegistry) {
|
||||
this.ticketRegistry = ticketRegistry;
|
||||
|
||||
if (this.serviceTicketRegistry == null) {
|
||||
this.serviceTicketRegistry = ticketRegistry;
|
||||
}
|
||||
}
|
||||
|
||||
public void setServiceTicketRegistry(final TicketRegistry serviceTicketRegistry) {
|
||||
this.serviceTicketRegistry = serviceTicketRegistry;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to inject the AuthenticationManager into the class.
|
||||
*
|
||||
* @param authenticationManager The authenticationManager to set.
|
||||
*/
|
||||
public void setAuthenticationManager(
|
||||
final AuthenticationManager authenticationManager) {
|
||||
this.authenticationManager = authenticationManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to inject the TicketGrantingTicket Expiration Policy.
|
||||
*
|
||||
* @param ticketGrantingTicketExpirationPolicy The
|
||||
* ticketGrantingTicketExpirationPolicy to set.
|
||||
*/
|
||||
public void setTicketGrantingTicketExpirationPolicy(
|
||||
final ExpirationPolicy ticketGrantingTicketExpirationPolicy) {
|
||||
this.ticketGrantingTicketExpirationPolicy = ticketGrantingTicketExpirationPolicy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to inject the Unique Ticket Id Generator into the class.
|
||||
*
|
||||
* @param uniqueTicketIdGenerator The uniqueTicketIdGenerator to use
|
||||
*/
|
||||
public void setTicketGrantingTicketUniqueTicketIdGenerator(
|
||||
final UniqueTicketIdGenerator uniqueTicketIdGenerator) {
|
||||
this.ticketGrantingTicketUniqueTicketIdGenerator = uniqueTicketIdGenerator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to inject the TicketGrantingTicket Expiration Policy.
|
||||
*
|
||||
* @param serviceTicketExpirationPolicy The serviceTicketExpirationPolicy to
|
||||
* set.
|
||||
*/
|
||||
public void setServiceTicketExpirationPolicy(
|
||||
final ExpirationPolicy serviceTicketExpirationPolicy) {
|
||||
this.serviceTicketExpirationPolicy = serviceTicketExpirationPolicy;
|
||||
}
|
||||
|
||||
public void setUniqueTicketIdGeneratorsForService(
|
||||
final Map<String, UniqueTicketIdGenerator> uniqueTicketIdGeneratorsForService) {
|
||||
this.uniqueTicketIdGeneratorsForService = uniqueTicketIdGeneratorsForService;
|
||||
}
|
||||
|
||||
public void setServicesManager(final ServicesManager servicesManager) {
|
||||
this.servicesManager = servicesManager;
|
||||
}
|
||||
|
||||
public void setPersistentIdGenerator(
|
||||
final PersistentIdGenerator persistentIdGenerator) {
|
||||
this.persistentIdGenerator = persistentIdGenerator;
|
||||
}
|
||||
}
|
@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Licensed to Jasig under one or more contributor license
|
||||
* agreements. See the NOTICE file distributed with this work
|
||||
* for additional information regarding copyright ownership.
|
||||
* Jasig licenses this file to you under the Apache License,
|
||||
* Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a
|
||||
* copy of the License at the following location:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.jasig.cas.aspect;
|
||||
|
||||
import org.aspectj.lang.JoinPoint;
|
||||
import org.aspectj.lang.ProceedingJoinPoint;
|
||||
import org.aspectj.lang.annotation.Around;
|
||||
import org.aspectj.lang.annotation.Aspect;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @version $Revision$ $Date$
|
||||
* @since 3.3.6
|
||||
*/
|
||||
@Aspect
|
||||
public class LogAspect {
|
||||
|
||||
@Around("(execution (public * org.jasig.cas..*.*(..))) && !(execution( * org.jasig.cas..*.set*(..)))")
|
||||
public Object traceMethod(final ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
|
||||
Object returnVal = null;
|
||||
final Logger log = getLog(proceedingJoinPoint);
|
||||
final String methodName = proceedingJoinPoint.getSignature().getName();
|
||||
|
||||
try {
|
||||
if (log.isTraceEnabled()) {
|
||||
final Object[] args = proceedingJoinPoint.getArgs();
|
||||
final String arguments;
|
||||
if (args == null || args.length == 0) {
|
||||
arguments = "";
|
||||
} else {
|
||||
arguments = Arrays.deepToString(args);
|
||||
}
|
||||
log.trace("Entering method [" + methodName + " with arguments [" + arguments + "]");
|
||||
}
|
||||
returnVal = proceedingJoinPoint.proceed();
|
||||
return returnVal;
|
||||
} finally {
|
||||
if (log.isTraceEnabled()) {
|
||||
log.trace("Leaving method [" + methodName + "] with return value [" + (returnVal != null ? returnVal.toString() : "null") + "].");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected Logger getLog(final JoinPoint joinPoint) {
|
||||
final Object target = joinPoint.getTarget();
|
||||
|
||||
if (target != null) {
|
||||
return LoggerFactory.getLogger(target.getClass());
|
||||
}
|
||||
|
||||
return LoggerFactory.getLogger(getClass());
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Licensed to Jasig under one or more contributor license
|
||||
* agreements. See the NOTICE file distributed with this work
|
||||
* for additional information regarding copyright ownership.
|
||||
* Jasig licenses this file to you under the Apache License,
|
||||
* Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a
|
||||
* copy of the License at the following location:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.jasig.cas.audit.spi;
|
||||
|
||||
import org.aspectj.lang.JoinPoint;
|
||||
import com.github.inspektr.audit.spi.AuditResourceResolver;
|
||||
import org.jasig.cas.authentication.principal.Credentials;
|
||||
import org.jasig.cas.util.AopUtils;
|
||||
|
||||
/**
|
||||
* Converts the Credentials object into a String resource identifier.
|
||||
*
|
||||
* @author Scott Battaglia
|
||||
* @version $Revision: 1.1 $ $Date: 2005/08/19 18:27:17 $
|
||||
* @since 3.1.2
|
||||
*
|
||||
*/
|
||||
public final class CredentialsAsFirstParameterResourceResolver implements AuditResourceResolver {
|
||||
|
||||
public String[] resolveFrom(final JoinPoint joinPoint, final Object retval) {
|
||||
final Credentials credentials = (Credentials) AopUtils.unWrapJoinPoint(joinPoint).getArgs()[0];
|
||||
return new String[] { "supplied credentials: " + credentials.toString() };
|
||||
}
|
||||
|
||||
public String[] resolveFrom(final JoinPoint joinPoint, final Exception exception) {
|
||||
final Credentials credentials = (Credentials) AopUtils.unWrapJoinPoint(joinPoint).getArgs()[0];
|
||||
return new String[] { "supplied credentials: " + credentials.toString() };
|
||||
}
|
||||
}
|
@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Licensed to Jasig under one or more contributor license
|
||||
* agreements. See the NOTICE file distributed with this work
|
||||
* for additional information regarding copyright ownership.
|
||||
* Jasig licenses this file to you under the Apache License,
|
||||
* Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a
|
||||
* copy of the License at the following location:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
package org.jasig.cas.audit.spi;
|
||||
|
||||
import com.github.inspektr.audit.spi.AuditResourceResolver;
|
||||
import org.aspectj.lang.JoinPoint;
|
||||
import org.jasig.cas.services.RegisteredService;
|
||||
import org.jasig.cas.services.ServicesManager;
|
||||
import org.jasig.cas.util.AopUtils;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
/**
|
||||
* Resolves a service id to the service.
|
||||
* <p>
|
||||
* The expectation is that args[0] is a Long.
|
||||
*
|
||||
* @author Scott Battaglia
|
||||
* @version $Revision$ $Date$
|
||||
* @since 3.4.6
|
||||
*/
|
||||
public final class ServiceManagementResourceResolver implements AuditResourceResolver {
|
||||
|
||||
public String[] resolveFrom(final JoinPoint target, final Object returnValue) {
|
||||
return findService(target);
|
||||
}
|
||||
|
||||
public String[] resolveFrom(final JoinPoint target, final Exception exception) {
|
||||
return findService(target);
|
||||
}
|
||||
|
||||
private String[] findService(final JoinPoint joinPoint) {
|
||||
final JoinPoint j = AopUtils.unWrapJoinPoint(joinPoint);
|
||||
|
||||
final Long id = (Long) j.getArgs()[0];
|
||||
|
||||
if (id == null) {
|
||||
return new String[] {""};
|
||||
}
|
||||
|
||||
return new String[] {"id=" + id};
|
||||
}
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Licensed to Jasig under one or more contributor license
|
||||
* agreements. See the NOTICE file distributed with this work
|
||||
* for additional information regarding copyright ownership.
|
||||
* Jasig licenses this file to you under the Apache License,
|
||||
* Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a
|
||||
* copy of the License at the following location:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.jasig.cas.audit.spi;
|
||||
|
||||
import org.aspectj.lang.JoinPoint;
|
||||
import com.github.inspektr.audit.spi.AuditResourceResolver;
|
||||
import org.jasig.cas.authentication.principal.Service;
|
||||
import org.jasig.cas.util.AopUtils;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Scott Battaglia
|
||||
* @version $Revision: 1.1 $ $Date: 2005/08/19 18:27:17 $
|
||||
* @since 3.1.2
|
||||
*
|
||||
*/
|
||||
public final class ServiceResourceResolver implements AuditResourceResolver {
|
||||
|
||||
public String[] resolveFrom(final JoinPoint joinPoint, final Object retval) {
|
||||
final Service service = (Service) AopUtils.unWrapJoinPoint(joinPoint).getArgs()[1];
|
||||
return new String[] { retval.toString() + " for " + service.getId() };
|
||||
}
|
||||
|
||||
public String[] resolveFrom(final JoinPoint joinPoint, final Exception ex) {
|
||||
final Service service = (Service) AopUtils.unWrapJoinPoint(joinPoint).getArgs()[1];
|
||||
return new String[] { service.getId() };
|
||||
}
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Licensed to Jasig under one or more contributor license
|
||||
* agreements. See the NOTICE file distributed with this work
|
||||
* for additional information regarding copyright ownership.
|
||||
* Jasig licenses this file to you under the Apache License,
|
||||
* Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a
|
||||
* copy of the License at the following location:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.jasig.cas.audit.spi;
|
||||
|
||||
import com.github.inspektr.audit.spi.AuditResourceResolver;
|
||||
import org.aspectj.lang.JoinPoint;
|
||||
import org.jasig.cas.util.AopUtils;
|
||||
|
||||
/**
|
||||
* Implementation of the ResourceResolver that can determine the Ticket Id from the first parameter of the method call.
|
||||
|
||||
* @author Scott Battaglia
|
||||
* @version $Revision: 1.1 $ $Date: 2005/08/19 18:27:17 $
|
||||
* @since 3.1.2
|
||||
*
|
||||
*/
|
||||
public final class TicketAsFirstParameterResourceResolver implements AuditResourceResolver {
|
||||
|
||||
public String[] resolveFrom(final JoinPoint joinPoint, final Exception exception) {
|
||||
return new String[] { AopUtils.unWrapJoinPoint(joinPoint).getArgs()[0].toString() };
|
||||
}
|
||||
|
||||
public String[] resolveFrom(final JoinPoint joinPoint, final Object object) {
|
||||
return new String[] { AopUtils.unWrapJoinPoint(joinPoint).getArgs()[0].toString() };
|
||||
}
|
||||
}
|
@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Licensed to Jasig under one or more contributor license
|
||||
* agreements. See the NOTICE file distributed with this work
|
||||
* for additional information regarding copyright ownership.
|
||||
* Jasig licenses this file to you under the Apache License,
|
||||
* Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a
|
||||
* copy of the License at the following location:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.jasig.cas.audit.spi;
|
||||
|
||||
import org.aspectj.lang.JoinPoint;
|
||||
import com.github.inspektr.common.spi.PrincipalResolver;
|
||||
import org.jasig.cas.authentication.principal.Credentials;
|
||||
import org.jasig.cas.ticket.ServiceTicket;
|
||||
import org.jasig.cas.ticket.Ticket;
|
||||
import org.jasig.cas.ticket.TicketGrantingTicket;
|
||||
import org.jasig.cas.ticket.registry.TicketRegistry;
|
||||
import org.jasig.cas.util.AopUtils;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.context.SecurityContext;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
/**
|
||||
* PrincipalResolver that can retrieve the username from either the Ticket or from the Credentials.
|
||||
*
|
||||
* @author Scott Battaglia
|
||||
* @version $Revision: 1.1 $ $Date: 2005/08/19 18:27:17 $
|
||||
* @since 3.1.2
|
||||
*
|
||||
*/
|
||||
public final class TicketOrCredentialPrincipalResolver implements PrincipalResolver {
|
||||
|
||||
@NotNull
|
||||
private final TicketRegistry ticketRegistry;
|
||||
|
||||
public TicketOrCredentialPrincipalResolver(final TicketRegistry ticketRegistry) {
|
||||
this.ticketRegistry = ticketRegistry;
|
||||
}
|
||||
|
||||
public String resolveFrom(final JoinPoint joinPoint, final Object retVal) {
|
||||
return resolveFromInternal(AopUtils.unWrapJoinPoint(joinPoint));
|
||||
}
|
||||
|
||||
public String resolveFrom(final JoinPoint joinPoint, final Exception retVal) {
|
||||
return resolveFromInternal(AopUtils.unWrapJoinPoint(joinPoint));
|
||||
}
|
||||
|
||||
public String resolve() {
|
||||
return UNKNOWN_USER;
|
||||
}
|
||||
|
||||
protected String resolveFromInternal(final JoinPoint joinPoint) {
|
||||
final Object arg1 = joinPoint.getArgs()[0];
|
||||
if (arg1 instanceof Credentials) {
|
||||
return arg1.toString();
|
||||
} else if (arg1 instanceof String) {
|
||||
final Ticket ticket = this.ticketRegistry.getTicket((String) arg1);
|
||||
if (ticket instanceof ServiceTicket) {
|
||||
final ServiceTicket serviceTicket = (ServiceTicket) ticket;
|
||||
return serviceTicket.getGrantingTicket().getAuthentication().getPrincipal().getId();
|
||||
} else if (ticket instanceof TicketGrantingTicket) {
|
||||
final TicketGrantingTicket tgt = (TicketGrantingTicket) ticket;
|
||||
return tgt.getAuthentication().getPrincipal().getId();
|
||||
}
|
||||
} else {
|
||||
final SecurityContext securityContext = SecurityContextHolder.getContext();
|
||||
if (securityContext != null) {
|
||||
final Authentication authentication = securityContext.getAuthentication();
|
||||
|
||||
if (authentication != null) {
|
||||
return ((UserDetails) authentication.getPrincipal()).getUsername();
|
||||
}
|
||||
}
|
||||
}
|
||||
return UNKNOWN_USER;
|
||||
}
|
||||
}
|
@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Licensed to Jasig under one or more contributor license
|
||||
* agreements. See the NOTICE file distributed with this work
|
||||
* for additional information regarding copyright ownership.
|
||||
* Jasig licenses this file to you under the Apache License,
|
||||
* Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a
|
||||
* copy of the License at the following location:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.jasig.cas.authentication;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.jasig.cas.authentication.principal.Principal;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* @author Scott Battaglia
|
||||
* @version $Revision$ $Date: 2007-02-20 09:41:49 -0500 (Tue, 20 Feb
|
||||
* 2007) $
|
||||
* @since 3.0.3
|
||||
*/
|
||||
public abstract class AbstractAuthentication implements Authentication {
|
||||
|
||||
/** A Principal object representing the authenticated entity. */
|
||||
private final Principal principal;
|
||||
|
||||
/** Associated authentication attributes. */
|
||||
private final Map<String, Object> attributes;
|
||||
|
||||
public AbstractAuthentication(final Principal principal,
|
||||
final Map<String, Object> attributes) {
|
||||
Assert.notNull(principal, "principal cannot be null");
|
||||
Assert.notNull(attributes, "attributes cannot be null");
|
||||
|
||||
this.principal = principal;
|
||||
this.attributes = attributes;
|
||||
}
|
||||
|
||||
public final Map<String, Object> getAttributes() {
|
||||
return this.attributes;
|
||||
}
|
||||
|
||||
public final Principal getPrincipal() {
|
||||
return this.principal;
|
||||
}
|
||||
|
||||
public final boolean equals(final Object o) {
|
||||
if (o == null || !this.getClass().isAssignableFrom(o.getClass())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Authentication a = (Authentication) o;
|
||||
|
||||
return this.principal.equals(a.getPrincipal())
|
||||
&& this.getAuthenticatedDate().equals(a.getAuthenticatedDate()) && this.attributes.equals(a.getAttributes());
|
||||
}
|
||||
|
||||
public final int hashCode() {
|
||||
return 49 * this.principal.hashCode()
|
||||
^ this.getAuthenticatedDate().hashCode();
|
||||
}
|
||||
|
||||
public final String toString() {
|
||||
return "[Principal=" + this.principal.getId() + ", attributes="
|
||||
+ this.attributes.toString() + "]";
|
||||
}
|
||||
}
|
@ -0,0 +1,140 @@
|
||||
/*
|
||||
* Licensed to Jasig under one or more contributor license
|
||||
* agreements. See the NOTICE file distributed with this work
|
||||
* for additional information regarding copyright ownership.
|
||||
* Jasig licenses this file to you under the Apache License,
|
||||
* Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a
|
||||
* copy of the License at the following location:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.jasig.cas.authentication;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
import com.github.inspektr.audit.annotation.Audit;
|
||||
import org.jasig.cas.authentication.handler.AuthenticationException;
|
||||
import org.jasig.cas.authentication.handler.AuthenticationHandler;
|
||||
import org.jasig.cas.authentication.handler.NamedAuthenticationHandler;
|
||||
import org.jasig.cas.authentication.handler.UncategorizedAuthenticationException;
|
||||
import org.jasig.cas.authentication.principal.Credentials;
|
||||
import org.jasig.cas.authentication.principal.Principal;
|
||||
import org.perf4j.aop.Profiled;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* @author Scott Battaglia
|
||||
* @version $Revision$ $Date$
|
||||
* @since 3.3.5
|
||||
*/
|
||||
public abstract class AbstractAuthenticationManager implements AuthenticationManager {
|
||||
|
||||
/** Log instance for logging events, errors, warnings, etc. */
|
||||
protected final Logger log = LoggerFactory.getLogger(AuthenticationManagerImpl.class);
|
||||
|
||||
/** An array of AuthenticationAttributesPopulators. */
|
||||
@NotNull
|
||||
private List<AuthenticationMetaDataPopulator> authenticationMetaDataPopulators = new ArrayList<AuthenticationMetaDataPopulator>();
|
||||
|
||||
@Audit(
|
||||
action="AUTHENTICATION",
|
||||
actionResolverName="AUTHENTICATION_RESOLVER",
|
||||
resourceResolverName="AUTHENTICATION_RESOURCE_RESOLVER")
|
||||
@Profiled(tag = "AUTHENTICATE", logFailuresSeparately = false)
|
||||
public final Authentication authenticate(final Credentials credentials) throws AuthenticationException {
|
||||
|
||||
final Pair<AuthenticationHandler, Principal> pair = authenticateAndObtainPrincipal(credentials);
|
||||
|
||||
// we can only get here if the above method doesn't throw an exception. And if it doesn't, then the pair must not be null.
|
||||
final Principal p = pair.getSecond();
|
||||
log.info("{} authenticated {} with credential {}.", pair.getFirst(), p, credentials);
|
||||
log.debug("Attribute map for {}: {}", p.getId(), p.getAttributes());
|
||||
|
||||
Authentication authentication = new MutableAuthentication(p);
|
||||
|
||||
if (pair.getFirst()instanceof NamedAuthenticationHandler) {
|
||||
final NamedAuthenticationHandler a = (NamedAuthenticationHandler) pair.getFirst();
|
||||
authentication.getAttributes().put(AuthenticationManager.AUTHENTICATION_METHOD_ATTRIBUTE, a.getName());
|
||||
}
|
||||
|
||||
for (final AuthenticationMetaDataPopulator authenticationMetaDataPopulator : this.authenticationMetaDataPopulators) {
|
||||
authentication = authenticationMetaDataPopulator
|
||||
.populateAttributes(authentication, credentials);
|
||||
}
|
||||
|
||||
return new ImmutableAuthentication(authentication.getPrincipal(),
|
||||
authentication.getAttributes());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param authenticationMetaDataPopulators the authenticationMetaDataPopulators to set.
|
||||
*/
|
||||
public final void setAuthenticationMetaDataPopulators(final List<AuthenticationMetaDataPopulator> authenticationMetaDataPopulators) {
|
||||
this.authenticationMetaDataPopulators = authenticationMetaDataPopulators;
|
||||
}
|
||||
|
||||
/**
|
||||
* Follows the same rules as the "authenticate" method (i.e. should only return a fully populated object, or throw an exception)
|
||||
*
|
||||
* @param credentials the credentials to check
|
||||
* @return the pair of authentication handler and principal. CANNOT be NULL.
|
||||
* @throws AuthenticationException if there is an error authenticating.
|
||||
*/
|
||||
protected abstract Pair<AuthenticationHandler,Principal> authenticateAndObtainPrincipal(Credentials credentials) throws AuthenticationException;
|
||||
|
||||
|
||||
/**
|
||||
* Handles an authentication error raised by an {@link AuthenticationHandler}.
|
||||
*
|
||||
* @param handlerName The class name of the authentication handler.
|
||||
* @param credentials Client credentials subject to authentication.
|
||||
* @param e The exception that has occurred during authentication attempt.
|
||||
*/
|
||||
protected void handleError(final String handlerName, final Credentials credentials, final Exception e)
|
||||
throws AuthenticationException {
|
||||
if (e instanceof AuthenticationException) {
|
||||
// CAS-1181 Log common authentication failures at INFO without stack trace
|
||||
log.info("{} failed authenticating {}", handlerName, credentials);
|
||||
throw (AuthenticationException) e;
|
||||
}
|
||||
log.error("{} threw error authenticating {}", handlerName, credentials, e);
|
||||
throw new UncategorizedAuthenticationException(e.getClass().getName(), e) {
|
||||
// Anonymous inner class allows us to throw uncategorized authentication error
|
||||
// since base class is abstract.
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
protected static class Pair<A,B> {
|
||||
|
||||
private final A first;
|
||||
|
||||
private final B second;
|
||||
|
||||
public Pair(final A first, final B second) {
|
||||
this.first = first;
|
||||
this.second = second;
|
||||
}
|
||||
|
||||
public A getFirst() {
|
||||
return this.first;
|
||||
}
|
||||
|
||||
|
||||
public B getSecond() {
|
||||
return this.second;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Licensed to Jasig under one or more contributor license
|
||||
* agreements. See the NOTICE file distributed with this work
|
||||
* for additional information regarding copyright ownership.
|
||||
* Jasig licenses this file to you under the Apache License,
|
||||
* Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a
|
||||
* copy of the License at the following location:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.jasig.cas.authentication;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
|
||||
import org.jasig.cas.authentication.principal.Principal;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* The Authentication object represents a successful authentication request. It
|
||||
* contains the principal that the authentication request was made for as well
|
||||
* as the additional meta information such as the authenticated date and a map
|
||||
* of attributes.
|
||||
* </p>
|
||||
* <p>
|
||||
* An Authentication object must be serializable to permit persistance and
|
||||
* clustering.
|
||||
* </p>
|
||||
* <p>
|
||||
* Implementing classes must take care to ensure that the Map returned by
|
||||
* getAttributes is serializable by using a Serializable map such as HashMap.
|
||||
* </p>
|
||||
*
|
||||
* @author Dmitriy Kopylenko
|
||||
* @author Scott Battaglia
|
||||
* @version $Revision$ $Date$
|
||||
* @since 3.0
|
||||
* <p>
|
||||
* This is a published and supported CAS Server 3 API.
|
||||
* </p>
|
||||
*/
|
||||
public interface Authentication extends Serializable {
|
||||
|
||||
/**
|
||||
* Method to obtain the Principal.
|
||||
*
|
||||
* @return a Principal implementation
|
||||
*/
|
||||
Principal getPrincipal();
|
||||
|
||||
/**
|
||||
* Method to retrieve the timestamp of when this Authentication object was
|
||||
* created.
|
||||
*
|
||||
* @return the date/time the authentication occurred.
|
||||
*/
|
||||
Date getAuthenticatedDate();
|
||||
|
||||
/**
|
||||
* Attributes of the authentication (not the Principal).
|
||||
*
|
||||
* @return the map of attributes.
|
||||
*/
|
||||
Map<String, Object> getAttributes();
|
||||
}
|
@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Licensed to Jasig under one or more contributor license
|
||||
* agreements. See the NOTICE file distributed with this work
|
||||
* for additional information regarding copyright ownership.
|
||||
* Jasig licenses this file to you under the Apache License,
|
||||
* Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a
|
||||
* copy of the License at the following location:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.jasig.cas.authentication;
|
||||
|
||||
import org.jasig.cas.authentication.handler.AuthenticationException;
|
||||
import org.jasig.cas.authentication.principal.Credentials;
|
||||
|
||||
/**
|
||||
* The AuthenticationManager class is the entity that determines the
|
||||
* authenticity of the credentials provided. It (or a class it delegates to) is
|
||||
* the sole authority on whether credentials are valid or not.
|
||||
*
|
||||
* @author Scott Battaglia
|
||||
* @version $Revision$ $Date$
|
||||
* @since 3.0
|
||||
* <p>
|
||||
* This is a published and supported CAS Server 3 API.
|
||||
* </p>
|
||||
*/
|
||||
public interface AuthenticationManager {
|
||||
|
||||
String AUTHENTICATION_METHOD_ATTRIBUTE = "authenticationMethod";
|
||||
|
||||
/**
|
||||
* Method to validate the credentials provided. On successful validation, a
|
||||
* fully populated Authentication object will be returned. Typically this
|
||||
* will involve resolving a principal and providing any additional
|
||||
* attributes, but specifics are left to the individual implementations to
|
||||
* determine. Failure to authenticate is considered an exceptional case, and
|
||||
* an AuthenticationException is thrown.
|
||||
*
|
||||
* @param credentials The credentials provided for authentication.
|
||||
* @return fully populated Authentication object.
|
||||
* @throws AuthenticationException if unable to determine validity of
|
||||
* credentials or there is an extenuating circumstance related to
|
||||
* credentials (i.e. Account locked).
|
||||
*/
|
||||
Authentication authenticate(final Credentials credentials)
|
||||
throws AuthenticationException;
|
||||
}
|
@ -0,0 +1,155 @@
|
||||
/*
|
||||
* Licensed to Jasig under one or more contributor license
|
||||
* agreements. See the NOTICE file distributed with this work
|
||||
* for additional information regarding copyright ownership.
|
||||
* Jasig licenses this file to you under the Apache License,
|
||||
* Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a
|
||||
* copy of the License at the following location:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.jasig.cas.authentication;
|
||||
|
||||
import java.util.List;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import javax.validation.constraints.Size;
|
||||
|
||||
import org.jasig.cas.authentication.handler.AuthenticationException;
|
||||
import org.jasig.cas.authentication.handler.AuthenticationHandler;
|
||||
import org.jasig.cas.authentication.handler.BadCredentialsAuthenticationException;
|
||||
import org.jasig.cas.authentication.handler.UnsupportedCredentialsException;
|
||||
import org.jasig.cas.authentication.principal.Credentials;
|
||||
import org.jasig.cas.authentication.principal.CredentialsToPrincipalResolver;
|
||||
import org.jasig.cas.authentication.principal.Principal;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Default implementation of the AuthenticationManager. The
|
||||
* AuthenticationManager follows the following algorithm. The manager loops
|
||||
* through the array of AuthenticationHandlers searching for one that can
|
||||
* attempt to determine the validity of the credentials. If it finds one, it
|
||||
* tries that one. If that handler returns true, it continues on. If it returns
|
||||
* false, it looks for another handler. If it throws an exception, it aborts the
|
||||
* whole process and rethrows the exception. Next, it looks for a
|
||||
* CredentialsToPrincipalResolver that can handle the credentials in order to
|
||||
* create a Principal. Finally, it attempts to populate the Authentication
|
||||
* object's attributes map using AuthenticationAttributesPopulators
|
||||
* <p>
|
||||
* Behavior is determined by external beans attached through three configuration
|
||||
* properties. The Credentials are opaque to the manager. They are passed to the
|
||||
* external beans to see if any can process the actual type represented by the
|
||||
* Credentials marker.
|
||||
* <p>
|
||||
* AuthenticationManagerImpl requires the following properties to be set:
|
||||
* </p>
|
||||
* <ul>
|
||||
* <li> <code>authenticationHandlers</code> - The array of
|
||||
* AuthenticationHandlers that know how to process the credentials provided.
|
||||
* <li> <code>credentialsToPrincipalResolvers</code> - The array of
|
||||
* CredentialsToPrincipal resolvers that know how to process the credentials
|
||||
* provided.
|
||||
* </ul>
|
||||
*
|
||||
* @author Scott Battaglia
|
||||
* @version $Revision$ $Date$
|
||||
* @since 3.0
|
||||
* @see org.jasig.cas.authentication.handler.AuthenticationHandler
|
||||
* @see org.jasig.cas.authentication.principal.CredentialsToPrincipalResolver
|
||||
* @see org.jasig.cas.authentication.AuthenticationMetaDataPopulator
|
||||
*/
|
||||
|
||||
public final class AuthenticationManagerImpl extends AbstractAuthenticationManager {
|
||||
|
||||
/** An array of authentication handlers. */
|
||||
@NotNull
|
||||
@Size(min=1)
|
||||
private List<AuthenticationHandler> authenticationHandlers;
|
||||
|
||||
/** An array of CredentialsToPrincipalResolvers. */
|
||||
@NotNull
|
||||
@Size(min=1)
|
||||
private List<CredentialsToPrincipalResolver> credentialsToPrincipalResolvers;
|
||||
|
||||
@Override
|
||||
protected Pair<AuthenticationHandler, Principal> authenticateAndObtainPrincipal(final Credentials credentials) throws AuthenticationException {
|
||||
boolean foundSupported = false;
|
||||
boolean authenticated = false;
|
||||
AuthenticationHandler authenticatedClass = null;
|
||||
String handlerName;
|
||||
|
||||
for (final AuthenticationHandler authenticationHandler : this.authenticationHandlers) {
|
||||
if (authenticationHandler.supports(credentials)) {
|
||||
foundSupported = true;
|
||||
handlerName = authenticationHandler.getClass().getName();
|
||||
try {
|
||||
if (!authenticationHandler.authenticate(credentials)) {
|
||||
log.info("{} failed to authenticate {}", handlerName, credentials);
|
||||
} else {
|
||||
log.info("{} successfully authenticated {}", handlerName, credentials);
|
||||
authenticatedClass = authenticationHandler;
|
||||
authenticated = true;
|
||||
break;
|
||||
}
|
||||
} catch (final Exception e) {
|
||||
handleError(handlerName, credentials, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!authenticated) {
|
||||
if (foundSupported) {
|
||||
throw BadCredentialsAuthenticationException.ERROR;
|
||||
}
|
||||
throw UnsupportedCredentialsException.ERROR;
|
||||
}
|
||||
|
||||
foundSupported = false;
|
||||
|
||||
for (final CredentialsToPrincipalResolver credentialsToPrincipalResolver : this.credentialsToPrincipalResolvers) {
|
||||
if (credentialsToPrincipalResolver.supports(credentials)) {
|
||||
final Principal principal = credentialsToPrincipalResolver.resolvePrincipal(credentials);
|
||||
log.info("Resolved principal " + principal);
|
||||
foundSupported = true;
|
||||
if (principal != null) {
|
||||
return new Pair<AuthenticationHandler,Principal>(authenticatedClass, principal);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (foundSupported) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("CredentialsToPrincipalResolver found but no principal returned.");
|
||||
}
|
||||
|
||||
throw BadCredentialsAuthenticationException.ERROR;
|
||||
}
|
||||
|
||||
log.error("CredentialsToPrincipalResolver not found for " + credentials.getClass().getName());
|
||||
throw UnsupportedCredentialsException.ERROR;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param authenticationHandlers The authenticationHandlers to set.
|
||||
*/
|
||||
public void setAuthenticationHandlers(
|
||||
final List<AuthenticationHandler> authenticationHandlers) {
|
||||
this.authenticationHandlers = authenticationHandlers;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param credentialsToPrincipalResolvers The
|
||||
* credentialsToPrincipalResolvers to set.
|
||||
*/
|
||||
public void setCredentialsToPrincipalResolvers(
|
||||
final List<CredentialsToPrincipalResolver> credentialsToPrincipalResolvers) {
|
||||
this.credentialsToPrincipalResolvers = credentialsToPrincipalResolvers;
|
||||
}
|
||||
}
|
@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Licensed to Jasig under one or more contributor license
|
||||
* agreements. See the NOTICE file distributed with this work
|
||||
* for additional information regarding copyright ownership.
|
||||
* Jasig licenses this file to you under the Apache License,
|
||||
* Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a
|
||||
* copy of the License at the following location:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.jasig.cas.authentication;
|
||||
|
||||
import org.jasig.cas.authentication.principal.Credentials;
|
||||
|
||||
/**
|
||||
* An extension point to the Authentication process that allows CAS to provide
|
||||
* additional attributes related to the overall Authentication (such as
|
||||
* authentication type) that are specific to the Authentication request versus
|
||||
* the Principal itself. AuthenticationAttributePopulators are a new feature in
|
||||
* CAS3. In order for an installation to be CAS2 compliant, deployers do not
|
||||
* need an AuthenticationMetaDataPopulator.
|
||||
*
|
||||
* @author Scott Battaglia
|
||||
* @version $Revision$ $Date$
|
||||
* @since 3.0
|
||||
* <p>
|
||||
* This is a published and supported CAS Server 3 API.
|
||||
* </p>
|
||||
*/
|
||||
public interface AuthenticationMetaDataPopulator {
|
||||
|
||||
/**
|
||||
* Provided with an Authentication object and the original credentials
|
||||
* presented, provide any additional attributes to the Authentication
|
||||
* object. Implementations have the option of returning the same
|
||||
* Authentication object, or a new one.
|
||||
*
|
||||
* @param authentication The Authentication to potentially augment with
|
||||
* additional attributes.
|
||||
* @return the original Authentication object or a new Authentication
|
||||
* object.
|
||||
*/
|
||||
Authentication populateAttributes(Authentication authentication,
|
||||
Credentials credentials);
|
||||
}
|
@ -0,0 +1,112 @@
|
||||
/*
|
||||
* Licensed to Jasig under one or more contributor license
|
||||
* agreements. See the NOTICE file distributed with this work
|
||||
* for additional information regarding copyright ownership.
|
||||
* Jasig licenses this file to you under the Apache License,
|
||||
* Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a
|
||||
* copy of the License at the following location:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.jasig.cas.authentication;
|
||||
|
||||
import java.util.Map;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import javax.validation.constraints.Size;
|
||||
|
||||
import org.jasig.cas.authentication.handler.AuthenticationException;
|
||||
import org.jasig.cas.authentication.handler.AuthenticationHandler;
|
||||
import org.jasig.cas.authentication.handler.BadCredentialsAuthenticationException;
|
||||
import org.jasig.cas.authentication.principal.Credentials;
|
||||
import org.jasig.cas.authentication.principal.CredentialsToPrincipalResolver;
|
||||
import org.jasig.cas.authentication.principal.Principal;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Authentication Manager that provides a direct mapping between credentials
|
||||
* provided and the authentication handler used to authenticate the user.
|
||||
*
|
||||
* @author Scott Battaglia
|
||||
* @version $Revision$ $Date$
|
||||
* @since 3.1
|
||||
*/
|
||||
public final class DirectMappingAuthenticationManagerImpl extends AbstractAuthenticationManager {
|
||||
|
||||
@NotNull
|
||||
@Size(min=1)
|
||||
private Map<Class< ? extends Credentials>, DirectAuthenticationHandlerMappingHolder> credentialsMapping;
|
||||
|
||||
/**
|
||||
* @throws IllegalArgumentException if a mapping cannot be found.
|
||||
* @see org.jasig.cas.authentication.AuthenticationManager#authenticate(org.jasig.cas.authentication.principal.Credentials)
|
||||
*/
|
||||
@Override
|
||||
protected Pair<AuthenticationHandler, Principal> authenticateAndObtainPrincipal(final Credentials credentials) throws AuthenticationException {
|
||||
final Class< ? extends Credentials> credentialsClass = credentials.getClass();
|
||||
final DirectAuthenticationHandlerMappingHolder d = this.credentialsMapping.get(credentialsClass);
|
||||
|
||||
Assert.notNull(d, "no mapping found for: " + credentialsClass.getName());
|
||||
|
||||
final String handlerName = d.getAuthenticationHandler().getClass().getSimpleName();
|
||||
boolean authenticated = false;
|
||||
|
||||
try {
|
||||
authenticated = d.getAuthenticationHandler().authenticate(credentials);
|
||||
} catch (final Exception e) {
|
||||
handleError(handlerName, credentials, e);
|
||||
}
|
||||
|
||||
if (!authenticated) {
|
||||
log.info("{} failed to authenticate {}", handlerName, credentials);
|
||||
throw BadCredentialsAuthenticationException.ERROR;
|
||||
}
|
||||
log.info("{} successfully authenticated {}", handlerName, credentials);
|
||||
|
||||
final Principal p = d.getCredentialsToPrincipalResolver().resolvePrincipal(credentials);
|
||||
|
||||
return new Pair<AuthenticationHandler,Principal>(d.getAuthenticationHandler(), p);
|
||||
}
|
||||
|
||||
public final void setCredentialsMapping(
|
||||
final Map<Class< ? extends Credentials>, DirectAuthenticationHandlerMappingHolder> credentialsMapping) {
|
||||
this.credentialsMapping = credentialsMapping;
|
||||
}
|
||||
|
||||
public static final class DirectAuthenticationHandlerMappingHolder {
|
||||
|
||||
private AuthenticationHandler authenticationHandler;
|
||||
|
||||
private CredentialsToPrincipalResolver credentialsToPrincipalResolver;
|
||||
|
||||
public DirectAuthenticationHandlerMappingHolder() {
|
||||
// nothing to do
|
||||
}
|
||||
|
||||
public final AuthenticationHandler getAuthenticationHandler() {
|
||||
return this.authenticationHandler;
|
||||
}
|
||||
|
||||
public void setAuthenticationHandler(
|
||||
final AuthenticationHandler authenticationHandler) {
|
||||
this.authenticationHandler = authenticationHandler;
|
||||
}
|
||||
|
||||
public CredentialsToPrincipalResolver getCredentialsToPrincipalResolver() {
|
||||
return this.credentialsToPrincipalResolver;
|
||||
}
|
||||
|
||||
public void setCredentialsToPrincipalResolver(
|
||||
final CredentialsToPrincipalResolver credentialsToPrincipalResolver) {
|
||||
this.credentialsToPrincipalResolver = credentialsToPrincipalResolver;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Licensed to Jasig under one or more contributor license
|
||||
* agreements. See the NOTICE file distributed with this work
|
||||
* for additional information regarding copyright ownership.
|
||||
* Jasig licenses this file to you under the Apache License,
|
||||
* Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a
|
||||
* copy of the License at the following location:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.jasig.cas.authentication;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.jasig.cas.authentication.principal.Principal;
|
||||
|
||||
/**
|
||||
* Default implementation of Authentication interface. ImmutableAuthentication
|
||||
* is an immutable object and thus its attributes cannot be changed.
|
||||
* <p>
|
||||
* Instanciators of the ImmutableAuthentication class must take care that the
|
||||
* map they provide is serializable (i.e. HashMap).
|
||||
*
|
||||
* @author Dmitriy Kopylenko
|
||||
* @author Scott Battaglia
|
||||
* @version $Revision$ $Date$
|
||||
* @since 3.0
|
||||
*/
|
||||
public final class ImmutableAuthentication extends AbstractAuthentication {
|
||||
|
||||
/** UID for serializing. */
|
||||
private static final long serialVersionUID = 3906647483978365235L;
|
||||
|
||||
private static final Map<String, Object> EMPTY_MAP = Collections.unmodifiableMap(new HashMap<String, Object>());
|
||||
|
||||
/** The date/time this authentication object became valid. */
|
||||
final Date authenticatedDate;
|
||||
|
||||
/**
|
||||
* Constructor that accepts both a principal and a map.
|
||||
*
|
||||
* @param principal Principal representing user
|
||||
* @param attributes Authentication attributes map.
|
||||
* @throws IllegalArgumentException if the principal is null.
|
||||
*/
|
||||
public ImmutableAuthentication(final Principal principal,
|
||||
final Map<String, Object> attributes) {
|
||||
super(principal, attributes == null || attributes.isEmpty()
|
||||
? EMPTY_MAP : Collections.unmodifiableMap(attributes));
|
||||
|
||||
this.authenticatedDate = new Date();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor that assumes there are no additional authentication
|
||||
* attributes.
|
||||
*
|
||||
* @param principal the Principal representing the authenticated entity.
|
||||
*/
|
||||
public ImmutableAuthentication(final Principal principal) {
|
||||
this(principal, null);
|
||||
}
|
||||
|
||||
public Date getAuthenticatedDate() {
|
||||
return new Date(this.authenticatedDate.getTime());
|
||||
}
|
||||
}
|
@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Licensed to Jasig under one or more contributor license
|
||||
* agreements. See the NOTICE file distributed with this work
|
||||
* for additional information regarding copyright ownership.
|
||||
* Jasig licenses this file to you under the Apache License,
|
||||
* Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a
|
||||
* copy of the License at the following location:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.jasig.cas.authentication;
|
||||
|
||||
import java.util.Map;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import javax.validation.constraints.Size;
|
||||
|
||||
import org.jasig.cas.authentication.handler.AuthenticationException;
|
||||
import org.jasig.cas.authentication.handler.AuthenticationHandler;
|
||||
import org.jasig.cas.authentication.handler.BadCredentialsAuthenticationException;
|
||||
import org.jasig.cas.authentication.handler.UnsupportedCredentialsException;
|
||||
import org.jasig.cas.authentication.principal.Credentials;
|
||||
import org.jasig.cas.authentication.principal.CredentialsToPrincipalResolver;
|
||||
import org.jasig.cas.authentication.principal.Principal;
|
||||
|
||||
/**
|
||||
* Ensures that all authentication handlers are tried, but if one is tried, the associated CredentialsToPrincipalResolver is used.
|
||||
*
|
||||
* @author Scott Battaglia
|
||||
* @version $Revision$ $Date$
|
||||
* @since 3.3.5
|
||||
*/
|
||||
public class LinkedAuthenticationHandlerAndCredentialsToPrincipalResolverAuthenticationManager extends AbstractAuthenticationManager {
|
||||
|
||||
@NotNull
|
||||
@Size(min = 1)
|
||||
private final Map<AuthenticationHandler, CredentialsToPrincipalResolver> linkedHandlers;
|
||||
|
||||
public LinkedAuthenticationHandlerAndCredentialsToPrincipalResolverAuthenticationManager(final Map<AuthenticationHandler,CredentialsToPrincipalResolver> linkedHandlers) {
|
||||
this.linkedHandlers = linkedHandlers;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Pair<AuthenticationHandler, Principal> authenticateAndObtainPrincipal(final Credentials credentials) throws AuthenticationException {
|
||||
boolean foundOneThatWorks = false;
|
||||
String handlerName;
|
||||
|
||||
for (final AuthenticationHandler authenticationHandler : this.linkedHandlers.keySet()) {
|
||||
if (!authenticationHandler.supports(credentials)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
foundOneThatWorks = true;
|
||||
boolean authenticated = false;
|
||||
handlerName = authenticationHandler.getClass().getName();
|
||||
|
||||
try {
|
||||
authenticated = authenticationHandler.authenticate(credentials);
|
||||
} catch (final Exception e) {
|
||||
handleError(handlerName, credentials, e);
|
||||
}
|
||||
|
||||
if (authenticated) {
|
||||
log.info("{} successfully authenticated {}", handlerName, credentials);
|
||||
final Principal p = this.linkedHandlers.get(authenticationHandler).resolvePrincipal(credentials);
|
||||
return new Pair<AuthenticationHandler,Principal>(authenticationHandler, p);
|
||||
}
|
||||
log.info("{} failed to authenticate {}", handlerName, credentials);
|
||||
}
|
||||
|
||||
if (foundOneThatWorks) {
|
||||
throw BadCredentialsAuthenticationException.ERROR;
|
||||
}
|
||||
|
||||
throw UnsupportedCredentialsException.ERROR;
|
||||
}
|
||||
}
|
@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Licensed to Jasig under one or more contributor license
|
||||
* agreements. See the NOTICE file distributed with this work
|
||||
* for additional information regarding copyright ownership.
|
||||
* Jasig licenses this file to you under the Apache License,
|
||||
* Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a
|
||||
* copy of the License at the following location:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.jasig.cas.authentication;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
|
||||
import org.jasig.cas.authentication.principal.Principal;
|
||||
|
||||
/**
|
||||
* Mutable implementation of Authentication interface.
|
||||
* <p>
|
||||
* Instanciators of the MutableAuthentication class must take care that the map
|
||||
* they provide is serializable (i.e. HashMap).
|
||||
*
|
||||
* @author Scott Battaglia
|
||||
* @version $Revision$ $Date$
|
||||
* @since 3.0.3
|
||||
*/
|
||||
public final class MutableAuthentication extends AbstractAuthentication {
|
||||
|
||||
/** Unique Id for serialization. */
|
||||
private static final long serialVersionUID = -4415875344376642246L;
|
||||
|
||||
/** The date/time this authentication object became valid. */
|
||||
private final Date authenticatedDate;
|
||||
|
||||
public MutableAuthentication(final Principal principal) {
|
||||
this(principal, new Date());
|
||||
}
|
||||
|
||||
public MutableAuthentication(final Principal principal, final Date date) {
|
||||
super(principal, new HashMap<String, Object>());
|
||||
this.authenticatedDate = date;
|
||||
}
|
||||
|
||||
public Date getAuthenticatedDate() {
|
||||
return this.authenticatedDate;
|
||||
}
|
||||
}
|
@ -0,0 +1,94 @@
|
||||
/*
|
||||
* Licensed to Jasig under one or more contributor license
|
||||
* agreements. See the NOTICE file distributed with this work
|
||||
* for additional information regarding copyright ownership.
|
||||
* Jasig licenses this file to you under the Apache License,
|
||||
* Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a
|
||||
* copy of the License at the following location:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.jasig.cas.authentication;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.jasig.cas.authentication.principal.Credentials;
|
||||
import org.jasig.cas.authentication.principal.HttpBasedServiceCredentials;
|
||||
import org.jasig.cas.authentication.principal.UsernamePasswordCredentials;
|
||||
|
||||
/**
|
||||
* AuthenticationMetaDataPopulator to retrieve the Authentication Type.
|
||||
* <p>
|
||||
* Note: Authentication Methods are exposed under the key:
|
||||
* <code>samlAuthenticationStatement::authMethod</code> in the Authentication
|
||||
* attributes map.
|
||||
*
|
||||
* @author Scott Battaglia
|
||||
* @version $Revision$ $Date$
|
||||
* @since 3.1
|
||||
*/
|
||||
public class SamlAuthenticationMetaDataPopulator implements
|
||||
AuthenticationMetaDataPopulator {
|
||||
|
||||
public static final String ATTRIBUTE_AUTHENTICATION_METHOD = "samlAuthenticationStatementAuthMethod";
|
||||
|
||||
public static final String AUTHN_METHOD_PASSWORD = "urn:oasis:names:tc:SAML:1.0:am:password";
|
||||
|
||||
public static final String AUTHN_METHOD_SSL_TLS_CLIENT = "urn:ietf:rfc:2246";
|
||||
|
||||
public static final String AUTHN_METHOD_X509_PUBLICKEY = "urn:oasis:names:tc:SAML:1.0:am:X509-PKI";
|
||||
|
||||
public static final String AUTHN_METHOD_UNSPECIFIED = "urn:oasis:names:tc:SAML:1.0:am:unspecified";
|
||||
|
||||
private final Map<String, String> authenticationMethods = new HashMap<String, String>();
|
||||
|
||||
public SamlAuthenticationMetaDataPopulator() {
|
||||
this.authenticationMethods.put(
|
||||
HttpBasedServiceCredentials.class.getName(),
|
||||
AUTHN_METHOD_SSL_TLS_CLIENT);
|
||||
this.authenticationMethods.put(
|
||||
UsernamePasswordCredentials.class.getName(),
|
||||
AUTHN_METHOD_PASSWORD);
|
||||
|
||||
// Next two classes are in other modules, so avoid using Class#getName() to prevent circular dependency
|
||||
this.authenticationMethods.put(
|
||||
"org.jasig.cas.adaptors.trusted.authentication.principal.PrincipalBearingCredentials",
|
||||
AUTHN_METHOD_UNSPECIFIED);
|
||||
this.authenticationMethods.put(
|
||||
"org.jasig.cas.adaptors.x509.authentication.principal.X509CertificateCredentials",
|
||||
AUTHN_METHOD_X509_PUBLICKEY);
|
||||
}
|
||||
|
||||
public final Authentication populateAttributes(final Authentication authentication, final Credentials credentials) {
|
||||
|
||||
final String credentialsClass = credentials.getClass().getName();
|
||||
final String authenticationMethod = this.authenticationMethods.get(credentialsClass);
|
||||
|
||||
authentication.getAttributes().put(ATTRIBUTE_AUTHENTICATION_METHOD, authenticationMethod);
|
||||
|
||||
return authentication;
|
||||
}
|
||||
|
||||
/**
|
||||
* Map of user-defined mappings. Note it is possible to over-ride the
|
||||
* defaults. Mapping should be of the following type:
|
||||
* <p>(<String version of Package/Class Name> <SAML Type>)
|
||||
* <p>
|
||||
* Example: (<"org.jasig.cas.authentication.principal.HttpBasedServiceCredentials">
|
||||
* <SAMLAuthenticationStatement.AuthenticationMethod_SSL_TLS_Client>)
|
||||
*
|
||||
* @param userDefinedMappings map of user defined authentication types.
|
||||
*/
|
||||
public void setUserDefinedMappings(final Map<String, String> userDefinedMappings) {
|
||||
this.authenticationMethods.putAll(userDefinedMappings);
|
||||
}
|
||||
}
|
@ -0,0 +1,120 @@
|
||||
/*
|
||||
* Licensed to Jasig under one or more contributor license
|
||||
* agreements. See the NOTICE file distributed with this work
|
||||
* for additional information regarding copyright ownership.
|
||||
* Jasig licenses this file to you under the Apache License,
|
||||
* Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a
|
||||
* copy of the License at the following location:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.jasig.cas.authentication.handler;
|
||||
|
||||
/**
|
||||
* The most generic type of authentication exception that one can catch if not
|
||||
* sure what specific implementation will be thrown. Top of the tree of all
|
||||
* other AuthenticationExceptions.
|
||||
*
|
||||
* @author Scott Battaglia
|
||||
* @version $Revision$ $Date$
|
||||
* @since 3.0
|
||||
*/
|
||||
public abstract class AuthenticationException extends Exception {
|
||||
|
||||
/** Serializable ID. */
|
||||
private static final long serialVersionUID = 3906648604830611762L;
|
||||
|
||||
/** The code to return for resolving to a message description. */
|
||||
private String code;
|
||||
|
||||
/** The error type that provides additional info about the nature of the exception cause **/
|
||||
private String type = "error";
|
||||
|
||||
/**
|
||||
* Constructor that takes a code description of the error. These codes
|
||||
* normally have a corresponding entries in the messages file for the
|
||||
* internationalization of error messages.
|
||||
*
|
||||
* @param code The short unique identifier for this error.
|
||||
*/
|
||||
public AuthenticationException(final String code) {
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor that takes a <code>code</code> description of the error along with the exception
|
||||
* <code>msg</code> generally for logging purposes. These codes normally have a corresponding
|
||||
* entries in the messages file for the internationalization of error messages.
|
||||
*
|
||||
* @param code The short unique identifier for this error.
|
||||
* @param msg The error message associated with this exception for additional logging purposes.
|
||||
*/
|
||||
public AuthenticationException(final String code, final String msg) {
|
||||
super(msg);
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor that takes a <code>code</code> description of the error along with the exception
|
||||
* <code>msg</code> generally for logging purposes and the <code>type</code> of the error that originally caused the exception.
|
||||
* These codes normally have a corresponding entries in the messages file for the internationalization of error messages.
|
||||
*
|
||||
* @param code The short unique identifier for this error.
|
||||
* @param msg The error message associated with this exception for additional logging purposes.
|
||||
* @param type The type of the error message that caused the exception to be thrown. By default,
|
||||
* all errors are considered of <code>error</code>.
|
||||
*/
|
||||
public AuthenticationException(final String code, final String msg, final String type) {
|
||||
super(msg);
|
||||
this.code = code;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor that takes a code description of the error and the chained
|
||||
* exception. These codes normally have a corresponding entries in the
|
||||
* messages file for the internationalization of error messages.
|
||||
*
|
||||
* @param code The short unique identifier for this error.
|
||||
* @param throwable The chained exception for this AuthenticationException
|
||||
*/
|
||||
public AuthenticationException(final String code, final Throwable throwable) {
|
||||
super(throwable);
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to return the error type of this exception
|
||||
*
|
||||
* @return the String identifier for the cause of this error.
|
||||
*/
|
||||
public final String getType() {
|
||||
return this.type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to return the unique identifier for this error type.
|
||||
*
|
||||
* @return the String identifier for this error type.
|
||||
*/
|
||||
public final String getCode() {
|
||||
return this.code;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final String toString() {
|
||||
String msg = getCode();
|
||||
if (getMessage() != null && getMessage().trim().length() > 0)
|
||||
msg = ":" + getMessage();
|
||||
return msg;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Licensed to Jasig under one or more contributor license
|
||||
* agreements. See the NOTICE file distributed with this work
|
||||
* for additional information regarding copyright ownership.
|
||||
* Jasig licenses this file to you under the Apache License,
|
||||
* Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a
|
||||
* copy of the License at the following location:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.jasig.cas.authentication.handler;
|
||||
|
||||
import org.jasig.cas.authentication.principal.Credentials;
|
||||
|
||||
/**
|
||||
* Validate Credentials support for AuthenticationManagerImpl.
|
||||
* <p>
|
||||
* Determines that Credentials are valid. Password-based credentials may be
|
||||
* tested against an external LDAP, Kerberos, JDBC source. Certificates may be
|
||||
* checked against a list of CA's and do the usual chain validation.
|
||||
* Implementations must be parameterized with their sources of information.
|
||||
* <p>
|
||||
* Callers to this class should first call supports to determine if the
|
||||
* AuthenticationHandler can authenticate the credentials provided.
|
||||
*
|
||||
* @author Scott Battaglia
|
||||
* @version $Revision$ $Date$
|
||||
* @since 3.0
|
||||
* <p>
|
||||
* This is a published and supported CAS Server 3 API.
|
||||
* </p>
|
||||
*/
|
||||
public interface AuthenticationHandler {
|
||||
|
||||
/**
|
||||
* Method to determine if the credentials supplied are valid.
|
||||
*
|
||||
* @param credentials The credentials to validate.
|
||||
* @return true if valid, return false otherwise.
|
||||
* @throws AuthenticationException An AuthenticationException can contain
|
||||
* details about why a particular authentication request failed.
|
||||
*/
|
||||
boolean authenticate(Credentials credentials)
|
||||
throws AuthenticationException;
|
||||
|
||||
/**
|
||||
* Method to check if the handler knows how to handle the credentials
|
||||
* provided. It may be a simple check of the Credentials class or something
|
||||
* more complicated such as scanning the information contained in the
|
||||
* Credentials object.
|
||||
*
|
||||
* @param credentials The credentials to check.
|
||||
* @return true if the handler supports the Credentials, false othewrise.
|
||||
*/
|
||||
boolean supports(Credentials credentials);
|
||||
}
|
@ -0,0 +1,88 @@
|
||||
/*
|
||||
* Licensed to Jasig under one or more contributor license
|
||||
* agreements. See the NOTICE file distributed with this work
|
||||
* for additional information regarding copyright ownership.
|
||||
* Jasig licenses this file to you under the Apache License,
|
||||
* Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a
|
||||
* copy of the License at the following location:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.jasig.cas.authentication.handler;
|
||||
|
||||
/**
|
||||
* Generic Bad Credentials Exception. This can be thrown when the system knows
|
||||
* the credentials are not valid specificially because they are bad. Subclasses
|
||||
* can be specific to a certain type of Credentials
|
||||
* (BadUsernamePassowrdCredentials).
|
||||
*
|
||||
* @author Scott Battaglia
|
||||
* @version $Revision$ $Date$
|
||||
* @since 3.0
|
||||
*/
|
||||
public class BadCredentialsAuthenticationException extends
|
||||
AuthenticationException {
|
||||
|
||||
/**
|
||||
* Static instance of class to prevent cost incurred by creating new
|
||||
* instance.
|
||||
*/
|
||||
public static final BadCredentialsAuthenticationException ERROR = new BadCredentialsAuthenticationException();
|
||||
|
||||
/** UID for serializable objects. */
|
||||
private static final long serialVersionUID = 3256719585087797044L;
|
||||
|
||||
/**
|
||||
* Default constructor that does not allow the chaining of exceptions and
|
||||
* uses the default code as the error code for this exception.
|
||||
*/
|
||||
public static final String CODE = "error.authentication.credentials.bad";
|
||||
|
||||
/**
|
||||
* Default constructor that does not allow the chaining of exceptions and
|
||||
* uses the default code as the error code for this exception.
|
||||
*/
|
||||
public BadCredentialsAuthenticationException() {
|
||||
super(CODE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor to allow for the chaining of exceptions. Constructor defaults
|
||||
* to default code.
|
||||
*
|
||||
* @param throwable the chainable exception.
|
||||
*/
|
||||
public BadCredentialsAuthenticationException(final Throwable throwable) {
|
||||
super(CODE, throwable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor method to allow for providing a custom code to associate with
|
||||
* this exception.
|
||||
*
|
||||
* @param code the code to use.
|
||||
*/
|
||||
public BadCredentialsAuthenticationException(final String code) {
|
||||
super(code);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor to allow for the chaining of exceptions and use of a
|
||||
* non-default code.
|
||||
*
|
||||
* @param code the user-specified code.
|
||||
* @param throwable the chainable exception.
|
||||
*/
|
||||
public BadCredentialsAuthenticationException(final String code,
|
||||
final Throwable throwable) {
|
||||
super(code, throwable);
|
||||
}
|
||||
}
|
@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Licensed to Jasig under one or more contributor license
|
||||
* agreements. See the NOTICE file distributed with this work
|
||||
* for additional information regarding copyright ownership.
|
||||
* Jasig licenses this file to you under the Apache License,
|
||||
* Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a
|
||||
* copy of the License at the following location:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.jasig.cas.authentication.handler;
|
||||
|
||||
/**
|
||||
* The exception to throw when we know the username is correct but the password
|
||||
* is not.
|
||||
*
|
||||
* @author Scott Battaglia
|
||||
* @version $Revision$ $Date$
|
||||
* @since 3.0
|
||||
*/
|
||||
public class BadPasswordAuthenticationException extends
|
||||
BadUsernameOrPasswordAuthenticationException {
|
||||
|
||||
/** Static instance of BadPasswordAuthenticationException. */
|
||||
public static final BadPasswordAuthenticationException ERROR = new BadPasswordAuthenticationException();
|
||||
|
||||
/** Unique ID for serializing. */
|
||||
private static final long serialVersionUID = 3977861752513837361L;
|
||||
|
||||
/** The default code for this exception used for message resolving. */
|
||||
private static final String CODE = "error.authentication.credentials.bad.usernameorpassword.password";
|
||||
|
||||
/**
|
||||
* Default constructor that does not allow the chaining of exceptions and
|
||||
* uses the default code as the error code for this exception.
|
||||
*/
|
||||
public BadPasswordAuthenticationException() {
|
||||
super(CODE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor that allows for the chaining of exceptions. Defaults to the
|
||||
* default code provided for this exception.
|
||||
*
|
||||
* @param throwable the chained exception.
|
||||
*/
|
||||
public BadPasswordAuthenticationException(final Throwable throwable) {
|
||||
super(CODE, throwable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor that allows for providing a custom error code for this class.
|
||||
* Error codes are often used to resolve exceptions into messages. Providing
|
||||
* a custom error code allows the use of a different message.
|
||||
*
|
||||
* @param code the custom code to use with this exception.
|
||||
*/
|
||||
public BadPasswordAuthenticationException(final String code) {
|
||||
super(code);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor that allows for chaining of exceptions and a custom error
|
||||
* code.
|
||||
*
|
||||
* @param code the custom error code to use in message resolving.
|
||||
* @param throwable the chained exception.
|
||||
*/
|
||||
public BadPasswordAuthenticationException(final String code,
|
||||
final Throwable throwable) {
|
||||
super(code, throwable);
|
||||
}
|
||||
}
|
@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Licensed to Jasig under one or more contributor license
|
||||
* agreements. See the NOTICE file distributed with this work
|
||||
* for additional information regarding copyright ownership.
|
||||
* Jasig licenses this file to you under the Apache License,
|
||||
* Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a
|
||||
* copy of the License at the following location:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.jasig.cas.authentication.handler;
|
||||
|
||||
/**
|
||||
* Exception to throw when we know the credentials provided were
|
||||
* username/password and the combination is wrong.
|
||||
*
|
||||
* @author Scott Battaglia
|
||||
* @version $Revision$ $Date$
|
||||
* @since 3.0
|
||||
*/
|
||||
public class BadUsernameOrPasswordAuthenticationException extends
|
||||
BadCredentialsAuthenticationException {
|
||||
|
||||
/** Static instance of BadUsernameOrPasswordAuthenticationException. */
|
||||
public static final BadUsernameOrPasswordAuthenticationException ERROR = new BadUsernameOrPasswordAuthenticationException();
|
||||
|
||||
/** Unique ID for serializing. */
|
||||
private static final long serialVersionUID = 3977861752513837361L;
|
||||
|
||||
/** The default code for this exception used for message resolving. */
|
||||
private static final String CODE = "error.authentication.credentials.bad.usernameorpassword";
|
||||
|
||||
/**
|
||||
* Default constructor that does not allow the chaining of exceptions and
|
||||
* uses the default code as the error code for this exception.
|
||||
*/
|
||||
public BadUsernameOrPasswordAuthenticationException() {
|
||||
super(CODE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor that allows for the chaining of exceptions. Defaults to the
|
||||
* default code provided for this exception.
|
||||
*
|
||||
* @param throwable the chained exception.
|
||||
*/
|
||||
public BadUsernameOrPasswordAuthenticationException(
|
||||
final Throwable throwable) {
|
||||
super(CODE, throwable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor that allows for providing a custom error code for this class.
|
||||
* Error codes are often used to resolve exceptions into messages. Providing
|
||||
* a custom error code allows the use of a different message.
|
||||
*
|
||||
* @param code the custom code to use with this exception.
|
||||
*/
|
||||
public BadUsernameOrPasswordAuthenticationException(final String code) {
|
||||
super(code);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor that allows for chaining of exceptions and a custom error
|
||||
* code.
|
||||
*
|
||||
* @param code the custom error code to use in message resolving.
|
||||
* @param throwable the chained exception.
|
||||
*/
|
||||
public BadUsernameOrPasswordAuthenticationException(final String code,
|
||||
final Throwable throwable) {
|
||||
super(code, throwable);
|
||||
}
|
||||
}
|
@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Licensed to Jasig under one or more contributor license
|
||||
* agreements. See the NOTICE file distributed with this work
|
||||
* for additional information regarding copyright ownership.
|
||||
* Jasig licenses this file to you under the Apache License,
|
||||
* Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a
|
||||
* copy of the License at the following location:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.jasig.cas.authentication.handler;
|
||||
|
||||
/**
|
||||
* Exception to represent credentials that have been blocked for a reason such
|
||||
* as Locked account.
|
||||
*
|
||||
* @author Scott Battaglia
|
||||
* @version $Revision$ $Date$
|
||||
* @since 3.0
|
||||
*/
|
||||
public class BlockedCredentialsAuthenticationException extends
|
||||
AuthenticationException {
|
||||
|
||||
/** Static instance of BlockedCredentialsAuthenticationException. */
|
||||
public static final BlockedCredentialsAuthenticationException ERROR = new BlockedCredentialsAuthenticationException();
|
||||
|
||||
/** Unique ID for serialization. */
|
||||
private static final long serialVersionUID = 3544669598642420017L;
|
||||
|
||||
/** The default code for this exception used for message resolving. */
|
||||
private static final String CODE = "error.authentication.credentials.blocked";
|
||||
|
||||
/**
|
||||
* Default constructor that does not allow the chaining of exceptions and
|
||||
* uses the default code as the error code for this exception.
|
||||
*/
|
||||
public BlockedCredentialsAuthenticationException() {
|
||||
super(CODE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor that allows for the chaining of exceptions. Defaults to the
|
||||
* default code provided for this exception.
|
||||
*
|
||||
* @param throwable the chained exception.
|
||||
*/
|
||||
public BlockedCredentialsAuthenticationException(final Throwable throwable) {
|
||||
super(CODE, throwable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor that allows for providing a custom error code for this class.
|
||||
* Error codes are often used to resolve exceptions into messages. Providing
|
||||
* a custom error code allows the use of a different message.
|
||||
*
|
||||
* @param code the custom code to use with this exception.
|
||||
*/
|
||||
public BlockedCredentialsAuthenticationException(final String code) {
|
||||
super(code);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor that allows for chaining of exceptions and a custom error
|
||||
* code.
|
||||
*
|
||||
* @param code the custom error code to use in message resolving.
|
||||
* @param throwable the chained exception.
|
||||
*/
|
||||
public BlockedCredentialsAuthenticationException(final String code,
|
||||
final Throwable throwable) {
|
||||
super(code, throwable);
|
||||
}
|
||||
}
|
@ -0,0 +1,96 @@
|
||||
/*
|
||||
* Licensed to Jasig under one or more contributor license
|
||||
* agreements. See the NOTICE file distributed with this work
|
||||
* for additional information regarding copyright ownership.
|
||||
* Jasig licenses this file to you under the Apache License,
|
||||
* Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a
|
||||
* copy of the License at the following location:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.jasig.cas.authentication.handler;
|
||||
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
|
||||
/**
|
||||
* Implementation of PasswordEncoder using message digest. Can accept any
|
||||
* message digest that the JDK can accept, including MD5 and SHA1. Returns the
|
||||
* equivalent Hash you would get from a Perl digest.
|
||||
*
|
||||
* @author Scott Battaglia
|
||||
* @author Stephen More
|
||||
* @version $Revision$ $Date$
|
||||
* @since 3.1
|
||||
*/
|
||||
public final class DefaultPasswordEncoder implements PasswordEncoder {
|
||||
|
||||
private static final char[] HEX_DIGITS = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
|
||||
|
||||
@NotNull
|
||||
private final String encodingAlgorithm;
|
||||
|
||||
private String characterEncoding;
|
||||
|
||||
public DefaultPasswordEncoder(final String encodingAlgorithm) {
|
||||
this.encodingAlgorithm = encodingAlgorithm;
|
||||
}
|
||||
|
||||
public String encode(final String password) {
|
||||
if (password == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
MessageDigest messageDigest = MessageDigest
|
||||
.getInstance(this.encodingAlgorithm);
|
||||
|
||||
if (StringUtils.hasText(this.characterEncoding)) {
|
||||
messageDigest.update(password.getBytes(this.characterEncoding));
|
||||
} else {
|
||||
messageDigest.update(password.getBytes());
|
||||
}
|
||||
|
||||
|
||||
final byte[] digest = messageDigest.digest();
|
||||
|
||||
return getFormattedText(digest);
|
||||
} catch (final NoSuchAlgorithmException e) {
|
||||
throw new SecurityException(e);
|
||||
} catch (final UnsupportedEncodingException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes the raw bytes from the digest and formats them correct.
|
||||
*
|
||||
* @param bytes the raw bytes from the digest.
|
||||
* @return the formatted bytes.
|
||||
*/
|
||||
private String getFormattedText(byte[] bytes) {
|
||||
final StringBuilder buf = new StringBuilder(bytes.length * 2);
|
||||
|
||||
for (int j = 0; j < bytes.length; j++) {
|
||||
buf.append(HEX_DIGITS[(bytes[j] >> 4) & 0x0f]);
|
||||
buf.append(HEX_DIGITS[bytes[j] & 0x0f]);
|
||||
}
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
public final void setCharacterEncoding(final String characterEncoding) {
|
||||
this.characterEncoding = characterEncoding;
|
||||
}
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Licensed to Jasig under one or more contributor license
|
||||
* agreements. See the NOTICE file distributed with this work
|
||||
* for additional information regarding copyright ownership.
|
||||
* Jasig licenses this file to you under the Apache License,
|
||||
* Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a
|
||||
* copy of the License at the following location:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.jasig.cas.authentication.handler;
|
||||
|
||||
/**
|
||||
* Offers AuthenticationHandlers a way to identify themselves by a
|
||||
* user-configured name.
|
||||
*
|
||||
* @author Scott Battaglia
|
||||
* @version $Revision: 1.1 $ $Date: 2005/08/19 18:27:17 $
|
||||
* @since 3.2.1
|
||||
*
|
||||
*/
|
||||
public interface NamedAuthenticationHandler extends AuthenticationHandler {
|
||||
|
||||
String getName();
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Licensed to Jasig under one or more contributor license
|
||||
* agreements. See the NOTICE file distributed with this work
|
||||
* for additional information regarding copyright ownership.
|
||||
* Jasig licenses this file to you under the Apache License,
|
||||
* Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a
|
||||
* copy of the License at the following location:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.jasig.cas.authentication.handler;
|
||||
|
||||
/**
|
||||
* Simple implementation that actually does NO transformation.
|
||||
*
|
||||
* @author Scott Battaglia
|
||||
* @version $Revision$ $Date$
|
||||
* @since 3.3.6
|
||||
*/
|
||||
public final class NoOpPrincipalNameTransformer implements PrincipalNameTransformer {
|
||||
|
||||
public String transform(final String formUserId) {
|
||||
return formUserId;
|
||||
}
|
||||
}
|
@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Licensed to Jasig under one or more contributor license
|
||||
* agreements. See the NOTICE file distributed with this work
|
||||
* for additional information regarding copyright ownership.
|
||||
* Jasig licenses this file to you under the Apache License,
|
||||
* Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a
|
||||
* copy of the License at the following location:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.jasig.cas.authentication.handler;
|
||||
|
||||
/**
|
||||
* Interface to provide a standard way to translate a plaintext password into a
|
||||
* different representation of that password so that the password may be
|
||||
* compared with the stored encrypted password without having to decode the
|
||||
* encrypted password.
|
||||
* <p>
|
||||
* PasswordEncoders are useful because often the stored passwords are encoded
|
||||
* with a one way hash function which makes them almost impossible to decode.
|
||||
*
|
||||
* @author Scott Battaglia
|
||||
* @version $Revision$ $Date$
|
||||
* @since 3.0
|
||||
* <p>
|
||||
* This is a published and supported CAS Server 3 API.
|
||||
* </p>
|
||||
*/
|
||||
public interface PasswordEncoder {
|
||||
|
||||
/**
|
||||
* Method that actually performs the transformation of the plaintext
|
||||
* password into the encrypted password.
|
||||
*
|
||||
* @param password the password to translate
|
||||
* @return the transformed version of the password
|
||||
*/
|
||||
String encode(String password);
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Licensed to Jasig under one or more contributor license
|
||||
* agreements. See the NOTICE file distributed with this work
|
||||
* for additional information regarding copyright ownership.
|
||||
* Jasig licenses this file to you under the Apache License,
|
||||
* Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a
|
||||
* copy of the License at the following location:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.jasig.cas.authentication.handler;
|
||||
|
||||
/**
|
||||
* Default password encoder for the case where no password encoder is needed.
|
||||
* Encoding results in the same password that was passed in.
|
||||
*
|
||||
* @author Scott Battaglia
|
||||
* @version $Revision$ $Date$
|
||||
* @since 3.0
|
||||
*/
|
||||
public final class PlainTextPasswordEncoder implements PasswordEncoder {
|
||||
|
||||
public String encode(final String password) {
|
||||
return password;
|
||||
}
|
||||
}
|
@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Licensed to Jasig under one or more contributor license
|
||||
* agreements. See the NOTICE file distributed with this work
|
||||
* for additional information regarding copyright ownership.
|
||||
* Jasig licenses this file to you under the Apache License,
|
||||
* Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a
|
||||
* copy of the License at the following location:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
package org.jasig.cas.authentication.handler;
|
||||
|
||||
/**
|
||||
* Transform the user id by adding a prefix or suffix.
|
||||
*
|
||||
* @author Howard Gilbert
|
||||
* @author Scott Battaglia
|
||||
* @version $Revision$ $Date$
|
||||
* @since 3.3.6
|
||||
*/
|
||||
|
||||
public final class PrefixSuffixPrincipalNameTransformer implements PrincipalNameTransformer {
|
||||
|
||||
private String prefix;
|
||||
|
||||
private String suffix;
|
||||
|
||||
public String transform(final String formUserId) {
|
||||
final StringBuilder stringBuilder = new StringBuilder();
|
||||
|
||||
if (this.prefix != null) {
|
||||
stringBuilder.append(this.prefix);
|
||||
}
|
||||
|
||||
stringBuilder.append(formUserId);
|
||||
|
||||
if (this.suffix != null) {
|
||||
stringBuilder.append(this.suffix);
|
||||
}
|
||||
|
||||
return stringBuilder.toString();
|
||||
}
|
||||
|
||||
public void setPrefix(final String prefix) {
|
||||
this.prefix = prefix;
|
||||
}
|
||||
|
||||
public void setSuffix(final String suffix) {
|
||||
this.suffix = suffix;
|
||||
}
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Licensed to Jasig under one or more contributor license
|
||||
* agreements. See the NOTICE file distributed with this work
|
||||
* for additional information regarding copyright ownership.
|
||||
* Jasig licenses this file to you under the Apache License,
|
||||
* Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a
|
||||
* copy of the License at the following location:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.jasig.cas.authentication.handler;
|
||||
|
||||
|
||||
/**
|
||||
* @author Howard Gilbert
|
||||
* @version $Revision$ $Date$
|
||||
* @since 3.3.6
|
||||
*/
|
||||
public interface PrincipalNameTransformer {
|
||||
|
||||
/**
|
||||
* Transform the string typed into the login form into a tentative Principal Name to be
|
||||
* validated by a specific type of Authentication Handler.
|
||||
*
|
||||
* <p>The Principal Name eventually assigned by the CredentialsToPrincipalResolver may
|
||||
* be unqualified ("AENewman"). However, validation of the Principal name against a
|
||||
* particular backend source represented by a particular Authentication Handler may
|
||||
* require transformation to a temporary fully qualified format such as
|
||||
* AENewman@MAD.DCCOMICS.COM or MAD\AENewman. After validation, this form of the
|
||||
* Principal name is discarded in favor of the choice made by the Resolver.
|
||||
*
|
||||
* @param formUserId The raw userid typed into the login form
|
||||
* @return the string that the Authentication Handler should lookup in the backend system
|
||||
*/
|
||||
public String transform(String formUserId);
|
||||
}
|
||||
|
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Licensed to Jasig under one or more contributor license
|
||||
* agreements. See the NOTICE file distributed with this work
|
||||
* for additional information regarding copyright ownership.
|
||||
* Jasig licenses this file to you under the Apache License,
|
||||
* Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a
|
||||
* copy of the License at the following location:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.jasig.cas.authentication.handler;
|
||||
|
||||
/**
|
||||
* Generic abstract exception to extend when you don't know what the heck is
|
||||
* going on.
|
||||
*
|
||||
* @author Scott Battaglia
|
||||
* @version $Revision$ $Date$
|
||||
* @since 3.0
|
||||
*/
|
||||
public abstract class UncategorizedAuthenticationException extends
|
||||
AuthenticationException {
|
||||
|
||||
/**
|
||||
* Constructor that allows for providing a custom error code for this class.
|
||||
* Error codes are often used to resolve exceptions into messages. Providing
|
||||
* a custom error code allows the use of a different message.
|
||||
*
|
||||
* @param code the custom code to use with this exception.
|
||||
*/
|
||||
public UncategorizedAuthenticationException(final String code) {
|
||||
super(code);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor that allows for chaining of exceptions and a custom error
|
||||
* code.
|
||||
*
|
||||
* @param code the custom error code to use in message resolving.
|
||||
* @param throwable the chained exception.
|
||||
*/
|
||||
public UncategorizedAuthenticationException(final String code,
|
||||
final Throwable throwable) {
|
||||
super(code, throwable);
|
||||
}
|
||||
}
|
@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Licensed to Jasig under one or more contributor license
|
||||
* agreements. See the NOTICE file distributed with this work
|
||||
* for additional information regarding copyright ownership.
|
||||
* Jasig licenses this file to you under the Apache License,
|
||||
* Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a
|
||||
* copy of the License at the following location:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.jasig.cas.authentication.handler;
|
||||
|
||||
/**
|
||||
* The exception to throw when we explicitly don't know anything about the
|
||||
* username.
|
||||
*
|
||||
* @author Scott Battaglia
|
||||
* @version $Revision$ $Date$
|
||||
* @since 3.0
|
||||
*/
|
||||
public class UnknownUsernameAuthenticationException extends
|
||||
BadUsernameOrPasswordAuthenticationException {
|
||||
|
||||
/** Static instance of UnknownUsernameAuthenticationException. */
|
||||
public static final UnknownUsernameAuthenticationException ERROR = new UnknownUsernameAuthenticationException();
|
||||
|
||||
/** Unique ID for serializing. */
|
||||
private static final long serialVersionUID = 3977861752513837361L;
|
||||
|
||||
/** The code description of this exception. */
|
||||
private static final String CODE = "error.authentication.credentials.bad.usernameorpassword.username";
|
||||
|
||||
/**
|
||||
* Default constructor that does not allow the chaining of exceptions and
|
||||
* uses the default code as the error code for this exception.
|
||||
*/
|
||||
public UnknownUsernameAuthenticationException() {
|
||||
super(CODE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor that allows for the chaining of exceptions. Defaults to the
|
||||
* default code provided for this exception.
|
||||
*
|
||||
* @param throwable the chained exception.
|
||||
*/
|
||||
public UnknownUsernameAuthenticationException(final Throwable throwable) {
|
||||
super(CODE, throwable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor that allows for providing a custom error code for this class.
|
||||
* Error codes are often used to resolve exceptions into messages. Providing
|
||||
* a custom error code allows the use of a different message.
|
||||
*
|
||||
* @param code the custom code to use with this exception.
|
||||
*/
|
||||
public UnknownUsernameAuthenticationException(final String code) {
|
||||
super(code);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor that allows for chaining of exceptions and a custom error
|
||||
* code.
|
||||
*
|
||||
* @param code the custom error code to use in message resolving.
|
||||
* @param throwable the chained exception.
|
||||
*/
|
||||
public UnknownUsernameAuthenticationException(final String code,
|
||||
final Throwable throwable) {
|
||||
super(code, throwable);
|
||||
}
|
||||
}
|
@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Licensed to Jasig under one or more contributor license
|
||||
* agreements. See the NOTICE file distributed with this work
|
||||
* for additional information regarding copyright ownership.
|
||||
* Jasig licenses this file to you under the Apache License,
|
||||
* Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a
|
||||
* copy of the License at the following location:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.jasig.cas.authentication.handler;
|
||||
|
||||
/**
|
||||
* The exception thrown when a Handler does not know how to determine the
|
||||
* validity of the credentials based on the fact that it does not know what to
|
||||
* do with the credentials presented.
|
||||
*
|
||||
* @author Scott Battaglia
|
||||
* @version $Revision$ $Date$
|
||||
* @since 3.0
|
||||
*/
|
||||
public final class UnsupportedCredentialsException extends
|
||||
AuthenticationException {
|
||||
|
||||
/** Static instance of UnsupportedCredentialsException. */
|
||||
public static final UnsupportedCredentialsException ERROR = new UnsupportedCredentialsException();
|
||||
|
||||
/** Unique ID for serializing. */
|
||||
private static final long serialVersionUID = 3977861752513837361L;
|
||||
|
||||
/** The code description of this exception. */
|
||||
private static final String CODE = "error.authentication.credentials.unsupported";
|
||||
|
||||
/**
|
||||
* Default constructor that does not allow the chaining of exceptions and
|
||||
* uses the default code as the error code for this exception.
|
||||
*/
|
||||
public UnsupportedCredentialsException() {
|
||||
super(CODE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor that allows for the chaining of exceptions. Defaults to the
|
||||
* default code provided for this exception.
|
||||
*
|
||||
* @param throwable the chained exception.
|
||||
*/
|
||||
public UnsupportedCredentialsException(final Throwable throwable) {
|
||||
super(CODE, throwable);
|
||||
}
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
<!--
|
||||
|
||||
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.
|
||||
|
||||
-->
|
||||
<html>
|
||||
<body>
|
||||
The handler package contains the classes used to authenticate a user. It contains
|
||||
the AuthenticationHandler interface which is used to validate credentials. It also
|
||||
contains the PasswordEncoders which are used by implementations of the AuthenticationHandler
|
||||
to provide conversion from plain text to whatever the password is encoded as in the data
|
||||
store.
|
||||
<p>
|
||||
The package also contains a well-defined exception heirarchy to allow fine-grained error
|
||||
messages to be displayed.
|
||||
<p>
|
||||
Examples of AuthenticationHandlers implementations:
|
||||
<ul>
|
||||
<li>If the credentials are a Userid and Password, then it submits them to an
|
||||
external Kerberos, LDAP, or JDBC authority for validation.</li>
|
||||
<li>If the credentials are a Certificate, then it verifies the Issuer chain
|
||||
against some list of reliable CAs, checks the date to make sure it hasn't
|
||||
expired, and checks the CRL to make sure it wasn't revoked.</li>
|
||||
<li>If authentication has been done by the Servlet Container or by a Filter, then
|
||||
the Credentials have been extracted from the HttpRequest object. Notably, this
|
||||
will include the REMOTE_USER. Such Credentials are implicitly trusted and self
|
||||
validating, so an AuthenticationHandler recognizing such an object will indicate
|
||||
that it is valid without inspecting its contents.</li>
|
||||
</ul>
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,92 @@
|
||||
/*
|
||||
* Licensed to Jasig under one or more contributor license
|
||||
* agreements. See the NOTICE file distributed with this work
|
||||
* for additional information regarding copyright ownership.
|
||||
* Jasig licenses this file to you under the Apache License,
|
||||
* Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a
|
||||
* copy of the License at the following location:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.jasig.cas.authentication.handler.support;
|
||||
|
||||
import org.jasig.cas.authentication.handler.AuthenticationException;
|
||||
import org.jasig.cas.authentication.handler.NamedAuthenticationHandler;
|
||||
import org.jasig.cas.authentication.principal.Credentials;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
/**
|
||||
* Abstract authentication handler that allows deployers to utilize the bundled
|
||||
* AuthenticationHandlers while providing a mechanism to perform tasks before
|
||||
* and after authentication.
|
||||
*
|
||||
* @author Scott Battaglia
|
||||
* @version $Revision$ $Date$
|
||||
* @since 3.1
|
||||
*/
|
||||
public abstract class AbstractPreAndPostProcessingAuthenticationHandler
|
||||
implements NamedAuthenticationHandler {
|
||||
|
||||
/** Instance of logging for subclasses. */
|
||||
protected Logger log = LoggerFactory.getLogger(this.getClass());
|
||||
|
||||
/** The name of the authentication handler. */
|
||||
@NotNull
|
||||
private String name = getClass().getName();
|
||||
|
||||
/**
|
||||
* Method to execute before authentication occurs.
|
||||
*
|
||||
* @param credentials the Credentials supplied
|
||||
* @return true if authentication should continue, false otherwise.
|
||||
*/
|
||||
protected boolean preAuthenticate(final Credentials credentials) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to execute after authentication occurs.
|
||||
*
|
||||
* @param credentials the supplied credentials
|
||||
* @param authenticated the result of the authentication attempt.
|
||||
* @return true if the handler should return true, false otherwise.
|
||||
*/
|
||||
protected boolean postAuthenticate(final Credentials credentials,
|
||||
final boolean authenticated) {
|
||||
return authenticated;
|
||||
}
|
||||
|
||||
public final void setName(final String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public final String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
public final boolean authenticate(final Credentials credentials)
|
||||
throws AuthenticationException {
|
||||
|
||||
if (!preAuthenticate(credentials)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final boolean authenticated = doAuthentication(credentials);
|
||||
|
||||
return postAuthenticate(credentials, authenticated);
|
||||
}
|
||||
|
||||
protected abstract boolean doAuthentication(final Credentials credentials)
|
||||
throws AuthenticationException;
|
||||
}
|
@ -0,0 +1,144 @@
|
||||
/*
|
||||
* Licensed to Jasig under one or more contributor license
|
||||
* agreements. See the NOTICE file distributed with this work
|
||||
* for additional information regarding copyright ownership.
|
||||
* Jasig licenses this file to you under the Apache License,
|
||||
* Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a
|
||||
* copy of the License at the following location:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.jasig.cas.authentication.handler.support;
|
||||
|
||||
import org.jasig.cas.authentication.handler.*;
|
||||
import org.jasig.cas.authentication.principal.Credentials;
|
||||
import org.jasig.cas.authentication.principal.UsernamePasswordCredentials;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
/**
|
||||
* Abstract class to override supports so that we don't need to duplicate the
|
||||
* check for UsernamePasswordCredentials.
|
||||
*
|
||||
* @author Scott Battaglia
|
||||
* @version $Revision$ $Date$
|
||||
* @since 3.0
|
||||
* <p>
|
||||
* This is a published and supported CAS Server 3 API.
|
||||
* </p>
|
||||
*/
|
||||
public abstract class AbstractUsernamePasswordAuthenticationHandler extends
|
||||
AbstractPreAndPostProcessingAuthenticationHandler {
|
||||
|
||||
/** Default class to support if one is not supplied. */
|
||||
private static final Class<UsernamePasswordCredentials> DEFAULT_CLASS = UsernamePasswordCredentials.class;
|
||||
|
||||
/** Class that this instance will support. */
|
||||
@NotNull
|
||||
private Class< ? > classToSupport = DEFAULT_CLASS;
|
||||
|
||||
/**
|
||||
* Boolean to determine whether to support subclasses of the class to
|
||||
* support.
|
||||
*/
|
||||
private boolean supportSubClasses = true;
|
||||
|
||||
/**
|
||||
* PasswordEncoder to be used by subclasses to encode passwords for
|
||||
* comparing against a resource.
|
||||
*/
|
||||
@NotNull
|
||||
private PasswordEncoder passwordEncoder = new PlainTextPasswordEncoder();
|
||||
|
||||
@NotNull
|
||||
private PrincipalNameTransformer principalNameTransformer = new NoOpPrincipalNameTransformer();
|
||||
|
||||
/**
|
||||
* Method automatically handles conversion to UsernamePasswordCredentials
|
||||
* and delegates to abstract authenticateUsernamePasswordInternal so
|
||||
* subclasses do not need to cast.
|
||||
*/
|
||||
protected final boolean doAuthentication(final Credentials credentials)
|
||||
throws AuthenticationException {
|
||||
return authenticateUsernamePasswordInternal((UsernamePasswordCredentials) credentials);
|
||||
}
|
||||
|
||||
/**
|
||||
* Abstract convenience method that assumes the credentials passed in are a
|
||||
* subclass of UsernamePasswordCredentials.
|
||||
*
|
||||
* @param credentials the credentials representing the Username and Password
|
||||
* presented to CAS
|
||||
* @return true if the credentials are authentic, false otherwise.
|
||||
* @throws AuthenticationException if authenticity cannot be determined.
|
||||
*/
|
||||
protected abstract boolean authenticateUsernamePasswordInternal(
|
||||
final UsernamePasswordCredentials credentials)
|
||||
throws AuthenticationException;
|
||||
|
||||
/**
|
||||
* Method to return the PasswordEncoder to be used to encode passwords.
|
||||
*
|
||||
* @return the PasswordEncoder associated with this class.
|
||||
*/
|
||||
protected final PasswordEncoder getPasswordEncoder() {
|
||||
return this.passwordEncoder;
|
||||
}
|
||||
|
||||
protected final PrincipalNameTransformer getPrincipalNameTransformer() {
|
||||
return this.principalNameTransformer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to set the class to support.
|
||||
*
|
||||
* @param classToSupport the class we want this handler to support
|
||||
* explicitly.
|
||||
*/
|
||||
public final void setClassToSupport(final Class< ? > classToSupport) {
|
||||
this.classToSupport = classToSupport;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to set whether this handler will support subclasses of the
|
||||
* supported class.
|
||||
*
|
||||
* @param supportSubClasses boolean of whether to support subclasses or not.
|
||||
*/
|
||||
public final void setSupportSubClasses(final boolean supportSubClasses) {
|
||||
this.supportSubClasses = supportSubClasses;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the PasswordEncoder to be used with this class.
|
||||
*
|
||||
* @param passwordEncoder the PasswordEncoder to use when encoding
|
||||
* passwords.
|
||||
*/
|
||||
public final void setPasswordEncoder(final PasswordEncoder passwordEncoder) {
|
||||
this.passwordEncoder = passwordEncoder;
|
||||
}
|
||||
|
||||
public final void setPrincipalNameTransformer(final PrincipalNameTransformer principalNameTransformer) {
|
||||
this.principalNameTransformer = principalNameTransformer;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if the credentials are not null and the credentials class is
|
||||
* equal to the class defined in classToSupport.
|
||||
*/
|
||||
public final boolean supports(final Credentials credentials) {
|
||||
return credentials != null
|
||||
&& (this.classToSupport.equals(credentials.getClass()) || (this.classToSupport
|
||||
.isAssignableFrom(credentials.getClass()))
|
||||
&& this.supportSubClasses);
|
||||
}
|
||||
}
|
@ -0,0 +1,99 @@
|
||||
/*
|
||||
* Licensed to Jasig under one or more contributor license
|
||||
* agreements. See the NOTICE file distributed with this work
|
||||
* for additional information regarding copyright ownership.
|
||||
* Jasig licenses this file to you under the Apache License,
|
||||
* Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a
|
||||
* copy of the License at the following location:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.jasig.cas.authentication.handler.support;
|
||||
|
||||
import org.jasig.cas.authentication.handler.AuthenticationHandler;
|
||||
import org.jasig.cas.authentication.principal.Credentials;
|
||||
import org.jasig.cas.authentication.principal.HttpBasedServiceCredentials;
|
||||
import org.jasig.cas.util.HttpClient;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
/**
|
||||
* Class to validate the credentials presented by communicating with the web
|
||||
* server and checking the certificate that is returned against the hostname,
|
||||
* etc.
|
||||
* <p>
|
||||
* This class is concerned with ensuring that the protocol is HTTPS and that a
|
||||
* response is returned. The SSL handshake that occurs automatically by opening
|
||||
* a connection does the heavy process of authenticating.
|
||||
*
|
||||
* @author Scott Battaglia
|
||||
* @version $Revision$ $Date$
|
||||
* @since 3.0
|
||||
*/
|
||||
public final class HttpBasedServiceCredentialsAuthenticationHandler implements AuthenticationHandler {
|
||||
|
||||
/** The string representing the HTTPS protocol. */
|
||||
private static final String PROTOCOL_HTTPS = "https";
|
||||
|
||||
/** Boolean variable denoting whether secure connection is required or not. */
|
||||
private boolean requireSecure = true;
|
||||
|
||||
/** Log instance. */
|
||||
private final Logger log = LoggerFactory.getLogger(getClass());
|
||||
|
||||
/** Instance of Apache Commons HttpClient */
|
||||
@NotNull
|
||||
private HttpClient httpClient;
|
||||
|
||||
public boolean authenticate(final Credentials credentials) {
|
||||
final HttpBasedServiceCredentials serviceCredentials = (HttpBasedServiceCredentials) credentials;
|
||||
if (this.requireSecure
|
||||
&& !serviceCredentials.getCallbackUrl().getProtocol().equals(
|
||||
PROTOCOL_HTTPS)) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Authentication failed because url was not secure.");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
log
|
||||
.debug("Attempting to resolve credentials for "
|
||||
+ serviceCredentials);
|
||||
|
||||
return this.httpClient.isValidEndPoint(serviceCredentials
|
||||
.getCallbackUrl());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if the credentials provided are not null and the credentials
|
||||
* are a subclass of (or equal to) HttpBasedServiceCredentials.
|
||||
*/
|
||||
public boolean supports(final Credentials credentials) {
|
||||
return credentials != null
|
||||
&& HttpBasedServiceCredentials.class.isAssignableFrom(credentials
|
||||
.getClass());
|
||||
}
|
||||
|
||||
/** Sets the HttpClient which will do all of the connection stuff. */
|
||||
public void setHttpClient(final HttpClient httpClient) {
|
||||
this.httpClient = httpClient;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether a secure url is required or not.
|
||||
*
|
||||
* @param requireSecure true if its required, false if not. Default is true.
|
||||
*/
|
||||
public void setRequireSecure(final boolean requireSecure) {
|
||||
this.requireSecure = requireSecure;
|
||||
}
|
||||
}
|
@ -0,0 +1,151 @@
|
||||
/*
|
||||
* Licensed to Jasig under one or more contributor license
|
||||
* agreements. See the NOTICE file distributed with this work
|
||||
* for additional information regarding copyright ownership.
|
||||
* Jasig licenses this file to you under the Apache License,
|
||||
* Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a
|
||||
* copy of the License at the following location:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.jasig.cas.authentication.handler.support;
|
||||
|
||||
import javax.security.auth.callback.Callback;
|
||||
import javax.security.auth.callback.CallbackHandler;
|
||||
import javax.security.auth.callback.NameCallback;
|
||||
import javax.security.auth.callback.PasswordCallback;
|
||||
import javax.security.auth.callback.UnsupportedCallbackException;
|
||||
import javax.security.auth.login.Configuration;
|
||||
import javax.security.auth.login.LoginContext;
|
||||
import javax.security.auth.login.LoginException;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
import org.jasig.cas.authentication.handler.AuthenticationException;
|
||||
import org.jasig.cas.authentication.principal.UsernamePasswordCredentials;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* JAAS Authentication Handler for CAAS. This is a simple bridge from CAS'
|
||||
* authentication to JAAS.
|
||||
* <p>
|
||||
* Using the JAAS Authentication Handler requires you to configure the
|
||||
* appropriate JAAS modules. You can specify the location of a jass.conf file
|
||||
* using the VM parameter
|
||||
* -Djava.security.auth.login.config=$PATH_TO_JAAS_CONF/jaas.conf.
|
||||
* <p>
|
||||
* This example jaas.conf would try Kerberos based authentication, then try LDAP
|
||||
* authentication CAS { com.sun.security.auth.module.Krb5LoginModule sufficient
|
||||
* client=TRUE debug=FALSE useTicketCache=FALSE;
|
||||
* edu.uconn.netid.jaas.LDAPLoginModule sufficient<br />
|
||||
* java.naming.provider.url="ldap://ldapserver.my.edu:389/dc=my,dc=edu"<br />
|
||||
* java.naming.security.principal="uid=jaasauth,dc=my,dc=edu"<br />
|
||||
* java.naming.security.credentials="password" Attribute="uid" startTLS="true"; };<br />
|
||||
*
|
||||
* @author <a href="mailto:dotmatt@uconn.edu">Matthew J. Smith</a>
|
||||
* @version $Revision$ $Date$
|
||||
* @since 3.0.5
|
||||
* @see javax.security.auth.callback.CallbackHandler
|
||||
* @see javax.security.auth.callback.PasswordCallback
|
||||
* @see javax.security.auth.callback.NameCallback
|
||||
*/
|
||||
public class JaasAuthenticationHandler extends
|
||||
AbstractUsernamePasswordAuthenticationHandler {
|
||||
|
||||
/** If no realm is specified, we default to CAS. */
|
||||
private static final String DEFAULT_REALM = "CAS";
|
||||
|
||||
/** The realm that contains the login module information. */
|
||||
@NotNull
|
||||
private String realm = DEFAULT_REALM;
|
||||
|
||||
public JaasAuthenticationHandler() {
|
||||
Assert.notNull(Configuration.getConfiguration(), "Static Configuration cannot be null. Did you remember to specify \"java.security.auth.login.config\"?");
|
||||
}
|
||||
|
||||
protected final boolean authenticateUsernamePasswordInternal(
|
||||
final UsernamePasswordCredentials credentials)
|
||||
throws AuthenticationException {
|
||||
|
||||
final String transformedUsername = getPrincipalNameTransformer().transform(credentials.getUsername());
|
||||
|
||||
try {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Attempting authentication for: "
|
||||
+ transformedUsername);
|
||||
}
|
||||
final LoginContext lc = new LoginContext(this.realm,
|
||||
new UsernamePasswordCallbackHandler(transformedUsername,
|
||||
credentials.getPassword()));
|
||||
|
||||
lc.login();
|
||||
lc.logout();
|
||||
} catch (final LoginException fle) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Authentication failed for: "
|
||||
+ transformedUsername);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Authentication succeeded for: "
|
||||
+ transformedUsername);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public void setRealm(final String realm) {
|
||||
this.realm = realm;
|
||||
}
|
||||
|
||||
/**
|
||||
* A simple JAAS CallbackHandler which accepts a Name String and Password
|
||||
* String in the constructor. Only NameCallbacks and PasswordCallbacks are
|
||||
* accepted in the callback array. This code based loosely on example given
|
||||
* in Sun's javadoc for CallbackHandler interface.
|
||||
*/
|
||||
protected static final class UsernamePasswordCallbackHandler implements CallbackHandler {
|
||||
|
||||
/** The username of the principal we are trying to authenticate. */
|
||||
private final String userName;
|
||||
|
||||
/** The password of the principal we are trying to authenticate. */
|
||||
private final String password;
|
||||
|
||||
/**
|
||||
* Constuctor accepts name and password to be used for authentication.
|
||||
*
|
||||
* @param userName name to be used for authentication
|
||||
* @param password Password to be used for authentication
|
||||
*/
|
||||
protected UsernamePasswordCallbackHandler(final String userName,
|
||||
final String password) {
|
||||
this.userName = userName;
|
||||
this.password = password;
|
||||
|
||||
}
|
||||
|
||||
public void handle(final Callback[] callbacks)
|
||||
throws UnsupportedCallbackException {
|
||||
for (final Callback callback : callbacks ) {
|
||||
if (callback.getClass().equals(NameCallback.class)) {
|
||||
((NameCallback) callback).setName(this.userName);
|
||||
} else if (callback.getClass().equals(PasswordCallback.class)) {
|
||||
((PasswordCallback) callback).setPassword(this.password
|
||||
.toCharArray());
|
||||
} else {
|
||||
throw new UnsupportedCallbackException(callback,
|
||||
"Unrecognized Callback");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Licensed to Jasig under one or more contributor license
|
||||
* agreements. See the NOTICE file distributed with this work
|
||||
* for additional information regarding copyright ownership.
|
||||
* Jasig licenses this file to you under the Apache License,
|
||||
* Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a
|
||||
* copy of the License at the following location:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.jasig.cas.authentication.handler.support;
|
||||
|
||||
import org.jasig.cas.authentication.principal.UsernamePasswordCredentials;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Simple test implementation of a AuthenticationHandler that returns true if
|
||||
* the username and password match. This class should never be enabled in a
|
||||
* production environment and is only designed to facilitate unit testing and
|
||||
* load testing.
|
||||
*
|
||||
* @author Scott Battaglia
|
||||
* @version $Revision$ $Date$
|
||||
* @since 3.0
|
||||
*/
|
||||
public final class SimpleTestUsernamePasswordAuthenticationHandler extends
|
||||
AbstractUsernamePasswordAuthenticationHandler {
|
||||
|
||||
public SimpleTestUsernamePasswordAuthenticationHandler() {
|
||||
log
|
||||
.warn(this.getClass().getName()
|
||||
+ " is only to be used in a testing environment. NEVER enable this in a production environment.");
|
||||
}
|
||||
|
||||
public boolean authenticateUsernamePasswordInternal(final UsernamePasswordCredentials credentials) {
|
||||
final String username = credentials.getUsername();
|
||||
final String password = credentials.getPassword();
|
||||
|
||||
if (StringUtils.hasText(username) && StringUtils.hasText(password)
|
||||
&& username.equals(getPasswordEncoder().encode(password))) {
|
||||
log
|
||||
.debug("User [" + username
|
||||
+ "] was successfully authenticated.");
|
||||
return true;
|
||||
}
|
||||
|
||||
log.debug("User [" + username + "] failed authentication");
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
<!--
|
||||
|
||||
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.
|
||||
|
||||
-->
|
||||
<html>
|
||||
<body>
|
||||
<p>
|
||||
Authentication.support contains the specific implementations of
|
||||
the AuthenticationHandler interface. These implementations are designed
|
||||
to authenticate a specific type of Credential.
|
||||
<p>
|
||||
AuthenticationHandlers are normally associated with the provided
|
||||
AuthenticationManagerImpl which handles all aspects of the request for
|
||||
Authentication.
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,39 @@
|
||||
<!--
|
||||
|
||||
Licensed to Jasig under one or more contributor license
|
||||
agreements. See the NOTICE file distributed with this work
|
||||
for additional information regarding copyright ownership.
|
||||
Jasig licenses this file to you under the Apache License,
|
||||
Version 2.0 (the "License"); you may not use this file
|
||||
except in compliance with the License. You may obtain a
|
||||
copy of the License at the following location:
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
|
||||
-->
|
||||
<html>
|
||||
<body>
|
||||
|
||||
<p>Authentication validates the Credentials provided during a /login
|
||||
request. In this context, "Credentials" are an opaque object declared
|
||||
with the Credentials marker interface. The AuthenticationManager
|
||||
typically passes the Credentials to a sequence of plug-in elements
|
||||
to see if any of them can recognize and process the concrete implementing
|
||||
type.</p>
|
||||
|
||||
<p>Successful authentication generates a Principal object wrapped in an
|
||||
Authentication object. All these objects must be serializable, and the
|
||||
Authentication becomes part of the TGT in the ticket cache.</p>
|
||||
|
||||
<p>Unsucessful authentication must throw an AuthenticationException. The
|
||||
AuthenticationManager may not return null to signal a failure.</p>
|
||||
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,110 @@
|
||||
/*
|
||||
* Licensed to Jasig under one or more contributor license
|
||||
* agreements. See the NOTICE file distributed with this work
|
||||
* for additional information regarding copyright ownership.
|
||||
* Jasig licenses this file to you under the Apache License,
|
||||
* Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a
|
||||
* copy of the License at the following location:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.jasig.cas.authentication.principal;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.jasig.services.persondir.IPersonAttributeDao;
|
||||
import org.jasig.services.persondir.IPersonAttributes;
|
||||
import org.jasig.services.persondir.support.StubPersonAttributeDao;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Scott Battaglia
|
||||
* @version $Revision: 1.1 $ $Date: 2005/08/19 18:27:17 $
|
||||
* @since 3.1
|
||||
*
|
||||
*/
|
||||
public abstract class AbstractPersonDirectoryCredentialsToPrincipalResolver
|
||||
implements CredentialsToPrincipalResolver {
|
||||
|
||||
/** Log instance. */
|
||||
protected final Logger log = LoggerFactory.getLogger(this.getClass());
|
||||
|
||||
private boolean returnNullIfNoAttributes = false;
|
||||
|
||||
/** Repository of principal attributes to be retrieved */
|
||||
@NotNull
|
||||
private IPersonAttributeDao attributeRepository = new StubPersonAttributeDao(new HashMap<String, List<Object>>());
|
||||
|
||||
public final Principal resolvePrincipal(final Credentials credentials) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Attempting to resolve a principal...");
|
||||
}
|
||||
|
||||
final String principalId = extractPrincipalId(credentials);
|
||||
|
||||
if (principalId == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Creating SimplePrincipal for ["
|
||||
+ principalId + "]");
|
||||
}
|
||||
|
||||
final IPersonAttributes personAttributes = this.attributeRepository.getPerson(principalId);
|
||||
final Map<String, List<Object>> attributes;
|
||||
|
||||
if (personAttributes == null) {
|
||||
attributes = null;
|
||||
} else {
|
||||
attributes = personAttributes.getAttributes();
|
||||
}
|
||||
|
||||
if (attributes == null & !this.returnNullIfNoAttributes) {
|
||||
return new SimplePrincipal(principalId);
|
||||
}
|
||||
|
||||
if (attributes == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final Map<String, Object> convertedAttributes = new HashMap<String, Object>();
|
||||
|
||||
for (final Map.Entry<String, List<Object>> entry : attributes.entrySet()) {
|
||||
final String key = entry.getKey();
|
||||
final Object value = entry.getValue().size() == 1 ? entry.getValue().get(0) : entry.getValue();
|
||||
convertedAttributes.put(key, value);
|
||||
}
|
||||
return new SimplePrincipal(principalId, convertedAttributes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the id of the user from the provided credentials.
|
||||
*
|
||||
* @param credentials the credentials provided by the user.
|
||||
* @return the username, or null if it could not be resolved.
|
||||
*/
|
||||
protected abstract String extractPrincipalId(Credentials credentials);
|
||||
|
||||
public final void setAttributeRepository(final IPersonAttributeDao attributeRepository) {
|
||||
this.attributeRepository = attributeRepository;
|
||||
}
|
||||
|
||||
public void setReturnNullIfNoAttributes(final boolean returnNullIfNoAttributes) {
|
||||
this.returnNullIfNoAttributes = returnNullIfNoAttributes;
|
||||
}
|
||||
}
|
@ -0,0 +1,169 @@
|
||||
/*
|
||||
* Licensed to Jasig under one or more contributor license
|
||||
* agreements. See the NOTICE file distributed with this work
|
||||
* for additional information regarding copyright ownership.
|
||||
* Jasig licenses this file to you under the Apache License,
|
||||
* Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a
|
||||
* copy of the License at the following location:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.jasig.cas.authentication.principal;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.jasig.cas.util.DefaultUniqueTicketIdGenerator;
|
||||
import org.jasig.cas.util.HttpClient;
|
||||
import org.jasig.cas.util.SamlUtils;
|
||||
import org.jasig.cas.util.UniqueTicketIdGenerator;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Abstract implementation of a WebApplicationService.
|
||||
*
|
||||
* @author Scott Battaglia
|
||||
* @version $Revision: 1.3 $ $Date: 2007/04/19 20:13:01 $
|
||||
* @since 3.1
|
||||
*
|
||||
*/
|
||||
public abstract class AbstractWebApplicationService implements WebApplicationService {
|
||||
|
||||
protected static final Logger LOG = LoggerFactory.getLogger(SamlService.class);
|
||||
|
||||
private static final Map<String, Object> EMPTY_MAP = Collections.unmodifiableMap(new HashMap<String, Object>());
|
||||
|
||||
private static final UniqueTicketIdGenerator GENERATOR = new DefaultUniqueTicketIdGenerator();
|
||||
|
||||
/** The id of the service. */
|
||||
private final String id;
|
||||
|
||||
/** The original url provided, used to reconstruct the redirect url. */
|
||||
private final String originalUrl;
|
||||
|
||||
private final String artifactId;
|
||||
|
||||
private Principal principal;
|
||||
|
||||
private boolean loggedOutAlready = false;
|
||||
|
||||
private final HttpClient httpClient;
|
||||
|
||||
protected AbstractWebApplicationService(final String id, final String originalUrl, final String artifactId, final HttpClient httpClient) {
|
||||
this.id = id;
|
||||
this.originalUrl = originalUrl;
|
||||
this.artifactId = artifactId;
|
||||
this.httpClient = httpClient;
|
||||
}
|
||||
|
||||
public final String toString() {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
public final String getId() {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
public final String getArtifactId() {
|
||||
return this.artifactId;
|
||||
}
|
||||
|
||||
public final Map<String, Object> getAttributes() {
|
||||
return EMPTY_MAP;
|
||||
}
|
||||
|
||||
protected static String cleanupUrl(final String url) {
|
||||
if (url == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final int jsessionPosition = url.indexOf(";jsession");
|
||||
|
||||
if (jsessionPosition == -1) {
|
||||
return url;
|
||||
}
|
||||
|
||||
final int questionMarkPosition = url.indexOf("?");
|
||||
|
||||
if (questionMarkPosition < jsessionPosition) {
|
||||
return url.substring(0, url.indexOf(";jsession"));
|
||||
}
|
||||
|
||||
return url.substring(0, jsessionPosition)
|
||||
+ url.substring(questionMarkPosition);
|
||||
}
|
||||
|
||||
protected final String getOriginalUrl() {
|
||||
return this.originalUrl;
|
||||
}
|
||||
|
||||
protected final HttpClient getHttpClient() {
|
||||
return this.httpClient;
|
||||
}
|
||||
|
||||
public boolean equals(final Object object) {
|
||||
if (object == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (object instanceof Service) {
|
||||
final Service service = (Service) object;
|
||||
|
||||
return getId().equals(service.getId());
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
final int prime = 41;
|
||||
int result = 1;
|
||||
result = prime * result
|
||||
+ ((this.id == null) ? 0 : this.id.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
protected Principal getPrincipal() {
|
||||
return this.principal;
|
||||
}
|
||||
|
||||
public void setPrincipal(final Principal principal) {
|
||||
this.principal = principal;
|
||||
}
|
||||
|
||||
public boolean matches(final Service service) {
|
||||
return this.id.equals(service.getId());
|
||||
}
|
||||
|
||||
public synchronized boolean logOutOfService(final String sessionIdentifier) {
|
||||
if (this.loggedOutAlready) {
|
||||
return true;
|
||||
}
|
||||
|
||||
LOG.debug("Sending logout request for: " + getId());
|
||||
|
||||
final String logoutRequest = "<samlp:LogoutRequest xmlns:samlp=\"urn:oasis:names:tc:SAML:2.0:protocol\" ID=\""
|
||||
+ GENERATOR.getNewTicketId("LR")
|
||||
+ "\" Version=\"2.0\" IssueInstant=\"" + SamlUtils.getCurrentDateAndTime()
|
||||
+ "\"><saml:NameID xmlns:saml=\"urn:oasis:names:tc:SAML:2.0:assertion\">@NOT_USED@</saml:NameID><samlp:SessionIndex>"
|
||||
+ sessionIdentifier + "</samlp:SessionIndex></samlp:LogoutRequest>";
|
||||
|
||||
this.loggedOutAlready = true;
|
||||
|
||||
if (this.httpClient != null) {
|
||||
return this.httpClient.sendMessageToEndPoint(getOriginalUrl(), logoutRequest, true);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Licensed to Jasig under one or more contributor license
|
||||
* agreements. See the NOTICE file distributed with this work
|
||||
* for additional information regarding copyright ownership.
|
||||
* Jasig licenses this file to you under the Apache License,
|
||||
* Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a
|
||||
* copy of the License at the following location:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.jasig.cas.authentication.principal;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* Marker interface for credentials required to authenticate a principal.
|
||||
* <p>
|
||||
* The Credentials is an opaque object that represents the information a user
|
||||
* asserts proves that the user is who it says it is. In CAS, any information
|
||||
* that is to be presented for authentication must be wrapped (or implement) the
|
||||
* Credentials interface. Credentials can contain a userid and password, or a
|
||||
* Certificate, or an IP address, or a cookie value. Some credentials require
|
||||
* validation, while others (such as container based or Filter based validation)
|
||||
* are inherently trustworthy.
|
||||
* <p>
|
||||
* People who choose to implement their own Credentials object should take care that
|
||||
* any toString() they implement does not accidentally expose confidential information.
|
||||
* toString() can be called from various portions of the CAS code base, including logging
|
||||
* statements, and thus toString should never contain anything confidential or anything
|
||||
* that should not be logged.
|
||||
* <p>
|
||||
* Credentials objects that are included in CAS do NOT expose any confidential information.
|
||||
*
|
||||
* @author William G. Thompson, Jr.
|
||||
* @version $Revision: 1.2 $ $Date: 2007/01/22 20:35:26 $
|
||||
* @since 3.0
|
||||
* <p>
|
||||
* This is a published and supported CAS Server 3 API.
|
||||
* </p>
|
||||
*/
|
||||
public interface Credentials extends Serializable {
|
||||
// marker interface contains no methods
|
||||
}
|
@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Licensed to Jasig under one or more contributor license
|
||||
* agreements. See the NOTICE file distributed with this work
|
||||
* for additional information regarding copyright ownership.
|
||||
* Jasig licenses this file to you under the Apache License,
|
||||
* Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a
|
||||
* copy of the License at the following location:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.jasig.cas.authentication.principal;
|
||||
|
||||
/**
|
||||
* CredentialsToPrincipalResolvers extract information from the Credentials
|
||||
* provided and determine the Principal represented by those credentials.
|
||||
* <p>
|
||||
* A minimal Principal object just has one ID value. This can be extended with
|
||||
* richer objects containing more properties. The SimplePrincipal class
|
||||
* implementing this interface just stores a userid.
|
||||
* </p>
|
||||
* <p>
|
||||
* The Credentials typically contains a userid typed by the user or a
|
||||
* Certificate presented by the browser. In the simplest case the userid is
|
||||
* stored as the Principal ID. The Certificate is a more complicated case
|
||||
* because the ID may have to be extracted from the Subject DN or from one of
|
||||
* the alternate subject names. In a few cases, the institution may prefer the
|
||||
* ID to be a student or employee ID number that can only be obtained by
|
||||
* database lookup using information supplied in the Credentials.
|
||||
* </p>
|
||||
* <p>
|
||||
* The Resolver is free to obtain additional information about the user and
|
||||
* place it in the fields of a class that extends Principal. Such extended
|
||||
* information will be stored like other Principal objects in the TGT, persisted
|
||||
* as needed, and will be available to the View layer, but it is transparent to
|
||||
* most CAS processing.
|
||||
* </p>
|
||||
*
|
||||
* @author Scott Battaglia
|
||||
* @version $Revision: 1.2 $ $Date: 2007/01/22 20:35:27 $
|
||||
* @since 3.0
|
||||
* <p>
|
||||
* This is a published and supported CAS Server 3 API.
|
||||
* </p>
|
||||
* @see org.jasig.cas.authentication.principal.Principal
|
||||
* @see org.jasig.cas.authentication.principal.Credentials
|
||||
*/
|
||||
public interface CredentialsToPrincipalResolver {
|
||||
|
||||
/**
|
||||
* Turn Credentials into a Principal object by analyzing the information
|
||||
* provided in the Credentials and constructing a Principal object based on
|
||||
* that information or information derived from the Credentials object.
|
||||
*
|
||||
* @param credentials from which to resolve Principal
|
||||
* @return resolved Principal, or null if the principal could not be resolved.
|
||||
*/
|
||||
Principal resolvePrincipal(Credentials credentials);
|
||||
|
||||
/**
|
||||
* Determine if a credentials type is supported by this resolver. This is
|
||||
* checked before calling resolve principal.
|
||||
*
|
||||
* @param credentials The credentials to check if we support.
|
||||
* @return true if we support these credentials, false otherwise.
|
||||
*/
|
||||
boolean supports(Credentials credentials);
|
||||
}
|
@ -0,0 +1,304 @@
|
||||
/*
|
||||
* Licensed to Jasig under one or more contributor license
|
||||
* agreements. See the NOTICE file distributed with this work
|
||||
* for additional information regarding copyright ownership.
|
||||
* Jasig licenses this file to you under the Apache License,
|
||||
* Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a
|
||||
* copy of the License at the following location:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.jasig.cas.authentication.principal;
|
||||
|
||||
import org.jasig.cas.util.SamlUtils;
|
||||
import org.jdom.Document;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.security.PrivateKey;
|
||||
import java.security.PublicKey;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
import java.util.zip.DataFormatException;
|
||||
import java.util.zip.Inflater;
|
||||
import java.util.zip.InflaterInputStream;
|
||||
|
||||
import org.apache.commons.codec.binary.Base64;
|
||||
|
||||
/**
|
||||
* Implementation of a Service that supports Google Accounts (eventually a more
|
||||
* generic SAML2 support will come).
|
||||
*
|
||||
* @author Scott Battaglia
|
||||
* @version $Revision: 1.1 $ $Date: 2005/08/19 18:27:17 $
|
||||
* @since 3.1
|
||||
*/
|
||||
public class GoogleAccountsService extends AbstractWebApplicationService {
|
||||
|
||||
/**
|
||||
* Comment for <code>serialVersionUID</code>
|
||||
*/
|
||||
private static final long serialVersionUID = 6678711809842282833L;
|
||||
|
||||
private static Random random = new Random();
|
||||
|
||||
private static final char[] charMapping = {
|
||||
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
|
||||
'p'};
|
||||
|
||||
private static final String CONST_PARAM_SERVICE = "SAMLRequest";
|
||||
|
||||
private static final String CONST_RELAY_STATE = "RelayState";
|
||||
|
||||
private static final String TEMPLATE_SAML_RESPONSE = "<samlp:Response ID=\"<RESPONSE_ID>\" IssueInstant=\"<ISSUE_INSTANT>\" Version=\"2.0\""
|
||||
+ " xmlns=\"urn:oasis:names:tc:SAML:2.0:assertion\""
|
||||
+ " xmlns:samlp=\"urn:oasis:names:tc:SAML:2.0:protocol\""
|
||||
+ " xmlns:xenc=\"http://www.w3.org/2001/04/xmlenc#\">"
|
||||
+ "<samlp:Status>"
|
||||
+ "<samlp:StatusCode Value=\"urn:oasis:names:tc:SAML:2.0:status:Success\" />"
|
||||
+ "</samlp:Status>"
|
||||
+ "<Assertion ID=\"<ASSERTION_ID>\""
|
||||
+ " IssueInstant=\"2003-04-17T00:46:02Z\" Version=\"2.0\""
|
||||
+ " xmlns=\"urn:oasis:names:tc:SAML:2.0:assertion\">"
|
||||
+ "<Issuer>https://www.opensaml.org/IDP</Issuer>"
|
||||
+ "<Subject>"
|
||||
+ "<NameID Format=\"urn:oasis:names:tc:SAML:2.0:nameid-format:emailAddress\">"
|
||||
+ "<USERNAME_STRING>"
|
||||
+ "</NameID>"
|
||||
+ "<SubjectConfirmation Method=\"urn:oasis:names:tc:SAML:2.0:cm:bearer\">"
|
||||
+ "<SubjectConfirmationData Recipient=\"<ACS_URL>\" NotOnOrAfter=\"<NOT_ON_OR_AFTER>\" InResponseTo=\"<REQUEST_ID>\" />"
|
||||
+ "</SubjectConfirmation>"
|
||||
+ "</Subject>"
|
||||
+ "<Conditions NotBefore=\"2003-04-17T00:46:02Z\""
|
||||
+ " NotOnOrAfter=\"<NOT_ON_OR_AFTER>\">"
|
||||
+ "<AudienceRestriction>"
|
||||
+ "<Audience><ACS_URL></Audience>"
|
||||
+ "</AudienceRestriction>"
|
||||
+ "</Conditions>"
|
||||
+ "<AuthnStatement AuthnInstant=\"<AUTHN_INSTANT>\">"
|
||||
+ "<AuthnContext>"
|
||||
+ "<AuthnContextClassRef>"
|
||||
+ "urn:oasis:names:tc:SAML:2.0:ac:classes:Password"
|
||||
+ "</AuthnContextClassRef>"
|
||||
+ "</AuthnContext>"
|
||||
+ "</AuthnStatement>"
|
||||
+ "</Assertion></samlp:Response>";
|
||||
|
||||
private final String relayState;
|
||||
|
||||
private final PublicKey publicKey;
|
||||
|
||||
private final PrivateKey privateKey;
|
||||
|
||||
private final String requestId;
|
||||
|
||||
private final String alternateUserName;
|
||||
|
||||
protected GoogleAccountsService(final String id, final String relayState, final String requestId,
|
||||
final PrivateKey privateKey, final PublicKey publicKey, final String alternateUserName) {
|
||||
this(id, id, null, relayState, requestId, privateKey, publicKey, alternateUserName);
|
||||
}
|
||||
|
||||
protected GoogleAccountsService(final String id, final String originalUrl,
|
||||
final String artifactId, final String relayState, final String requestId,
|
||||
final PrivateKey privateKey, final PublicKey publicKey, final String alternateUserName) {
|
||||
super(id, originalUrl, artifactId, null);
|
||||
this.relayState = relayState;
|
||||
this.privateKey = privateKey;
|
||||
this.publicKey = publicKey;
|
||||
this.requestId = requestId;
|
||||
this.alternateUserName = alternateUserName;
|
||||
}
|
||||
|
||||
public static GoogleAccountsService createServiceFrom(
|
||||
final HttpServletRequest request, final PrivateKey privateKey,
|
||||
final PublicKey publicKey, final String alternateUserName) {
|
||||
final String relayState = request.getParameter(CONST_RELAY_STATE);
|
||||
|
||||
final String xmlRequest = decodeAuthnRequestXML(request
|
||||
.getParameter(CONST_PARAM_SERVICE));
|
||||
|
||||
if (!StringUtils.hasText(xmlRequest)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final Document document = SamlUtils
|
||||
.constructDocumentFromXmlString(xmlRequest);
|
||||
|
||||
if (document == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final String assertionConsumerServiceUrl = document.getRootElement().getAttributeValue("AssertionConsumerServiceURL");
|
||||
final String requestId = document.getRootElement().getAttributeValue("ID");
|
||||
|
||||
return new GoogleAccountsService(assertionConsumerServiceUrl,
|
||||
relayState, requestId, privateKey, publicKey, alternateUserName);
|
||||
}
|
||||
|
||||
public Response getResponse(final String ticketId) {
|
||||
final Map<String, String> parameters = new HashMap<String, String>();
|
||||
final String samlResponse = constructSamlResponse();
|
||||
final String signedResponse = SamlUtils.signSamlResponse(samlResponse,
|
||||
this.privateKey, this.publicKey);
|
||||
parameters.put("SAMLResponse", signedResponse);
|
||||
parameters.put("RelayState", this.relayState);
|
||||
|
||||
return Response.getPostResponse(getOriginalUrl(), parameters);
|
||||
}
|
||||
|
||||
/**
|
||||
* Service does not support Single Log Out
|
||||
*
|
||||
* @see org.jasig.cas.authentication.principal.WebApplicationService#logOutOfService(java.lang.String)
|
||||
*/
|
||||
public boolean logOutOfService(final String sessionIdentifier) {
|
||||
return false;
|
||||
}
|
||||
|
||||
private String constructSamlResponse() {
|
||||
String samlResponse = TEMPLATE_SAML_RESPONSE;
|
||||
|
||||
final Calendar c = Calendar.getInstance();
|
||||
c.setTime(new Date());
|
||||
c.add(Calendar.YEAR, 1);
|
||||
|
||||
final String userId;
|
||||
|
||||
if (this.alternateUserName == null) {
|
||||
userId = getPrincipal().getId();
|
||||
} else {
|
||||
final String attributeValue = (String) getPrincipal().getAttributes().get(this.alternateUserName);
|
||||
if (attributeValue == null) {
|
||||
userId = getPrincipal().getId();
|
||||
} else {
|
||||
userId = attributeValue;
|
||||
}
|
||||
}
|
||||
|
||||
samlResponse = samlResponse.replace("<USERNAME_STRING>", userId);
|
||||
samlResponse = samlResponse.replace("<RESPONSE_ID>", createID());
|
||||
samlResponse = samlResponse.replace("<ISSUE_INSTANT>", SamlUtils
|
||||
.getCurrentDateAndTime());
|
||||
samlResponse = samlResponse.replace("<AUTHN_INSTANT>", SamlUtils
|
||||
.getCurrentDateAndTime());
|
||||
samlResponse = samlResponse.replaceAll("<NOT_ON_OR_AFTER>", SamlUtils
|
||||
.getFormattedDateAndTime(c.getTime()));
|
||||
samlResponse = samlResponse.replace("<ASSERTION_ID>", createID());
|
||||
samlResponse = samlResponse.replaceAll("<ACS_URL>", getId());
|
||||
samlResponse = samlResponse.replace("<REQUEST_ID>", this.requestId);
|
||||
|
||||
return samlResponse;
|
||||
}
|
||||
|
||||
private static String createID() {
|
||||
final byte[] bytes = new byte[20]; // 160 bits
|
||||
random.nextBytes(bytes);
|
||||
|
||||
final char[] chars = new char[40];
|
||||
|
||||
for (int i = 0; i < bytes.length; i++) {
|
||||
int left = (bytes[i] >> 4) & 0x0f;
|
||||
int right = bytes[i] & 0x0f;
|
||||
chars[i * 2] = charMapping[left];
|
||||
chars[i * 2 + 1] = charMapping[right];
|
||||
}
|
||||
|
||||
return String.valueOf(chars);
|
||||
}
|
||||
|
||||
private static String decodeAuthnRequestXML(
|
||||
final String encodedRequestXmlString) {
|
||||
if (encodedRequestXmlString == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final byte[] decodedBytes = base64Decode(encodedRequestXmlString);
|
||||
|
||||
if (decodedBytes == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final String inflated = inflate(decodedBytes);
|
||||
|
||||
if (inflated != null) {
|
||||
return inflated;
|
||||
}
|
||||
|
||||
return zlibDeflate(decodedBytes);
|
||||
}
|
||||
|
||||
private static String zlibDeflate(final byte[] bytes) {
|
||||
final ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
|
||||
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
final InflaterInputStream iis = new InflaterInputStream(bais);
|
||||
final byte[] buf = new byte[1024];
|
||||
|
||||
try {
|
||||
int count = iis.read(buf);
|
||||
while (count != -1) {
|
||||
baos.write(buf, 0, count);
|
||||
count = iis.read(buf);
|
||||
}
|
||||
return new String(baos.toByteArray());
|
||||
} catch (final Exception e) {
|
||||
return null;
|
||||
} finally {
|
||||
try {
|
||||
iis.close();
|
||||
} catch (final Exception e) {
|
||||
// nothing to do
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static byte[] base64Decode(final String xml) {
|
||||
try {
|
||||
final byte[] xmlBytes = xml.getBytes("UTF-8");
|
||||
return Base64.decodeBase64(xmlBytes);
|
||||
} catch (final Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static String inflate(final byte[] bytes) {
|
||||
final Inflater inflater = new Inflater(true);
|
||||
final byte[] xmlMessageBytes = new byte[10000];
|
||||
|
||||
final byte[] extendedBytes = new byte[bytes.length + 1];
|
||||
System.arraycopy(bytes, 0, extendedBytes, 0, bytes.length);
|
||||
extendedBytes[bytes.length] = 0;
|
||||
|
||||
inflater.setInput(extendedBytes);
|
||||
|
||||
try {
|
||||
final int resultLength = inflater.inflate(xmlMessageBytes);
|
||||
inflater.end();
|
||||
|
||||
if (!inflater.finished()) {
|
||||
throw new RuntimeException("buffer not large enough.");
|
||||
}
|
||||
|
||||
inflater.end();
|
||||
return new String(xmlMessageBytes, 0, resultLength, "UTF-8");
|
||||
} catch (final DataFormatException e) {
|
||||
return null;
|
||||
} catch (final UnsupportedEncodingException e) {
|
||||
throw new RuntimeException("Cannot find encoding: UTF-8", e);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,101 @@
|
||||
/*
|
||||
* Licensed to Jasig under one or more contributor license
|
||||
* agreements. See the NOTICE file distributed with this work
|
||||
* for additional information regarding copyright ownership.
|
||||
* Jasig licenses this file to you under the Apache License,
|
||||
* Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a
|
||||
* copy of the License at the following location:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.jasig.cas.authentication.principal;
|
||||
|
||||
import java.net.URL;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* The Credentials representing an HTTP-based service. HTTP-based services (such
|
||||
* as web applications) are often represented by the URL entry point of the
|
||||
* application.
|
||||
*
|
||||
* @author Scott Battaglia
|
||||
* @version $Revision: 1.3 $ $Date: 2007/04/24 13:01:51 $
|
||||
* @since 3.0
|
||||
*/
|
||||
public class HttpBasedServiceCredentials implements Credentials {
|
||||
|
||||
/** Unique Serializable ID. */
|
||||
private static final long serialVersionUID = 3904681574350991665L;
|
||||
|
||||
/** The callbackURL to check that identifies the application. */
|
||||
private final URL callbackUrl;
|
||||
|
||||
/** String form of callbackUrl; */
|
||||
private final String callbackUrlAsString;
|
||||
|
||||
/**
|
||||
* Constructor that takes the URL of the HTTP-based service and creates the
|
||||
* Credentials object. Caches the value of URL.toExternalForm so updates to
|
||||
* the URL will not be reflected in a call to toString().
|
||||
*
|
||||
* @param callbackUrl the URL representing the service
|
||||
* @throws IllegalArgumentException if the callbackUrl is null.
|
||||
*/
|
||||
public HttpBasedServiceCredentials(final URL callbackUrl) {
|
||||
Assert.notNull(callbackUrl, "callbackUrl cannot be null");
|
||||
this.callbackUrl = callbackUrl;
|
||||
this.callbackUrlAsString = callbackUrl.toExternalForm();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Returns the callbackUrl.
|
||||
*/
|
||||
public final URL getCallbackUrl() {
|
||||
return this.callbackUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the String version of the URL, based on the original URL
|
||||
* provided. i.e. this caches the value of URL.toExternalForm()
|
||||
*/
|
||||
public final String toString() {
|
||||
return "[callbackUrl: " + this.callbackUrlAsString + "]";
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime
|
||||
* result
|
||||
+ ((this.callbackUrlAsString == null) ? 0 : this.callbackUrlAsString
|
||||
.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
public boolean equals(final Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
final HttpBasedServiceCredentials other = (HttpBasedServiceCredentials) obj;
|
||||
if (this.callbackUrlAsString == null) {
|
||||
if (other.callbackUrlAsString != null)
|
||||
return false;
|
||||
} else if (!this.callbackUrlAsString.equals(other.callbackUrlAsString))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Licensed to Jasig under one or more contributor license
|
||||
* agreements. See the NOTICE file distributed with this work
|
||||
* for additional information regarding copyright ownership.
|
||||
* Jasig licenses this file to you under the Apache License,
|
||||
* Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a
|
||||
* copy of the License at the following location:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.jasig.cas.authentication.principal;
|
||||
|
||||
/**
|
||||
* HttpBasedServiceCredentialsToPrincipalResolver extracts the callbackUrl from
|
||||
* the HttpBasedServiceCredentials and constructs a SimpleService with the
|
||||
* callbackUrl as the unique Id.
|
||||
*
|
||||
* @author Scott Battaglia
|
||||
* @version $Revision: 1.5 $ $Date: 2007/02/27 19:31:58 $
|
||||
* @since 3.0
|
||||
*/
|
||||
public final class HttpBasedServiceCredentialsToPrincipalResolver implements
|
||||
CredentialsToPrincipalResolver {
|
||||
|
||||
/**
|
||||
* Method to return a simple Service Principal with the identifier set to be
|
||||
* the callback url.
|
||||
*/
|
||||
public Principal resolvePrincipal(final Credentials credentials) {
|
||||
final HttpBasedServiceCredentials serviceCredentials = (HttpBasedServiceCredentials) credentials;
|
||||
return new SimpleWebApplicationServiceImpl(serviceCredentials.getCallbackUrl().toExternalForm());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if the credentials provided are not null and are assignable
|
||||
* from HttpBasedServiceCredentials, otherwise returns false.
|
||||
*/
|
||||
public boolean supports(final Credentials credentials) {
|
||||
return credentials != null
|
||||
&& HttpBasedServiceCredentials.class.isAssignableFrom(credentials
|
||||
.getClass());
|
||||
}
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Licensed to Jasig under one or more contributor license
|
||||
* agreements. See the NOTICE file distributed with this work
|
||||
* for additional information regarding copyright ownership.
|
||||
* Jasig licenses this file to you under the Apache License,
|
||||
* Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a
|
||||
* copy of the License at the following location:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.jasig.cas.authentication.principal;
|
||||
|
||||
/**
|
||||
* Generates a unique consistant Id based on the principal, a service, and some
|
||||
* algorithm.
|
||||
*
|
||||
* @author Scott Battaglia
|
||||
* @version $Revision: 1.1 $ $Date: 2007/04/20 19:39:31 $
|
||||
* @since 3.1
|
||||
*/
|
||||
public interface PersistentIdGenerator {
|
||||
|
||||
/**
|
||||
* Generates a PersistentId based on some algorithm plus the principal and
|
||||
* service.
|
||||
*
|
||||
* @param principal the principal to generate the id for.
|
||||
* @param service the service to generate the id for.
|
||||
* @return the generated persistent id.
|
||||
*/
|
||||
String generate(Principal principal, Service service);
|
||||
}
|
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Licensed to Jasig under one or more contributor license
|
||||
* agreements. See the NOTICE file distributed with this work
|
||||
* for additional information regarding copyright ownership.
|
||||
* Jasig licenses this file to you under the Apache License,
|
||||
* Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a
|
||||
* copy of the License at the following location:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.jasig.cas.authentication.principal;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Generic concept of an authenticated thing. Examples include a person or a
|
||||
* service.
|
||||
* <p>
|
||||
* The implementation SimplePrincipal just contains the Id property. More
|
||||
* complex Principal objects may contain additional information that are
|
||||
* meaningful to the View layer but are generally transparent to the rest of
|
||||
* CAS.
|
||||
* </p>
|
||||
*
|
||||
* @author Scott Battaglia
|
||||
* @version $Revision: 1.3 $ $Date: 2007/04/19 20:13:01 $
|
||||
* @since 3.0
|
||||
* <p>
|
||||
* This is a published and supported CAS Server 3 API.
|
||||
* </p>
|
||||
*/
|
||||
public interface Principal extends Serializable {
|
||||
|
||||
/**
|
||||
* Returns the unique id for the Principal
|
||||
* @return the unique id for the Principal.
|
||||
*/
|
||||
String getId();
|
||||
|
||||
/**
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
Map<String, Object> getAttributes();
|
||||
}
|
@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Licensed to Jasig under one or more contributor license
|
||||
* agreements. See the NOTICE file distributed with this work
|
||||
* for additional information regarding copyright ownership.
|
||||
* Jasig licenses this file to you under the Apache License,
|
||||
* Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a
|
||||
* copy of the License at the following location:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.jasig.cas.authentication.principal;
|
||||
|
||||
import org.jasig.cas.authentication.Authentication;
|
||||
import org.jasig.cas.authentication.AuthenticationMetaDataPopulator;
|
||||
|
||||
/**
|
||||
* Determines if the credentials provided are for Remember Me Services and then sets the appropriate
|
||||
* Authentication attribute if remember me services have been requested.
|
||||
*
|
||||
* @author Scott Battaglia
|
||||
* @version $Revision: 1.1 $ $Date: 2005/08/19 18:27:17 $
|
||||
* @since 3.2.1
|
||||
*
|
||||
*/
|
||||
public final class RememberMeAuthenticationMetaDataPopulator implements
|
||||
AuthenticationMetaDataPopulator {
|
||||
|
||||
public Authentication populateAttributes(final Authentication authentication,
|
||||
final Credentials credentials) {
|
||||
if (credentials instanceof RememberMeCredentials) {
|
||||
final RememberMeCredentials r = (RememberMeCredentials) credentials;
|
||||
if (r.isRememberMe()) {
|
||||
authentication.getAttributes().put(RememberMeCredentials.AUTHENTICATION_ATTRIBUTE_REMEMBER_ME, Boolean.TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
return authentication;
|
||||
}
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Licensed to Jasig under one or more contributor license
|
||||
* agreements. See the NOTICE file distributed with this work
|
||||
* for additional information regarding copyright ownership.
|
||||
* Jasig licenses this file to you under the Apache License,
|
||||
* Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a
|
||||
* copy of the License at the following location:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.jasig.cas.authentication.principal;
|
||||
|
||||
/**
|
||||
* Credentials that wish to handle remember me scenarios need
|
||||
* to implement this class.
|
||||
*
|
||||
* @author Scott Battaglia
|
||||
* @version $Revision: 1.1 $ $Date: 2005/08/19 18:27:17 $
|
||||
* @since 3.2.1
|
||||
*
|
||||
*/
|
||||
public interface RememberMeCredentials extends Credentials {
|
||||
|
||||
String AUTHENTICATION_ATTRIBUTE_REMEMBER_ME = "org.jasig.cas.authentication.principal.REMEMBER_ME";
|
||||
|
||||
String REQUEST_PARAMETER_REMEMBER_ME = "rememberMe";
|
||||
|
||||
boolean isRememberMe();
|
||||
|
||||
void setRememberMe(boolean rememberMe);
|
||||
}
|
@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Licensed to Jasig under one or more contributor license
|
||||
* agreements. See the NOTICE file distributed with this work
|
||||
* for additional information regarding copyright ownership.
|
||||
* Jasig licenses this file to you under the Apache License,
|
||||
* Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a
|
||||
* copy of the License at the following location:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.jasig.cas.authentication.principal;
|
||||
|
||||
/**
|
||||
* Handles both remember me services and username and password.
|
||||
*
|
||||
* @author Scott Battaglia
|
||||
* @version $Revision: 1.1 $ $Date: 2005/08/19 18:27:17 $
|
||||
* @since 3.2.1
|
||||
*
|
||||
*/
|
||||
public class RememberMeUsernamePasswordCredentials extends
|
||||
UsernamePasswordCredentials implements RememberMeCredentials {
|
||||
|
||||
/** Unique Id for serialization. */
|
||||
private static final long serialVersionUID = -9178853167397038282L;
|
||||
|
||||
private boolean rememberMe;
|
||||
|
||||
public final boolean isRememberMe() {
|
||||
return this.rememberMe;
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = super.hashCode();
|
||||
result = prime * result + (this.rememberMe ? 1231 : 1237);
|
||||
return result;
|
||||
}
|
||||
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (!super.equals(obj))
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
final RememberMeUsernamePasswordCredentials other = (RememberMeUsernamePasswordCredentials) obj;
|
||||
if (this.rememberMe != other.rememberMe)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
public final void setRememberMe(boolean rememberMe) {
|
||||
this.rememberMe = rememberMe;
|
||||
}
|
||||
}
|
@ -0,0 +1,135 @@
|
||||
/*
|
||||
* Licensed to Jasig under one or more contributor license
|
||||
* agreements. See the NOTICE file distributed with this work
|
||||
* for additional information regarding copyright ownership.
|
||||
* Jasig licenses this file to you under the Apache License,
|
||||
* Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a
|
||||
* copy of the License at the following location:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.jasig.cas.authentication.principal;
|
||||
|
||||
import java.net.URLEncoder;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Encapsulates a Response to send back for a particular service.
|
||||
*
|
||||
* @author Scott Battaglia
|
||||
* @author Arnaud Lesueur
|
||||
* @version $Revision: 1.1 $ $Date: 2005/08/19 18:27:17 $
|
||||
* @since 3.1
|
||||
*/
|
||||
public final class Response {
|
||||
/** Pattern to detect unprintable ASCII characters. */
|
||||
private static final Pattern NON_PRINTABLE =
|
||||
Pattern.compile("[\\x00-\\x19\\x7F]+");
|
||||
|
||||
/** Log instance. */
|
||||
protected static final Logger LOG = LoggerFactory.getLogger(Response.class);
|
||||
|
||||
public static enum ResponseType {
|
||||
POST, REDIRECT
|
||||
}
|
||||
|
||||
private final ResponseType responseType;
|
||||
|
||||
private final String url;
|
||||
|
||||
private final Map<String, String> attributes;
|
||||
|
||||
protected Response(ResponseType responseType, final String url, final Map<String, String> attributes) {
|
||||
this.responseType = responseType;
|
||||
this.url = url;
|
||||
this.attributes = attributes;
|
||||
}
|
||||
|
||||
public static Response getPostResponse(final String url, final Map<String, String> attributes) {
|
||||
return new Response(ResponseType.POST, url, attributes);
|
||||
}
|
||||
|
||||
public static Response getRedirectResponse(final String url, final Map<String, String> parameters) {
|
||||
final StringBuilder builder = new StringBuilder(parameters.size() * 40 + 100);
|
||||
boolean isFirst = true;
|
||||
final String[] fragmentSplit = sanitizeUrl(url).split("#");
|
||||
|
||||
builder.append(fragmentSplit[0]);
|
||||
|
||||
for (final Map.Entry<String, String> entry : parameters.entrySet()) {
|
||||
if (entry.getValue() != null) {
|
||||
if (isFirst) {
|
||||
builder.append(url.contains("?") ? "&" : "?");
|
||||
isFirst = false;
|
||||
} else {
|
||||
builder.append("&");
|
||||
}
|
||||
builder.append(entry.getKey());
|
||||
builder.append("=");
|
||||
|
||||
try {
|
||||
builder.append(URLEncoder.encode(entry.getValue(), "UTF-8"));
|
||||
} catch (final Exception e) {
|
||||
builder.append(entry.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (fragmentSplit.length > 1) {
|
||||
builder.append("#");
|
||||
builder.append(fragmentSplit[1]);
|
||||
}
|
||||
|
||||
return new Response(ResponseType.REDIRECT, builder.toString(), parameters);
|
||||
}
|
||||
|
||||
public Map<String, String> getAttributes() {
|
||||
return this.attributes;
|
||||
}
|
||||
|
||||
public ResponseType getResponseType() {
|
||||
return this.responseType;
|
||||
}
|
||||
|
||||
public String getUrl() {
|
||||
return this.url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanitize a URL provided by a relying party by normalizing non-printable
|
||||
* ASCII character sequences into spaces. This functionality protects
|
||||
* against CRLF attacks and other similar attacks using invisible characters
|
||||
* that could be abused to trick user agents.
|
||||
*
|
||||
* @param url URL to sanitize.
|
||||
*
|
||||
* @return Sanitized URL string.
|
||||
*/
|
||||
private static String sanitizeUrl(final String url) {
|
||||
final Matcher m = NON_PRINTABLE.matcher(url);
|
||||
final StringBuffer sb = new StringBuffer(url.length());
|
||||
boolean hasNonPrintable = false;
|
||||
while (m.find()) {
|
||||
m.appendReplacement(sb, " ");
|
||||
hasNonPrintable = true;
|
||||
}
|
||||
m.appendTail(sb);
|
||||
if (hasNonPrintable) {
|
||||
LOG.warn("The following redirect URL has been sanitized and may be sign of attack:\n" + url);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
@ -0,0 +1,172 @@
|
||||
/*
|
||||
* Licensed to Jasig under one or more contributor license
|
||||
* agreements. See the NOTICE file distributed with this work
|
||||
* for additional information regarding copyright ownership.
|
||||
* Jasig licenses this file to you under the Apache License,
|
||||
* Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a
|
||||
* copy of the License at the following location:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.jasig.cas.authentication.principal;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.jasig.cas.util.HttpClient;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Class to represent that this service wants to use SAML. We use this in
|
||||
* combination with the CentralAuthenticationServiceImpl to choose the right
|
||||
* UniqueTicketIdGenerator.
|
||||
*
|
||||
* @author Scott Battaglia
|
||||
* @version $Revision: 1.6 $ $Date: 2007/02/27 19:31:58 $
|
||||
* @since 3.1
|
||||
*/
|
||||
public final class SamlService extends AbstractWebApplicationService {
|
||||
|
||||
private static final Log log = LogFactory.getLog(SamlService.class);
|
||||
|
||||
/** Constant representing service. */
|
||||
private static final String CONST_PARAM_SERVICE = "TARGET";
|
||||
|
||||
/** Constant representing artifact. */
|
||||
private static final String CONST_PARAM_TICKET = "SAMLart";
|
||||
|
||||
private static final String CONST_START_ARTIFACT_XML_TAG_NO_NAMESPACE = "<AssertionArtifact>";
|
||||
|
||||
private static final String CONST_END_ARTIFACT_XML_TAG_NO_NAMESPACE = "</AssertionArtifact>";
|
||||
|
||||
private static final String CONST_START_ARTIFACT_XML_TAG = "<samlp:AssertionArtifact>";
|
||||
|
||||
private static final String CONST_END_ARTIFACT_XML_TAG = "</samlp:AssertionArtifact>";
|
||||
|
||||
private String requestId;
|
||||
|
||||
/**
|
||||
* Unique Id for serialization.
|
||||
*/
|
||||
private static final long serialVersionUID = -6867572626767140223L;
|
||||
|
||||
protected SamlService(final String id) {
|
||||
super(id, id, null, new HttpClient());
|
||||
}
|
||||
|
||||
protected SamlService(final String id, final String originalUrl, final String artifactId, final HttpClient httpClient, final String requestId) {
|
||||
super(id, originalUrl, artifactId, httpClient);
|
||||
this.requestId = requestId;
|
||||
}
|
||||
|
||||
/**
|
||||
* This always returns true because a SAML Service does not receive the TARGET value on validation.
|
||||
*/
|
||||
public boolean matches(final Service service) {
|
||||
return true;
|
||||
}
|
||||
|
||||
public String getRequestID() {
|
||||
return this.requestId;
|
||||
}
|
||||
|
||||
public static SamlService createServiceFrom(
|
||||
final HttpServletRequest request, final HttpClient httpClient) {
|
||||
final String service = request.getParameter(CONST_PARAM_SERVICE);
|
||||
final String artifactId;
|
||||
final String requestBody = getRequestBody(request);
|
||||
final String requestId;
|
||||
|
||||
if (!StringUtils.hasText(service) && !StringUtils.hasText(requestBody)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final String id = cleanupUrl(service);
|
||||
|
||||
if (StringUtils.hasText(requestBody)) {
|
||||
|
||||
final String tagStart;
|
||||
final String tagEnd;
|
||||
if (requestBody.contains(CONST_START_ARTIFACT_XML_TAG)) {
|
||||
tagStart = CONST_START_ARTIFACT_XML_TAG;
|
||||
tagEnd = CONST_END_ARTIFACT_XML_TAG;
|
||||
} else {
|
||||
tagStart = CONST_START_ARTIFACT_XML_TAG_NO_NAMESPACE;
|
||||
tagEnd = CONST_END_ARTIFACT_XML_TAG_NO_NAMESPACE;
|
||||
}
|
||||
final int startTagLocation = requestBody.indexOf(tagStart);
|
||||
final int artifactStartLocation = startTagLocation + tagStart.length();
|
||||
final int endTagLocation = requestBody.indexOf(tagEnd);
|
||||
|
||||
artifactId = requestBody.substring(artifactStartLocation, endTagLocation).trim();
|
||||
|
||||
// is there a request id?
|
||||
requestId = extractRequestId(requestBody);
|
||||
} else {
|
||||
artifactId = null;
|
||||
requestId = null;
|
||||
}
|
||||
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Attempted to extract Request from HttpServletRequest. Results:");
|
||||
log.debug(String.format("Request Body: %s", requestBody));
|
||||
log.debug(String.format("Extracted ArtifactId: %s", artifactId));
|
||||
log.debug(String.format("Extracted Request Id: %s", requestId));
|
||||
}
|
||||
|
||||
return new SamlService(id, service, artifactId, httpClient, requestId);
|
||||
}
|
||||
|
||||
public Response getResponse(final String ticketId) {
|
||||
final Map<String, String> parameters = new HashMap<String, String>();
|
||||
|
||||
parameters.put(CONST_PARAM_TICKET, ticketId);
|
||||
parameters.put(CONST_PARAM_SERVICE, getOriginalUrl());
|
||||
|
||||
return Response.getRedirectResponse(getOriginalUrl(), parameters);
|
||||
}
|
||||
|
||||
protected static String extractRequestId(final String requestBody) {
|
||||
if (!requestBody.contains("RequestID")) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
final int position = requestBody.indexOf("RequestID=\"") + 11;
|
||||
final int nextPosition = requestBody.indexOf("\"", position);
|
||||
|
||||
return requestBody.substring(position, nextPosition);
|
||||
} catch (final Exception e) {
|
||||
log.debug("Exception parsing RequestID from request." ,e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
protected static String getRequestBody(final HttpServletRequest request) {
|
||||
final StringBuilder builder = new StringBuilder();
|
||||
try {
|
||||
final BufferedReader reader = request.getReader();
|
||||
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
builder.append(line);
|
||||
}
|
||||
return builder.toString();
|
||||
} catch (final Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Licensed to Jasig under one or more contributor license
|
||||
* agreements. See the NOTICE file distributed with this work
|
||||
* for additional information regarding copyright ownership.
|
||||
* Jasig licenses this file to you under the Apache License,
|
||||
* Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a
|
||||
* copy of the License at the following location:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.jasig.cas.authentication.principal;
|
||||
|
||||
/**
|
||||
* Marker interface for Services. Services are generally either remote
|
||||
* applications utilizing CAS or applications that principals wish to gain
|
||||
* access to. In most cases this will be some form of web application.
|
||||
*
|
||||
* @author William G. Thompson, Jr.
|
||||
* @author Scott Battaglia
|
||||
* @version $Revision: 1.2 $ $Date: 2007/01/22 20:35:26 $
|
||||
* @since 3.0
|
||||
* <p>
|
||||
* This is a published and supported CAS Server 3 API.
|
||||
* </p>
|
||||
*/
|
||||
public interface Service extends Principal {
|
||||
|
||||
void setPrincipal(Principal principal);
|
||||
|
||||
boolean logOutOfService(String sessionIdentifier);
|
||||
|
||||
boolean matches(Service service);
|
||||
}
|
@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Licensed to Jasig under one or more contributor license
|
||||
* agreements. See the NOTICE file distributed with this work
|
||||
* for additional information regarding copyright ownership.
|
||||
* Jasig licenses this file to you under the Apache License,
|
||||
* Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a
|
||||
* copy of the License at the following location:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.jasig.cas.authentication.principal;
|
||||
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
|
||||
import org.apache.commons.codec.binary.Base64;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
/**
|
||||
* Generates PersistentIds based on the Shibboleth algorithm.
|
||||
*
|
||||
* @author Scott Battaglia
|
||||
* @version $Revision: 1.1 $ $Date: 2007/04/20 19:39:31 $
|
||||
* @since 3.1
|
||||
*/
|
||||
public final class ShibbolethCompatiblePersistentIdGenerator implements
|
||||
PersistentIdGenerator {
|
||||
|
||||
private static final byte CONST_SEPARATOR = (byte) '!';
|
||||
|
||||
@NotNull
|
||||
private byte[] salt;
|
||||
|
||||
public String generate(final Principal principal, final Service service) {
|
||||
try {
|
||||
final MessageDigest md = MessageDigest.getInstance("SHA");
|
||||
md.update(service.getId().getBytes());
|
||||
md.update(CONST_SEPARATOR);
|
||||
md.update(principal.getId().getBytes());
|
||||
md.update(CONST_SEPARATOR);
|
||||
|
||||
return Base64.encodeBase64String(md.digest(this.salt)).replaceAll(
|
||||
System.getProperty("line.separator"), "");
|
||||
} catch (final NoSuchAlgorithmException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public void setSalt(final String salt) {
|
||||
this.salt = salt.getBytes();
|
||||
}
|
||||
}
|
@ -0,0 +1,91 @@
|
||||
/*
|
||||
* Licensed to Jasig under one or more contributor license
|
||||
* agreements. See the NOTICE file distributed with this work
|
||||
* for additional information regarding copyright ownership.
|
||||
* Jasig licenses this file to you under the Apache License,
|
||||
* Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a
|
||||
* copy of the License at the following location:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.jasig.cas.authentication.principal;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Simple implementation of a AttributePrincipal that exposes an unmodifiable
|
||||
* map of attributes.
|
||||
*
|
||||
* @author Scott Battaglia
|
||||
* @version $Revision: 1.3 $ $Date: 2007/04/19 20:13:01 $
|
||||
* @since 3.1
|
||||
*/
|
||||
public class SimplePrincipal implements Principal {
|
||||
|
||||
private static final Map<String, Object> EMPTY_MAP = Collections
|
||||
.unmodifiableMap(new HashMap<String, Object>());
|
||||
|
||||
/**
|
||||
* Unique Id for Serialization.
|
||||
*/
|
||||
private static final long serialVersionUID = -5265620187476296219L;
|
||||
|
||||
/** The unique identifier for the principal. */
|
||||
private final String id;
|
||||
|
||||
/** Map of attributes for the Principal. */
|
||||
private Map<String, Object> attributes;
|
||||
|
||||
public SimplePrincipal(final String id) {
|
||||
this(id, null);
|
||||
}
|
||||
|
||||
public SimplePrincipal(final String id, final Map<String, Object> attributes) {
|
||||
Assert.notNull(id, "id cannot be null");
|
||||
this.id = id;
|
||||
|
||||
this.attributes = attributes == null || attributes.isEmpty()
|
||||
? EMPTY_MAP : Collections.unmodifiableMap(attributes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an immutable map.
|
||||
*/
|
||||
public Map<String, Object> getAttributes() {
|
||||
return this.attributes;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return super.hashCode() ^ this.id.hashCode();
|
||||
}
|
||||
|
||||
public final String getId() {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
public boolean equals(final Object o) {
|
||||
if (o == null || !this.getClass().equals(o.getClass())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final SimplePrincipal p = (SimplePrincipal) o;
|
||||
|
||||
return this.id.equals(p.getId());
|
||||
}
|
||||
}
|
@ -0,0 +1,106 @@
|
||||
/*
|
||||
* Licensed to Jasig under one or more contributor license
|
||||
* agreements. See the NOTICE file distributed with this work
|
||||
* for additional information regarding copyright ownership.
|
||||
* Jasig licenses this file to you under the Apache License,
|
||||
* Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a
|
||||
* copy of the License at the following location:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.jasig.cas.authentication.principal;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.jasig.cas.authentication.principal.Response.ResponseType;
|
||||
import org.jasig.cas.util.HttpClient;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Represents a service which wishes to use the CAS protocol.
|
||||
*
|
||||
* @author Scott Battaglia
|
||||
* @version $Revision: 1.3 $ $Date: 2007/04/24 18:19:22 $
|
||||
* @since 3.1
|
||||
*/
|
||||
public final class SimpleWebApplicationServiceImpl extends
|
||||
AbstractWebApplicationService {
|
||||
|
||||
private static final String CONST_PARAM_SERVICE = "service";
|
||||
|
||||
private static final String CONST_PARAM_TARGET_SERVICE = "targetService";
|
||||
|
||||
private static final String CONST_PARAM_TICKET = "ticket";
|
||||
|
||||
private static final String CONST_PARAM_METHOD = "method";
|
||||
|
||||
private final ResponseType responseType;
|
||||
|
||||
/**
|
||||
* Unique Id for Serialization
|
||||
*/
|
||||
private static final long serialVersionUID = 8334068957483758042L;
|
||||
|
||||
public SimpleWebApplicationServiceImpl(final String id) {
|
||||
this(id, id, null, null, null);
|
||||
}
|
||||
|
||||
public SimpleWebApplicationServiceImpl(final String id, final HttpClient httpClient) {
|
||||
this(id, id, null, null, httpClient);
|
||||
}
|
||||
|
||||
private SimpleWebApplicationServiceImpl(final String id,
|
||||
final String originalUrl, final String artifactId,
|
||||
final ResponseType responseType, final HttpClient httpClient) {
|
||||
super(id, originalUrl, artifactId, httpClient);
|
||||
this.responseType = responseType;
|
||||
}
|
||||
|
||||
public static SimpleWebApplicationServiceImpl createServiceFrom(final HttpServletRequest request) {
|
||||
return createServiceFrom(request, null);
|
||||
}
|
||||
|
||||
public static SimpleWebApplicationServiceImpl createServiceFrom(
|
||||
final HttpServletRequest request, final HttpClient httpClient) {
|
||||
final String targetService = request
|
||||
.getParameter(CONST_PARAM_TARGET_SERVICE);
|
||||
final String method = request.getParameter(CONST_PARAM_METHOD);
|
||||
final String serviceToUse = StringUtils.hasText(targetService)
|
||||
? targetService : request.getParameter(CONST_PARAM_SERVICE);
|
||||
|
||||
if (!StringUtils.hasText(serviceToUse)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final String id = cleanupUrl(serviceToUse);
|
||||
final String artifactId = request.getParameter(CONST_PARAM_TICKET);
|
||||
|
||||
return new SimpleWebApplicationServiceImpl(id, serviceToUse,
|
||||
artifactId, "POST".equals(method) ? ResponseType.POST
|
||||
: ResponseType.REDIRECT, httpClient);
|
||||
}
|
||||
|
||||
public Response getResponse(final String ticketId) {
|
||||
final Map<String, String> parameters = new HashMap<String, String>();
|
||||
|
||||
if (StringUtils.hasText(ticketId)) {
|
||||
parameters.put(CONST_PARAM_TICKET, ticketId);
|
||||
}
|
||||
|
||||
if (ResponseType.POST == this.responseType) {
|
||||
return Response.getPostResponse(getOriginalUrl(), parameters);
|
||||
}
|
||||
return Response.getRedirectResponse(getOriginalUrl(), parameters);
|
||||
}
|
||||
}
|
@ -0,0 +1,101 @@
|
||||
/*
|
||||
* Licensed to Jasig under one or more contributor license
|
||||
* agreements. See the NOTICE file distributed with this work
|
||||
* for additional information regarding copyright ownership.
|
||||
* Jasig licenses this file to you under the Apache License,
|
||||
* Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a
|
||||
* copy of the License at the following location:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.jasig.cas.authentication.principal;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
import javax.validation.constraints.Size;
|
||||
|
||||
/**
|
||||
* UsernamePasswordCredentials respresents the username and password that a user
|
||||
* may provide in order to prove the authenticity of who they say they are.
|
||||
*
|
||||
* @author Scott Battaglia
|
||||
* @version $Revision: 1.2 $ $Date: 2007/01/22 20:35:26 $
|
||||
* @since 3.0
|
||||
* <p>
|
||||
* This is a published and supported CAS Server 3 API.
|
||||
* </p>
|
||||
*/
|
||||
public class UsernamePasswordCredentials implements Credentials {
|
||||
|
||||
/** Unique ID for serialization. */
|
||||
private static final long serialVersionUID = -8343864967200862794L;
|
||||
|
||||
/** The username. */
|
||||
@NotNull
|
||||
@Size(min=1,message = "required.username")
|
||||
private String username;
|
||||
|
||||
/** The password. */
|
||||
@NotNull
|
||||
@Size(min=1, message = "required.password")
|
||||
private String password;
|
||||
|
||||
/**
|
||||
* @return Returns the password.
|
||||
*/
|
||||
public final String getPassword() {
|
||||
return this.password;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param password The password to set.
|
||||
*/
|
||||
public final void setPassword(final String password) {
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Returns the userName.
|
||||
*/
|
||||
public final String getUsername() {
|
||||
return this.username;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param userName The userName to set.
|
||||
*/
|
||||
public final void setUsername(final String userName) {
|
||||
this.username = userName;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "[username: " + this.username + "]";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
UsernamePasswordCredentials that = (UsernamePasswordCredentials) o;
|
||||
|
||||
if (password != null ? !password.equals(that.password) : that.password != null) return false;
|
||||
if (username != null ? !username.equals(that.username) : that.username != null) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = username != null ? username.hashCode() : 0;
|
||||
result = 31 * result + (password != null ? password.hashCode() : 0);
|
||||
return result;
|
||||
}
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Licensed to Jasig under one or more contributor license
|
||||
* agreements. See the NOTICE file distributed with this work
|
||||
* for additional information regarding copyright ownership.
|
||||
* Jasig licenses this file to you under the Apache License,
|
||||
* Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a
|
||||
* copy of the License at the following location:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.jasig.cas.authentication.principal;
|
||||
|
||||
/**
|
||||
* Implementation of CredentialsToPrincipalResolver for Credentials based on
|
||||
* UsernamePasswordCredentials when a SimplePrincipal (username only) is
|
||||
* sufficient.
|
||||
* <p>
|
||||
* Implementation extracts the username from the Credentials provided and
|
||||
* constructs a new SimplePrincipal with the unique id set to the username.
|
||||
* </p>
|
||||
*
|
||||
* @author Scott Battaglia
|
||||
* @version $Revision: 1.2 $ $Date: 2007/01/22 20:35:26 $
|
||||
* @since 3.0
|
||||
* @see org.jasig.cas.authentication.principal.SimplePrincipal
|
||||
*/
|
||||
public final class UsernamePasswordCredentialsToPrincipalResolver extends
|
||||
AbstractPersonDirectoryCredentialsToPrincipalResolver {
|
||||
|
||||
protected String extractPrincipalId(final Credentials credentials) {
|
||||
final UsernamePasswordCredentials usernamePasswordCredentials = (UsernamePasswordCredentials) credentials;
|
||||
return usernamePasswordCredentials.getUsername();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if Credentials are UsernamePasswordCredentials, false
|
||||
* otherwise.
|
||||
*/
|
||||
public boolean supports(final Credentials credentials) {
|
||||
return credentials != null
|
||||
&& UsernamePasswordCredentials.class.isAssignableFrom(credentials
|
||||
.getClass());
|
||||
}
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Licensed to Jasig under one or more contributor license
|
||||
* agreements. See the NOTICE file distributed with this work
|
||||
* for additional information regarding copyright ownership.
|
||||
* Jasig licenses this file to you under the Apache License,
|
||||
* Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a
|
||||
* copy of the License at the following location:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.jasig.cas.authentication.principal;
|
||||
|
||||
/**
|
||||
* Represents a service using CAS that comes from the web.
|
||||
*
|
||||
* @author Scott Battaglia
|
||||
* @version $Revision: 1.3 $ $Date: 2007/02/27 19:31:58 $
|
||||
* @since 3.1
|
||||
*/
|
||||
public interface WebApplicationService extends Service {
|
||||
|
||||
/**
|
||||
* Constructs the url to redirect the service back to.
|
||||
*
|
||||
* @param ticketId the service ticket to provide to the service.
|
||||
* @return the redirect url.
|
||||
*/
|
||||
Response getResponse(String ticketId);
|
||||
|
||||
/**
|
||||
* Retrieves the artifact supplied with the service. May be null.
|
||||
*
|
||||
* @return the artifact if it exists, null otherwise.
|
||||
*/
|
||||
String getArtifactId();
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
<!--
|
||||
|
||||
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.
|
||||
|
||||
-->
|
||||
<html>
|
||||
<body>
|
||||
<p>Credentials is a marker interface for an opaque object that may be recognized by
|
||||
Handlers and Resolvers. Credentials may be a Userid/Password, Certificate,
|
||||
RemoteUser, IP address, etc.</p>
|
||||
<p>When the simple AuthenticationManagerImpl is
|
||||
used, that bean is configured with a list of AuthenticationHandlers that
|
||||
validate Credentials and CredentialsToPrincipalResolvers that turn Credentials
|
||||
into Principal objects.</p>
|
||||
<p>The Authentication Handler validates Credentials but does not extract
|
||||
information. This seems curious in the simple case when the credentials are a
|
||||
Userid/Password. It becomes clearer for a Certificate. A Certificate is valid if
|
||||
you trust the CA, if it hasn't expired, and if it isn't revoked. You can decide
|
||||
all this, and still not have the foggiest idea what ID to give to the person (if
|
||||
it is a person) reprepsented by the Certificate.</p>
|
||||
<p>The CredentialsToPrincipalResolver looks into previously validated
|
||||
Credentials to construct a Principal object containing an ID (and in more
|
||||
complex cases some attributes). The DefaultCredentialsToPrincipalResolver takes
|
||||
UsernamePasswordCredentials and creates a SimplePrincipal containing the Userid.</p>
|
||||
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,109 @@
|
||||
/*
|
||||
* Licensed to Jasig under one or more contributor license
|
||||
* agreements. See the NOTICE file distributed with this work
|
||||
* for additional information regarding copyright ownership.
|
||||
* Jasig licenses this file to you under the Apache License,
|
||||
* Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a
|
||||
* copy of the License at the following location:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
package org.jasig.cas.monitor;
|
||||
|
||||
/**
|
||||
* Abstract base class for monitors that observe cache storage systems.
|
||||
*
|
||||
* @author Marvin S. Addison
|
||||
* @since 3.5.1
|
||||
*/
|
||||
public abstract class AbstractCacheMonitor extends AbstractNamedMonitor<CacheStatus> {
|
||||
|
||||
/** Default free capacity threshold is 10%. */
|
||||
public static final int DEFAULT_WARN_FREE_THRESHOLD = 10;
|
||||
|
||||
/** Default eviction threshold is 0. */
|
||||
public static final long DEFAULT_EVICTION_THRESHOLD = 0;
|
||||
|
||||
/** Percent free capacity threshold below which a warning is issued.*/
|
||||
private int warnFreeThreshold = DEFAULT_WARN_FREE_THRESHOLD;
|
||||
|
||||
/** Threshold for number of acceptable evictions above which an error is issued. */
|
||||
private long evictionThreshold = DEFAULT_EVICTION_THRESHOLD;
|
||||
|
||||
|
||||
/**
|
||||
* Sets the percent free capacity threshold below which a warning is issued.
|
||||
*
|
||||
* @param percent Warning threshold percent.
|
||||
*/
|
||||
public void setWarnFreeThreshold(final int percent) {
|
||||
this.warnFreeThreshold = percent;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets the eviction threshold count above which an error is issued.
|
||||
*
|
||||
* @param count Threshold for number of cache evictions.
|
||||
*/
|
||||
public void setEvictionThreshold(final long count) {
|
||||
this.evictionThreshold = count;
|
||||
}
|
||||
|
||||
|
||||
public CacheStatus observe() {
|
||||
CacheStatus status;
|
||||
try {
|
||||
final CacheStatistics[] statistics = getStatistics();
|
||||
if (statistics == null || statistics.length == 0) {
|
||||
return new CacheStatus(StatusCode.ERROR, "Cache statistics not available.");
|
||||
}
|
||||
StatusCode overall = StatusCode.OK;
|
||||
StatusCode code;
|
||||
for (final CacheStatistics stats : statistics) {
|
||||
code = status(stats);
|
||||
// Record highest status which is equivalent to worst case
|
||||
if (code.value() > overall.value()) {
|
||||
overall = code;
|
||||
}
|
||||
}
|
||||
status = new CacheStatus(overall, null, statistics);
|
||||
} catch (final Exception e) {
|
||||
status = new CacheStatus(e);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
protected abstract CacheStatistics[] getStatistics();
|
||||
|
||||
|
||||
/**
|
||||
* Computes the status code for a given set of cache statistics.
|
||||
*
|
||||
* @param statistics Cache statistics.
|
||||
*
|
||||
* @return {@link StatusCode#WARN} if eviction count is above threshold or if
|
||||
* percent free space is below threshold, otherwise {@link StatusCode#OK}.
|
||||
*/
|
||||
protected StatusCode status(final CacheStatistics statistics) {
|
||||
final StatusCode code;
|
||||
if (statistics.getEvictions() > this.evictionThreshold) {
|
||||
code = StatusCode.WARN;
|
||||
} else if (statistics.getPercentFree() < this.warnFreeThreshold) {
|
||||
code = StatusCode.WARN;
|
||||
} else {
|
||||
code = StatusCode.OK;
|
||||
}
|
||||
return code;
|
||||
}
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Licensed to Jasig under one or more contributor license
|
||||
* agreements. See the NOTICE file distributed with this work
|
||||
* for additional information regarding copyright ownership.
|
||||
* Jasig licenses this file to you under the Apache License,
|
||||
* Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a
|
||||
* copy of the License at the following location:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.jasig.cas.monitor;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Base class for all monitors that support configurable naming.
|
||||
*
|
||||
* @author Marvin S. Addison
|
||||
* @since 3.5.0
|
||||
*/
|
||||
public abstract class AbstractNamedMonitor<S extends Status> implements Monitor<S> {
|
||||
/** Monitor name. */
|
||||
protected String name;
|
||||
|
||||
|
||||
/**
|
||||
* @return Monitor name.
|
||||
*/
|
||||
public String getName() {
|
||||
return StringUtils.defaultIfEmpty(this.name, getClass().getSimpleName());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param n Monitor name.
|
||||
*/
|
||||
public void setName(final String n) {
|
||||
Assert.hasText(n, "Monitor name cannot be null or empty.");
|
||||
this.name = n;
|
||||
}
|
||||
}
|
@ -0,0 +1,122 @@
|
||||
/*
|
||||
* Licensed to Jasig under one or more contributor license
|
||||
* agreements. See the NOTICE file distributed with this work
|
||||
* for additional information regarding copyright ownership.
|
||||
* Jasig licenses this file to you under the Apache License,
|
||||
* Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a
|
||||
* copy of the License at the following location:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.jasig.cas.monitor;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
/**
|
||||
* Describes a monitor that observes a pool of resources.
|
||||
*
|
||||
* @author Marvin S. Addison
|
||||
* @since 3.5.0
|
||||
*/
|
||||
public abstract class AbstractPoolMonitor extends AbstractNamedMonitor<PoolStatus> {
|
||||
|
||||
/** Default maximum wait time for asynchronous pool validation. */
|
||||
public static final int DEFAULT_MAX_WAIT = 3000;
|
||||
|
||||
/** Maximum amount of time in ms to wait while validating pool resources. */
|
||||
private int maxWait = DEFAULT_MAX_WAIT;
|
||||
|
||||
/** Executor that performs pool resource validation. */
|
||||
@NotNull
|
||||
private ExecutorService executor;
|
||||
|
||||
|
||||
/**
|
||||
* Sets the executor service responsible for pool resource validation.
|
||||
*
|
||||
* @param executorService Executor of pool validation operations.
|
||||
*/
|
||||
public void setExecutor(final ExecutorService executorService) {
|
||||
this.executor = executorService;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the maximum amount of time wait while validating pool resources.
|
||||
* If the pool defines a minumum time to wait for a resource, this property
|
||||
* should be set less than that value.
|
||||
*
|
||||
* @param time Wait time in milliseconds.
|
||||
*/
|
||||
public void setMaxWait(final int time) {
|
||||
this.maxWait = time;
|
||||
}
|
||||
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public PoolStatus observe() {
|
||||
final Future<StatusCode> result = this.executor.submit(new Validator());
|
||||
StatusCode code;
|
||||
String description = null;
|
||||
try {
|
||||
code = result.get(this.maxWait, TimeUnit.MILLISECONDS);
|
||||
} catch (final InterruptedException e) {
|
||||
code = StatusCode.UNKNOWN;
|
||||
description = "Validator thread interrupted during pool validation.";
|
||||
} catch (final TimeoutException e) {
|
||||
code = StatusCode.WARN;
|
||||
description = String.format("Pool validation timed out. Max wait is %s ms.", this.maxWait);
|
||||
} catch (final Exception e) {
|
||||
code = StatusCode.ERROR;
|
||||
description = e.getMessage();
|
||||
}
|
||||
return new PoolStatus(code, description, getActiveCount(), getIdleCount());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Performs a health check on a the pool. The recommended implementation is to
|
||||
* obtain a pool resource, validate it, and return it to the pool.
|
||||
*
|
||||
* @return Status code describing pool health.
|
||||
*
|
||||
* @throws Exception Thrown to indicate a serious problem with pool validation.
|
||||
*/
|
||||
protected abstract StatusCode checkPool() throws Exception;
|
||||
|
||||
|
||||
/**
|
||||
* Gets the number of pool resources idle at present.
|
||||
*
|
||||
* @return Number of idle pool resources.
|
||||
*/
|
||||
protected abstract int getIdleCount();
|
||||
|
||||
|
||||
/**
|
||||
* Gets the number of pool resources active at present.
|
||||
*
|
||||
* @return Number of active pool resources.
|
||||
*/
|
||||
protected abstract int getActiveCount();
|
||||
|
||||
|
||||
private class Validator implements Callable<StatusCode> {
|
||||
public StatusCode call() throws Exception {
|
||||
return checkPool();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Licensed to Jasig under one or more contributor license
|
||||
* agreements. See the NOTICE file distributed with this work
|
||||
* for additional information regarding copyright ownership.
|
||||
* Jasig licenses this file to you under the Apache License,
|
||||
* Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a
|
||||
* copy of the License at the following location:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.jasig.cas.monitor;
|
||||
|
||||
/**
|
||||
* Describes the simplest set of cache statistics that are meaningful for health monitoring.
|
||||
*
|
||||
* @author Marvin S. Addison
|
||||
* @since 3.5.1
|
||||
*/
|
||||
public interface CacheStatistics {
|
||||
|
||||
/**
|
||||
* Gets the current size of the cache in a unit specific to the cache being monitored (e.g. bytes, items, etc).
|
||||
*
|
||||
* @return Current cache size.
|
||||
*/
|
||||
long getSize();
|
||||
|
||||
|
||||
/**
|
||||
* Gets the current capacity of the cache in a unit specific to the cache being monitored (e.g. bytes, items, etc).
|
||||
*
|
||||
* @return Current cache capacity.
|
||||
*/
|
||||
long getCapacity();
|
||||
|
||||
|
||||
/**
|
||||
* Gets the number of items evicted from the cache in order to make space for new items.
|
||||
*
|
||||
* @return Eviction count.
|
||||
*/
|
||||
long getEvictions();
|
||||
|
||||
|
||||
/**
|
||||
* Gets the percent free capacity remaining in the cache.
|
||||
*
|
||||
* @return Percent of space/capacity free.
|
||||
*/
|
||||
int getPercentFree();
|
||||
|
||||
|
||||
/**
|
||||
* Gets a descriptive name of the cache instance for which statistics apply.
|
||||
*
|
||||
* @return Name of cache instance/host to which statistics apply.
|
||||
*/
|
||||
String getName();
|
||||
|
||||
|
||||
/**
|
||||
* Writes a string representation of cache statistics to the given string builder.
|
||||
*
|
||||
* @param builder String builder to which string representation is appended.
|
||||
*/
|
||||
void toString(StringBuilder builder);
|
||||
|
||||
}
|
@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Licensed to Jasig under one or more contributor license
|
||||
* agreements. See the NOTICE file distributed with this work
|
||||
* for additional information regarding copyright ownership.
|
||||
* Jasig licenses this file to you under the Apache License,
|
||||
* Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a
|
||||
* copy of the License at the following location:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
package org.jasig.cas.monitor;
|
||||
|
||||
/**
|
||||
* Describes meaningful health metrics on the status of a cache.
|
||||
*
|
||||
* @author Marvin S. Addison
|
||||
* @since 3.5.1
|
||||
*/
|
||||
public class CacheStatus extends Status {
|
||||
|
||||
private final CacheStatistics[] statistics;
|
||||
|
||||
/**
|
||||
* Creates a new instance describing cache status.
|
||||
*
|
||||
* @param code Status code.
|
||||
* @param description Optional status description.
|
||||
* @param statistics One or more sets of cache statistics.
|
||||
*/
|
||||
public CacheStatus(final StatusCode code, final String description, final CacheStatistics... statistics) {
|
||||
super(code, buildDescription(description, statistics));
|
||||
this.statistics = statistics;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new instance when cache statistics are unavailable due to given exception.
|
||||
*
|
||||
* @param e Cause of unavailable statistics.
|
||||
*/
|
||||
public CacheStatus(final Exception e) {
|
||||
super(StatusCode.ERROR,
|
||||
String.format("Error fetching cache status: %s::%s", e.getClass().getSimpleName(), e.getMessage()));
|
||||
this.statistics = null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets the current cache statistics.
|
||||
*
|
||||
* @return Cache statistics.
|
||||
*/
|
||||
public CacheStatistics[] getStatistics() {
|
||||
return this.statistics;
|
||||
}
|
||||
|
||||
|
||||
private static String buildDescription(final String desc, final CacheStatistics... statistics) {
|
||||
if (statistics == null || statistics.length == 0) {
|
||||
return desc;
|
||||
}
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
if (desc != null) {
|
||||
sb.append(desc);
|
||||
if (!desc.endsWith(".")) {
|
||||
sb.append('.');
|
||||
}
|
||||
sb.append(' ');
|
||||
}
|
||||
sb.append("Cache statistics: [");
|
||||
int i = 0;
|
||||
for (final CacheStatistics stats : statistics) {
|
||||
if (i++ > 0) {
|
||||
sb.append('|');
|
||||
}
|
||||
stats.toString(sb);
|
||||
}
|
||||
sb.append(']');
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Licensed to Jasig under one or more contributor license
|
||||
* agreements. See the NOTICE file distributed with this work
|
||||
* for additional information regarding copyright ownership.
|
||||
* Jasig licenses this file to you under the Apache License,
|
||||
* Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a
|
||||
* copy of the License at the following location:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.jasig.cas.monitor;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import javax.sql.DataSource;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.jdbc.core.ResultSetExtractor;
|
||||
|
||||
/**
|
||||
* Monitors a data source that describes a single connection or connection pool to a database.
|
||||
*
|
||||
* @author Marvin S. Addison
|
||||
* @since 3.5.1
|
||||
*/
|
||||
public class DataSourceMonitor extends AbstractPoolMonitor {
|
||||
|
||||
@NotNull
|
||||
private final JdbcTemplate jdbcTemplate;
|
||||
|
||||
@NotNull
|
||||
private String validationQuery;
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new instance that monitors the given data source.
|
||||
*
|
||||
* @param dataSource Data source to monitor.
|
||||
*/
|
||||
public DataSourceMonitor(final DataSource dataSource) {
|
||||
this.jdbcTemplate = new JdbcTemplate(dataSource);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets the validation query used to monitor the data source. The validation query should return
|
||||
* at least one result; otherwise results are ignored.
|
||||
*
|
||||
* @param query Validation query that should be as efficient as possible.
|
||||
*/
|
||||
public void setValidationQuery(final String query) {
|
||||
this.validationQuery = query;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected StatusCode checkPool() throws Exception {
|
||||
return this.jdbcTemplate.query(this.validationQuery, new ResultSetExtractor<StatusCode>() {
|
||||
public StatusCode extractData(final ResultSet rs) throws SQLException, DataAccessException {
|
||||
if (rs.next()) {
|
||||
return StatusCode.OK;
|
||||
}
|
||||
return StatusCode.WARN;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected int getIdleCount() {
|
||||
return PoolStatus.UNKNOWN_COUNT;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected int getActiveCount() {
|
||||
return PoolStatus.UNKNOWN_COUNT;
|
||||
}
|
||||
}
|
@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Licensed to Jasig under one or more contributor license
|
||||
* agreements. See the NOTICE file distributed with this work
|
||||
* for additional information regarding copyright ownership.
|
||||
* Jasig licenses this file to you under the Apache License,
|
||||
* Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a
|
||||
* copy of the License at the following location:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.jasig.cas.monitor;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
/**
|
||||
* Simple health check monitor that reports the overall health as the greatest reported
|
||||
* {@link StatusCode} of an arbitrary number of individual checks.
|
||||
*
|
||||
* @author Marvin S. Addison
|
||||
* @since 3.5.0
|
||||
*/
|
||||
public class HealthCheckMonitor implements Monitor<HealthStatus> {
|
||||
/** Individual monitors that comprise health check. */
|
||||
@NotNull
|
||||
private Collection<Monitor> monitors = Collections.emptySet();
|
||||
|
||||
|
||||
/**
|
||||
* Sets the monitors that comprise the health check.
|
||||
*
|
||||
* @param monitors Collection of monitors responsible for observing various aspects of CAS.
|
||||
*/
|
||||
public void setMonitors(final Collection<Monitor> monitors) {
|
||||
this.monitors = monitors;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public String getName() {
|
||||
return HealthCheckMonitor.class.getSimpleName();
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public HealthStatus observe() {
|
||||
final Map<String, Status> results = new LinkedHashMap<String, Status>(this.monitors.size());
|
||||
StatusCode code = StatusCode.UNKNOWN;
|
||||
Status result;
|
||||
for (final Monitor monitor : this.monitors) {
|
||||
try {
|
||||
result = monitor.observe();
|
||||
if (result.getCode().value() > code.value()) {
|
||||
code = result.getCode();
|
||||
}
|
||||
} catch (final Exception e) {
|
||||
code = StatusCode.ERROR;
|
||||
result = new Status(code, e.getClass().getSimpleName() + ": " + e.getMessage());
|
||||
}
|
||||
results.put(monitor.getName(), result);
|
||||
}
|
||||
|
||||
return new HealthStatus(code, results);
|
||||
}
|
||||
}
|
@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Licensed to Jasig under one or more contributor license
|
||||
* agreements. See the NOTICE file distributed with this work
|
||||
* for additional information regarding copyright ownership.
|
||||
* Jasig licenses this file to you under the Apache License,
|
||||
* Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a
|
||||
* copy of the License at the following location:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.jasig.cas.monitor;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Describes the overall health status of the CAS server as determined by composite status values.
|
||||
*
|
||||
* @author Marvin S. Addison
|
||||
* @since 3.5.0
|
||||
*/
|
||||
public class HealthStatus extends Status {
|
||||
/** Map of names (e.g. monitor that produced it) to status information. */
|
||||
private final Map<String, Status> details;
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new status object with the given code.
|
||||
*
|
||||
* @param code Status code.
|
||||
* @param detailMap Map of names to status information. A reasonable name would be, for example, the name of
|
||||
* the monitor that produced it.
|
||||
* @see #getCode()
|
||||
*/
|
||||
public HealthStatus(final StatusCode code, final Map<String, Status> detailMap) {
|
||||
super(code);
|
||||
this.details = Collections.unmodifiableMap(detailMap);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets the status details comprising the individual health checks performed for overall health status.
|
||||
*
|
||||
* @return Map of named status items to status information for each check performed.
|
||||
*/
|
||||
public Map<String, Status> getDetails() {
|
||||
return this.details;
|
||||
}
|
||||
}
|
@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Licensed to Jasig under one or more contributor license
|
||||
* agreements. See the NOTICE file distributed with this work
|
||||
* for additional information regarding copyright ownership.
|
||||
* Jasig licenses this file to you under the Apache License,
|
||||
* Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a
|
||||
* copy of the License at the following location:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.jasig.cas.monitor;
|
||||
|
||||
/**
|
||||
* Monitors JVM memory usage.
|
||||
*
|
||||
* @author Marvin S. Addison
|
||||
* @since 3.5.0
|
||||
*/
|
||||
public class MemoryMonitor implements Monitor<MemoryStatus> {
|
||||
|
||||
/** Default percent free memory warning threshold. */
|
||||
public static final int DEFAULT_FREE_MEMORY_WARN_THRESHOLD = 10;
|
||||
|
||||
/** Percent free memory warning threshold. */
|
||||
private long freeMemoryWarnThreshold = DEFAULT_FREE_MEMORY_WARN_THRESHOLD;
|
||||
|
||||
|
||||
/**
|
||||
* Sets the percent of free memory below which a warning is reported.
|
||||
*
|
||||
* @param threshold Percent free memory warning threshold.
|
||||
*/
|
||||
public void setFreeMemoryWarnThreshold(final long threshold) {
|
||||
if (threshold < 0) {
|
||||
throw new IllegalArgumentException("Warning threshold must be non-negative.");
|
||||
}
|
||||
this.freeMemoryWarnThreshold = threshold;
|
||||
}
|
||||
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public String getName() {
|
||||
return MemoryMonitor.class.getSimpleName();
|
||||
}
|
||||
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public MemoryStatus observe() {
|
||||
final StatusCode code;
|
||||
final long free = Runtime.getRuntime().freeMemory();
|
||||
final long total = Runtime.getRuntime().totalMemory();
|
||||
if (free * 100 / total < this.freeMemoryWarnThreshold) {
|
||||
code = StatusCode.WARN;
|
||||
} else {
|
||||
code = StatusCode.OK;
|
||||
}
|
||||
return new MemoryStatus(code, free, total);
|
||||
}
|
||||
}
|
@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Licensed to Jasig under one or more contributor license
|
||||
* agreements. See the NOTICE file distributed with this work
|
||||
* for additional information regarding copyright ownership.
|
||||
* Jasig licenses this file to you under the Apache License,
|
||||
* Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a
|
||||
* copy of the License at the following location:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.jasig.cas.monitor;
|
||||
|
||||
/**
|
||||
* Describes the memory status of the JVM.
|
||||
*
|
||||
* @author Marvin S. Addison
|
||||
* @since 3.5.0
|
||||
*/
|
||||
public class MemoryStatus extends Status {
|
||||
|
||||
private static final double BYTES_PER_MB = 1048510.0;
|
||||
|
||||
/** JVM free memory. */
|
||||
private final long freeMemory;
|
||||
|
||||
/** JVM total memory. */
|
||||
private final long totalMemory;
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new status object with the given code.
|
||||
*
|
||||
* @param code Status code.
|
||||
* @param free JVM free memory in bytes.
|
||||
* @param total JVM total memory in bytes.
|
||||
*
|
||||
* @see #getCode()
|
||||
*/
|
||||
public MemoryStatus(final StatusCode code, final long free, final long total) {
|
||||
super(code, String.format("%.2fMB free, %.2fMB total.", free / BYTES_PER_MB, total / BYTES_PER_MB));
|
||||
this.freeMemory = free;
|
||||
this.totalMemory = total;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets JVM free memory.
|
||||
*
|
||||
* @return Free memory in bytes.
|
||||
*/
|
||||
public long getFreeMemory() {
|
||||
return this.freeMemory;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets JVM total memory.
|
||||
*
|
||||
* @return Max memory in bytes.
|
||||
*/
|
||||
public long getTotalMemory() {
|
||||
return this.totalMemory;
|
||||
}
|
||||
}
|
@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Licensed to Jasig under one or more contributor license
|
||||
* agreements. See the NOTICE file distributed with this work
|
||||
* for additional information regarding copyright ownership.
|
||||
* Jasig licenses this file to you under the Apache License,
|
||||
* Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a
|
||||
* copy of the License at the following location:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.jasig.cas.monitor;
|
||||
|
||||
/**
|
||||
* A monitor observes a resource and reports its status.
|
||||
*
|
||||
* @author Marvin S. Addison
|
||||
* @since 3.5.0
|
||||
*/
|
||||
public interface Monitor<S extends Status> {
|
||||
|
||||
/**
|
||||
* Gets the name of the monitor.
|
||||
*
|
||||
* @return Monitor name.
|
||||
*/
|
||||
String getName();
|
||||
|
||||
|
||||
/**
|
||||
* Observes the monitored resource and reports the status.
|
||||
*
|
||||
* @return Status of monitored resource.
|
||||
*/
|
||||
S observe();
|
||||
}
|
@ -0,0 +1,96 @@
|
||||
/*
|
||||
* Licensed to Jasig under one or more contributor license
|
||||
* agreements. See the NOTICE file distributed with this work
|
||||
* for additional information regarding copyright ownership.
|
||||
* Jasig licenses this file to you under the Apache License,
|
||||
* Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a
|
||||
* copy of the License at the following location:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.jasig.cas.monitor;
|
||||
|
||||
/**
|
||||
* Describes the status of a resource pool.
|
||||
*
|
||||
* @author Marvin S. Addison
|
||||
* @since 3.5.0
|
||||
*/
|
||||
public class PoolStatus extends Status {
|
||||
/**
|
||||
* Return value for {@link #getActiveCount()} and {@link #getIdleCount()}
|
||||
* when pool metrics are unknown or unknowable.
|
||||
*/
|
||||
public static final int UNKNOWN_COUNT = -1;
|
||||
|
||||
/** Number of idle pool resources. */
|
||||
private final int idleCount;
|
||||
|
||||
/** Number of active pool resources. */
|
||||
private final int activeCount;
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new status object with the given code.
|
||||
*
|
||||
* @param code Status code.
|
||||
* @param desc Human-readable status description.
|
||||
*
|
||||
* @see #getCode()
|
||||
*/
|
||||
public PoolStatus(final StatusCode code, final String desc, final int active, final int idle) {
|
||||
super(code, buildDescription(desc, active, idle));
|
||||
this.activeCount = active;
|
||||
this.idleCount = idle;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets the number of idle pool resources.
|
||||
*
|
||||
* @return Number of idle pool members.
|
||||
*/
|
||||
public int getIdleCount() {
|
||||
return this.idleCount;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets the number of active pool resources.
|
||||
*
|
||||
* @return Number of active pool members.
|
||||
*/
|
||||
public int getActiveCount() {
|
||||
return this.activeCount;
|
||||
}
|
||||
|
||||
|
||||
private static String buildDescription(final String desc, final int active, final int idle) {
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
if (desc != null) {
|
||||
sb.append(desc);
|
||||
if (!desc.endsWith(".")) {
|
||||
sb.append('.');
|
||||
}
|
||||
sb.append(' ');
|
||||
}
|
||||
if (active != UNKNOWN_COUNT) {
|
||||
sb.append(active).append(" active");
|
||||
}
|
||||
if (idle != UNKNOWN_COUNT) {
|
||||
sb.append(", ").append(idle).append(" idle.");
|
||||
}
|
||||
if (sb.length() > 0) {
|
||||
return sb.toString();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
@ -0,0 +1,114 @@
|
||||
/*
|
||||
* Licensed to Jasig under one or more contributor license
|
||||
* agreements. See the NOTICE file distributed with this work
|
||||
* for additional information regarding copyright ownership.
|
||||
* Jasig licenses this file to you under the Apache License,
|
||||
* Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a
|
||||
* copy of the License at the following location:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.jasig.cas.monitor;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
/**
|
||||
* Monitors the status of a {@link org.jasig.cas.ticket.registry.TicketRegistry}
|
||||
* that supports the {@link TicketRegistryState} interface for exposing internal
|
||||
* state information used in status reports.
|
||||
*
|
||||
* @author Marvin S. Addison
|
||||
* @since 3.5.0
|
||||
*/
|
||||
public class SessionMonitor implements Monitor<SessionStatus> {
|
||||
/** Ticket registry instance that exposes state info. */
|
||||
@NotNull
|
||||
private TicketRegistryState registryState;
|
||||
|
||||
/** Threshold above which warnings are issued for session count. */
|
||||
private int sessionCountWarnThreshold = -1;
|
||||
|
||||
/** Threshold above which warnings are issued for service ticket count. */
|
||||
private int serviceTicketCountWarnThreshold = -1;
|
||||
|
||||
|
||||
/**
|
||||
* Sets the ticket registry that exposes state information that may be queried by this monitor.
|
||||
* @param state
|
||||
*/
|
||||
public void setTicketRegistry(final TicketRegistryState state) {
|
||||
this.registryState = state;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets the threshold above which warnings are issued for session counts in excess of value.
|
||||
*
|
||||
* @param threshold Warn threshold if non-negative value, otherwise warnings are disabled.
|
||||
*/
|
||||
public void setSessionCountWarnThreshold(final int threshold) {
|
||||
this.sessionCountWarnThreshold = threshold;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets the threshold above which warnings are issued for service ticket counts in excess of value.
|
||||
*
|
||||
* @param threshold Warn threshold if non-negative value, otherwise warnings are disabled.
|
||||
*/
|
||||
public void setServiceTicketCountWarnThreshold(final int threshold) {
|
||||
this.serviceTicketCountWarnThreshold = threshold;
|
||||
}
|
||||
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public String getName() {
|
||||
return SessionMonitor.class.getSimpleName();
|
||||
}
|
||||
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public SessionStatus observe() {
|
||||
try {
|
||||
final int sessionCount = this.registryState.sessionCount();
|
||||
final int ticketCount = this.registryState.serviceTicketCount();
|
||||
|
||||
if (sessionCount == Integer.MIN_VALUE || ticketCount == Integer.MIN_VALUE) {
|
||||
return new SessionStatus(StatusCode.UNKNOWN,
|
||||
String.format("Ticket registry %s reports unknown session and/or ticket counts.",
|
||||
this.registryState.getClass().getName()),
|
||||
sessionCount, ticketCount);
|
||||
}
|
||||
|
||||
final StringBuilder msg = new StringBuilder();
|
||||
StatusCode code = StatusCode.OK;
|
||||
if (this.sessionCountWarnThreshold > -1 && sessionCount > this.sessionCountWarnThreshold) {
|
||||
code = StatusCode.WARN;
|
||||
msg.append(String.format(
|
||||
"Session count (%s) is above threshold %s. ", sessionCount, this.sessionCountWarnThreshold));
|
||||
} else {
|
||||
msg.append(sessionCount).append(" sessions. ");
|
||||
}
|
||||
if (this.serviceTicketCountWarnThreshold > -1 && ticketCount > this.serviceTicketCountWarnThreshold) {
|
||||
code = StatusCode.WARN;
|
||||
msg.append(String.format(
|
||||
"Service ticket count (%s) is above threshold %s.",
|
||||
ticketCount,
|
||||
this.serviceTicketCountWarnThreshold));
|
||||
} else {
|
||||
msg.append(ticketCount).append(" service tickets.");
|
||||
}
|
||||
return new SessionStatus(code, msg.toString(), sessionCount, ticketCount);
|
||||
} catch (final Exception e) {
|
||||
return new SessionStatus(StatusCode.ERROR, e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Licensed to Jasig under one or more contributor license
|
||||
* agreements. See the NOTICE file distributed with this work
|
||||
* for additional information regarding copyright ownership.
|
||||
* Jasig licenses this file to you under the Apache License,
|
||||
* Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a
|
||||
* copy of the License at the following location:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.jasig.cas.monitor;
|
||||
|
||||
/**
|
||||
* Provides status information about the number of SSO sessions established in CAS.
|
||||
*
|
||||
* @author Marvin S. Addison
|
||||
* @since 3.5.0
|
||||
*/
|
||||
public class SessionStatus extends Status {
|
||||
/** Total number of SSO sessions maintained by CAS. */
|
||||
private final int sessionCount;
|
||||
|
||||
/** Total number of service tickets in CAS ticket registry. */
|
||||
private final int serviceTicketCount;
|
||||
|
||||
/**
|
||||
* Creates a new status object with the given code.
|
||||
*
|
||||
* @param code Status code.
|
||||
* @param desc Human-readable status description.
|
||||
*
|
||||
* @see #getCode()
|
||||
*/
|
||||
public SessionStatus(final StatusCode code, final String desc) {
|
||||
this(code, desc, 0, 0);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new status object with the given code.
|
||||
*
|
||||
* @param code Status code.
|
||||
* @param desc Human-readable status description.
|
||||
* @param sessions Number of established SSO sessions in ticket registry.
|
||||
* @param serviceTickets Number of service tickets in ticket registry.
|
||||
*
|
||||
* @see #getCode()
|
||||
*/
|
||||
public SessionStatus(final StatusCode code, final String desc, final int sessions, final int serviceTickets) {
|
||||
super(code, desc);
|
||||
this.sessionCount = sessions;
|
||||
this.serviceTicketCount = serviceTickets;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets total number of SSO sessions maintained by CAS.
|
||||
*
|
||||
* @return Total number of SSO sessions.
|
||||
*/
|
||||
public int getSessionCount() {
|
||||
return this.sessionCount;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets the total number of service tickets in the CAS ticket registry.
|
||||
*
|
||||
* @return Total number of service tickets.
|
||||
*/
|
||||
public int getServiceTicketCount() {
|
||||
return this.serviceTicketCount;
|
||||
}
|
||||
}
|
@ -0,0 +1,117 @@
|
||||
/*
|
||||
* Licensed to Jasig under one or more contributor license
|
||||
* agreements. See the NOTICE file distributed with this work
|
||||
* for additional information regarding copyright ownership.
|
||||
* Jasig licenses this file to you under the Apache License,
|
||||
* Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a
|
||||
* copy of the License at the following location:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
package org.jasig.cas.monitor;
|
||||
|
||||
import java.util.Formatter;
|
||||
|
||||
/**
|
||||
* Simple implementation of cache statistics.
|
||||
*
|
||||
* @author Marvin S. Addison
|
||||
* @since 3.5.1
|
||||
*/
|
||||
public class SimpleCacheStatistics implements CacheStatistics {
|
||||
|
||||
private static final double BYTES_PER_MB = 1048510.0;
|
||||
|
||||
private final long size;
|
||||
|
||||
private final long capacity;
|
||||
|
||||
private final long evictions;
|
||||
|
||||
private String name;
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new instance with given parameters.
|
||||
*
|
||||
* @param size Current cache size (e.g. items, bytes, etc).
|
||||
* @param capacity Current cache capacity (e.g. items, bytes, etc). The units of capacity must be equal to size
|
||||
* in order to produce a meaningful value for {@link #getPercentFree}.
|
||||
* @param evictions Number of evictions reported by cache.
|
||||
*/
|
||||
public SimpleCacheStatistics(final long size, final long capacity, final long evictions) {
|
||||
this.size = size;
|
||||
this.capacity = capacity;
|
||||
this.evictions = evictions;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new named instance with given parameters.
|
||||
*
|
||||
* @param size Current cache size (e.g. items, bytes, etc).
|
||||
* @param capacity Current cache capacity (e.g. items, bytes, etc). The units of capacity must be equal to size
|
||||
* in order to produce a meaningful value for {@link #getPercentFree}.
|
||||
* @param evictions Number of evictions reported by cache.
|
||||
* @param name Name of cache instance to which statistics apply.
|
||||
*/
|
||||
public SimpleCacheStatistics(final long size, final long capacity, final long evictions, final String name) {
|
||||
this.size = size;
|
||||
this.capacity = capacity;
|
||||
this.evictions = evictions;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public long getSize() {
|
||||
return this.size;
|
||||
}
|
||||
|
||||
|
||||
public long getCapacity() {
|
||||
return this.capacity;
|
||||
}
|
||||
|
||||
|
||||
public long getEvictions() {
|
||||
return this.evictions;
|
||||
}
|
||||
|
||||
|
||||
public int getPercentFree() {
|
||||
if (this.capacity == 0) {
|
||||
return 0;
|
||||
}
|
||||
return (int) ((this.capacity - this.size) * 100 / this.capacity);
|
||||
}
|
||||
|
||||
|
||||
public void toString(final StringBuilder builder) {
|
||||
if (this.name != null) {
|
||||
builder.append(this.name).append(':');
|
||||
}
|
||||
final Formatter formatter = new Formatter(builder);
|
||||
formatter.format("%.2f", this.size / BYTES_PER_MB);
|
||||
builder.append("MB used, ");
|
||||
builder.append(getPercentFree()).append("% free, ");
|
||||
builder.append(this.evictions).append(" evictions");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets a descriptive name of the cache instance for which statistics apply.
|
||||
*
|
||||
* @return Name of cache instance/host to which statistics apply.
|
||||
*/
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
}
|
@ -0,0 +1,92 @@
|
||||
/*
|
||||
* Licensed to Jasig under one or more contributor license
|
||||
* agreements. See the NOTICE file distributed with this work
|
||||
* for additional information regarding copyright ownership.
|
||||
* Jasig licenses this file to you under the Apache License,
|
||||
* Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a
|
||||
* copy of the License at the following location:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.jasig.cas.monitor;
|
||||
|
||||
/**
|
||||
* Describes a generic status condition.
|
||||
*
|
||||
* @author Marvin S. Addison
|
||||
* @since 3.5.0
|
||||
*/
|
||||
public class Status {
|
||||
|
||||
/** Generic UNKNOWN status. */
|
||||
public static final Status UNKNOWN = new Status(StatusCode.UNKNOWN);
|
||||
|
||||
/** Generic OK status. */
|
||||
public static final Status OK = new Status(StatusCode.OK);
|
||||
|
||||
/** Generic INFO status. */
|
||||
public static final Status INFO = new Status(StatusCode.INFO);
|
||||
|
||||
/** Generic WARN status. */
|
||||
public static final Status WARN = new Status(StatusCode.WARN);
|
||||
|
||||
/** Generic ERROR status. */
|
||||
public static final Status ERROR = new Status(StatusCode.ERROR);
|
||||
|
||||
/** Status code. */
|
||||
private final StatusCode code;
|
||||
|
||||
/** Human-readable status description. */
|
||||
private final String description;
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new status object with the given code.
|
||||
*
|
||||
* @param code Status code.
|
||||
*
|
||||
* @see #getCode()
|
||||
*/
|
||||
public Status(final StatusCode code) {
|
||||
this(code, null);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new status object with the given code.
|
||||
*
|
||||
* @param code Status code.
|
||||
* @param desc Human-readable status description.
|
||||
*
|
||||
* @see #getCode()
|
||||
*/
|
||||
public Status(final StatusCode code, final String desc) {
|
||||
this.code = code;
|
||||
this.description = desc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the status code.
|
||||
*
|
||||
* @return Status code.
|
||||
*/
|
||||
public StatusCode getCode() {
|
||||
return this.code;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return Human-readable description of status.
|
||||
*/
|
||||
public String getDescription() {
|
||||
return this.description;
|
||||
}
|
||||
}
|
@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Licensed to Jasig under one or more contributor license
|
||||
* agreements. See the NOTICE file distributed with this work
|
||||
* for additional information regarding copyright ownership.
|
||||
* Jasig licenses this file to you under the Apache License,
|
||||
* Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a
|
||||
* copy of the License at the following location:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.jasig.cas.monitor;
|
||||
|
||||
/**
|
||||
* Monitor status code inspired by HTTP status codes.
|
||||
*
|
||||
* @author Marvin S. Addison
|
||||
* @since 3.5.0
|
||||
*/
|
||||
public enum StatusCode {
|
||||
ERROR(500),
|
||||
WARN(400),
|
||||
INFO(300),
|
||||
OK(200),
|
||||
UNKNOWN(100);
|
||||
|
||||
/** Status code numerical value */
|
||||
private final int value;
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new instance with the given numeric value.
|
||||
*
|
||||
* @param numericValue Numeric status code value.
|
||||
*/
|
||||
StatusCode(final int numericValue) {
|
||||
this.value = numericValue;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets the numeric value of the status code. Higher values describe more severe conditions.
|
||||
*
|
||||
* @return Numeric status code value.
|
||||
*/
|
||||
public int value() {
|
||||
return this.value;
|
||||
}
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Licensed to Jasig under one or more contributor license
|
||||
* agreements. See the NOTICE file distributed with this work
|
||||
* for additional information regarding copyright ownership.
|
||||
* Jasig licenses this file to you under the Apache License,
|
||||
* Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a
|
||||
* copy of the License at the following location:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.jasig.cas.monitor;
|
||||
|
||||
/**
|
||||
* Describes important state information that may be optionally exposed by
|
||||
* {@link org.jasig.cas.ticket.registry.TicketRegistry} components that might
|
||||
* be of interest to monitors.
|
||||
*
|
||||
* @author Marvin S. Addison
|
||||
* @since 3.5.0
|
||||
*/
|
||||
public interface TicketRegistryState {
|
||||
/**
|
||||
* Computes the number of SSO sessions stored in the ticket registry.
|
||||
*
|
||||
* @return Number of ticket-granting tickets in the registry at time of invocation
|
||||
* or {@link Integer#MIN_VALUE} if unknown.
|
||||
*/
|
||||
int sessionCount();
|
||||
|
||||
|
||||
/**
|
||||
* Computes the number of service tickets stored in the ticket registry.
|
||||
*
|
||||
* @return Number of service tickets in the registry at time of invocation
|
||||
* or {@link Integer#MIN_VALUE} if unknown.
|
||||
*/
|
||||
int serviceTicketCount();
|
||||
}
|
60
cas-server-core/src/main/java/org/jasig/cas/package.html
Normal file
60
cas-server-core/src/main/java/org/jasig/cas/package.html
Normal file
@ -0,0 +1,60 @@
|
||||
<!--
|
||||
|
||||
Licensed to Jasig under one or more contributor license
|
||||
agreements. See the NOTICE file distributed with this work
|
||||
for additional information regarding copyright ownership.
|
||||
Jasig licenses this file to you under the Apache License,
|
||||
Version 2.0 (the "License"); you may not use this file
|
||||
except in compliance with the License. You may obtain a
|
||||
copy of the License at the following location:
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
|
||||
-->
|
||||
<html>
|
||||
<body>
|
||||
|
||||
<p>This is the entry point to the part of the CAS processing that is independent
|
||||
of the user/program interface. This layer is mostly a service to create, manage,
|
||||
validate, query, and destroy tickets. The caller of this layer may be a Web
|
||||
application running in a Servlet container, but it may also be a Web Service
|
||||
client, RMI client, or even a program that finds these services compelling.</p>
|
||||
<p>One first enters this layer with opaque Credentials requesting creation of a
|
||||
TGT. The Credentials are "opaque" because they are an object whose nature is
|
||||
irrelevant to CAS. The Credentials are carried through the layers until they can
|
||||
be presented to plugin configuration beans that may recognize the underlying
|
||||
type and process it. Simple Credentials might be an object with a userid and
|
||||
password, but they may also be an X.509 Certificate, Kerberos Ticket, Shibboleth
|
||||
artifact, XML SOAP header, or any other object.</p>
|
||||
<p>The Credentials are presented to a set of objects plugged into the
|
||||
Authentication process by the system administrators. If one of these plugin
|
||||
elements recognizes the Credentials, validates their integrity, and maps them to
|
||||
the identity of a user in the local system, then CAS has logged someone on and
|
||||
creates a TGT.</p>
|
||||
<p>The results of the login are somewhat opaque. The TGT references an
|
||||
Authentication object that references a Principal. Minimally the Principal
|
||||
contains a simple ID string. What else the Principal or Authentication object
|
||||
contain are transparent to CAS. These objects must be Serializable, because the
|
||||
Tickets and everything they reference may need to be checkpointed to disk or
|
||||
shared with multiple machines in a clustering configuration. CAS is managing the
|
||||
TGT and, as a result, it also saves everything in the concrete classes
|
||||
referenced by it.</p>
|
||||
<p>Any additional information about the User fetched at login is of no direct
|
||||
interest to CAS. It may, however, be meaningful to the caller of this layer. In
|
||||
the case of an HTTP Servlet interface, this would be the View layer that
|
||||
generates, among other things, the response to the Ticket Validation query.</p>
|
||||
<p>Having created a TGT, CAS then proceeds to create Service Tickets which are
|
||||
chained off the TGT, and in the case of Proxy authentication creates chains of
|
||||
TGTs for the Service Ticket. TGTs and STs are stored in a cache until they
|
||||
expire or are deleted. Various technologies can be plugged into the back end so
|
||||
that the Ticket cache is shared among machines or persisted across a reboot.</p>
|
||||
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,130 @@
|
||||
/*
|
||||
* Licensed to Jasig under one or more contributor license
|
||||
* agreements. See the NOTICE file distributed with this work
|
||||
* for additional information regarding copyright ownership.
|
||||
* Jasig licenses this file to you under the Apache License,
|
||||
* Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a
|
||||
* copy of the License at the following location:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.jasig.cas.remoting.server;
|
||||
|
||||
import org.jasig.cas.CentralAuthenticationService;
|
||||
import org.jasig.cas.authentication.principal.Credentials;
|
||||
import org.jasig.cas.authentication.principal.Service;
|
||||
import org.jasig.cas.ticket.TicketException;
|
||||
import org.jasig.cas.validation.Assertion;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import javax.validation.*;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Wrapper implementation around a CentralAuthenticationService that does
|
||||
* completes the marshalling of parameters from the web-service layer to the
|
||||
* service layer. Typically the only thing that is done is to validate the
|
||||
* parameters (as you would in the web tier) and then delegate to the service
|
||||
* layer.
|
||||
* <p>
|
||||
* The following properties are required:
|
||||
* </p>
|
||||
* <ul>
|
||||
* <li>centralAuthenticationService - the service layer we are delegating to.</li>
|
||||
* </ul>
|
||||
*
|
||||
* @author Scott Battaglia
|
||||
* @version $Revision$ $Date$
|
||||
* @since 3.0
|
||||
*/
|
||||
public final class RemoteCentralAuthenticationService implements CentralAuthenticationService {
|
||||
|
||||
/** The CORE to delegate to. */
|
||||
@NotNull
|
||||
private CentralAuthenticationService centralAuthenticationService;
|
||||
|
||||
/** The validators to check the Credentials. */
|
||||
@NotNull
|
||||
private Validator validator = Validation.buildDefaultValidatorFactory().getValidator();
|
||||
|
||||
/**
|
||||
* @throws IllegalArgumentException if the Credentials are null or if given
|
||||
* invalid credentials.
|
||||
*/
|
||||
public String createTicketGrantingTicket(final Credentials credentials) throws TicketException {
|
||||
Assert.notNull(credentials, "credentials cannot be null");
|
||||
checkForErrors(credentials);
|
||||
|
||||
return this.centralAuthenticationService.createTicketGrantingTicket(credentials);
|
||||
}
|
||||
|
||||
public String grantServiceTicket(final String ticketGrantingTicketId, final Service service) throws TicketException {
|
||||
return this.centralAuthenticationService.grantServiceTicket(ticketGrantingTicketId, service);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws IllegalArgumentException if given invalid credentials
|
||||
*/
|
||||
public String grantServiceTicket(final String ticketGrantingTicketId, final Service service, final Credentials credentials) throws TicketException {
|
||||
checkForErrors(credentials);
|
||||
|
||||
return this.centralAuthenticationService.grantServiceTicket(ticketGrantingTicketId, service, credentials);
|
||||
}
|
||||
|
||||
public Assertion validateServiceTicket(final String serviceTicketId, final Service service) throws TicketException {
|
||||
return this.centralAuthenticationService.validateServiceTicket(serviceTicketId, service);
|
||||
}
|
||||
|
||||
public void destroyTicketGrantingTicket(final String ticketGrantingTicketId) {
|
||||
this.centralAuthenticationService.destroyTicketGrantingTicket(ticketGrantingTicketId);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws IllegalArgumentException if the credentials are invalid.
|
||||
*/
|
||||
public String delegateTicketGrantingTicket(final String serviceTicketId, final Credentials credentials) throws TicketException {
|
||||
checkForErrors(credentials);
|
||||
|
||||
return this.centralAuthenticationService.delegateTicketGrantingTicket(serviceTicketId, credentials);
|
||||
}
|
||||
|
||||
private void checkForErrors(final Credentials credentials) {
|
||||
if (credentials == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final Set<ConstraintViolation<Credentials>> errors = this.validator.validate(credentials);
|
||||
if (!errors.isEmpty()) {
|
||||
throw new IllegalArgumentException("Error validating credentials: " + errors.toString());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the CentralAuthenticationService.
|
||||
*
|
||||
* @param centralAuthenticationService The CentralAuthenticationService to
|
||||
* set.
|
||||
*/
|
||||
public void setCentralAuthenticationService(
|
||||
final CentralAuthenticationService centralAuthenticationService) {
|
||||
this.centralAuthenticationService = centralAuthenticationService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the list of validators.
|
||||
*
|
||||
* @param validator The array of validators to use.
|
||||
*/
|
||||
public void setValidator(final Validator validator) {
|
||||
this.validator = validator;
|
||||
}
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
<!--
|
||||
|
||||
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.
|
||||
|
||||
-->
|
||||
<html>
|
||||
<body>
|
||||
|
||||
Classes to allow CAS to be exposed as a server.
|
||||
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,328 @@
|
||||
/*
|
||||
* Licensed to Jasig under one or more contributor license
|
||||
* agreements. See the NOTICE file distributed with this work
|
||||
* for additional information regarding copyright ownership.
|
||||
* Jasig licenses this file to you under the Apache License,
|
||||
* Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a
|
||||
* copy of the License at the following location:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
package org.jasig.cas.services;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.apache.commons.lang.builder.CompareToBuilder;
|
||||
import org.apache.commons.lang.builder.EqualsBuilder;
|
||||
import org.apache.commons.lang.builder.HashCodeBuilder;
|
||||
import org.apache.commons.lang.builder.ToStringBuilder;
|
||||
import org.apache.commons.lang.builder.ToStringStyle;
|
||||
import org.hibernate.annotations.IndexColumn;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.persistence.DiscriminatorColumn;
|
||||
import javax.persistence.ElementCollection;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.GenerationType;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Inheritance;
|
||||
import javax.persistence.Table;
|
||||
import javax.persistence.DiscriminatorType;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.JoinTable;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.FetchType;
|
||||
|
||||
/**
|
||||
* Base class for mutable, persistable registered services.
|
||||
*
|
||||
* @author Marvin S. Addison
|
||||
* @author Scott Battaglia
|
||||
*/
|
||||
@Entity
|
||||
@Inheritance
|
||||
@DiscriminatorColumn(
|
||||
name = "expression_type",
|
||||
length = 15,
|
||||
discriminatorType = DiscriminatorType.STRING,
|
||||
columnDefinition = "VARCHAR(15) DEFAULT 'ant'")
|
||||
@Table(name = "RegisteredServiceImpl")
|
||||
public abstract class AbstractRegisteredService
|
||||
implements RegisteredService, Comparable<RegisteredService>, Serializable {
|
||||
|
||||
/** Serialization version marker */
|
||||
private static final long serialVersionUID = 7645279151115635245L;
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.AUTO)
|
||||
private long id = -1;
|
||||
|
||||
@ElementCollection(targetClass = String.class, fetch = FetchType.EAGER)
|
||||
@JoinTable(name = "rs_attributes", joinColumns = @JoinColumn(name = "RegisteredServiceImpl_id"))
|
||||
@Column(name = "a_name", nullable = false)
|
||||
@IndexColumn(name = "a_id")
|
||||
private List<String> allowedAttributes = new ArrayList<String>();
|
||||
|
||||
private String description;
|
||||
|
||||
protected String serviceId;
|
||||
|
||||
private String name;
|
||||
|
||||
private String theme;
|
||||
|
||||
private boolean allowedToProxy = true;
|
||||
|
||||
private boolean enabled = true;
|
||||
|
||||
private boolean ssoEnabled = true;
|
||||
|
||||
private boolean anonymousAccess = false;
|
||||
|
||||
private boolean ignoreAttributes = false;
|
||||
|
||||
@Column(name = "evaluation_order", nullable = false)
|
||||
private int evaluationOrder;
|
||||
|
||||
/**
|
||||
* Name of the user attribute that this service expects as the value of the username payload in the
|
||||
* validate responses.
|
||||
*/
|
||||
@Column(name = "username_attr", nullable = true, length = 256)
|
||||
private String usernameAttribute = null;
|
||||
|
||||
public boolean isAnonymousAccess() {
|
||||
return this.anonymousAccess;
|
||||
}
|
||||
|
||||
public void setAnonymousAccess(final boolean anonymousAccess) {
|
||||
this.anonymousAccess = anonymousAccess;
|
||||
}
|
||||
|
||||
public List<String> getAllowedAttributes() {
|
||||
return this.allowedAttributes;
|
||||
}
|
||||
|
||||
public long getId() {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return this.description;
|
||||
}
|
||||
|
||||
public String getServiceId() {
|
||||
return this.serviceId;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
public String getTheme() {
|
||||
return this.theme;
|
||||
}
|
||||
|
||||
public boolean isAllowedToProxy() {
|
||||
return this.allowedToProxy;
|
||||
}
|
||||
|
||||
public boolean isEnabled() {
|
||||
return this.enabled;
|
||||
}
|
||||
|
||||
public boolean isSsoEnabled() {
|
||||
return this.ssoEnabled;
|
||||
}
|
||||
|
||||
public boolean equals(Object o) {
|
||||
if (o == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!(o instanceof AbstractRegisteredService)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final AbstractRegisteredService that = (AbstractRegisteredService) o;
|
||||
|
||||
return new EqualsBuilder()
|
||||
.append(this.allowedToProxy, that.allowedToProxy)
|
||||
.append(this.anonymousAccess, that.anonymousAccess)
|
||||
.append(this.enabled, that.enabled)
|
||||
.append(this.evaluationOrder, that.evaluationOrder)
|
||||
.append(this.ignoreAttributes, that.ignoreAttributes)
|
||||
.append(this.ssoEnabled, that.ssoEnabled)
|
||||
.append(this.allowedAttributes, that.allowedAttributes)
|
||||
.append(this.description, that.description)
|
||||
.append(this.name, that.name)
|
||||
.append(this.serviceId, that.serviceId)
|
||||
.append(this.theme, that.theme)
|
||||
.append(this.usernameAttribute, that.usernameAttribute)
|
||||
.isEquals();
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return new HashCodeBuilder(7, 31)
|
||||
.append(this.allowedAttributes)
|
||||
.append(this.description)
|
||||
.append(this.serviceId)
|
||||
.append(this.name)
|
||||
.append(this.theme)
|
||||
.append(this.enabled)
|
||||
.append(this.ssoEnabled)
|
||||
.append(this.anonymousAccess)
|
||||
.append(this.ignoreAttributes)
|
||||
.append(this.evaluationOrder)
|
||||
.append(this.usernameAttribute)
|
||||
.toHashCode();
|
||||
}
|
||||
|
||||
public void setAllowedAttributes(final List<String> allowedAttributes) {
|
||||
if (allowedAttributes == null) {
|
||||
this.allowedAttributes = new ArrayList<String>();
|
||||
} else {
|
||||
this.allowedAttributes = allowedAttributes;
|
||||
}
|
||||
}
|
||||
|
||||
public void setAllowedToProxy(final boolean allowedToProxy) {
|
||||
this.allowedToProxy = allowedToProxy;
|
||||
}
|
||||
|
||||
public void setDescription(final String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public void setEnabled(final boolean enabled) {
|
||||
this.enabled = enabled;
|
||||
}
|
||||
|
||||
public abstract void setServiceId(final String id);
|
||||
|
||||
public void setId(final long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public void setName(final String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public void setSsoEnabled(final boolean ssoEnabled) {
|
||||
this.ssoEnabled = ssoEnabled;
|
||||
}
|
||||
|
||||
public void setTheme(final String theme) {
|
||||
this.theme = theme;
|
||||
}
|
||||
|
||||
public boolean isIgnoreAttributes() {
|
||||
return this.ignoreAttributes;
|
||||
}
|
||||
|
||||
public void setIgnoreAttributes(final boolean ignoreAttributes) {
|
||||
this.ignoreAttributes = ignoreAttributes;
|
||||
}
|
||||
|
||||
public void setEvaluationOrder(final int evaluationOrder) {
|
||||
this.evaluationOrder = evaluationOrder;
|
||||
}
|
||||
|
||||
public int getEvaluationOrder() {
|
||||
return this.evaluationOrder;
|
||||
}
|
||||
|
||||
public String getUsernameAttribute() {
|
||||
return this.usernameAttribute;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the name of the user attribute to use as the username when providing usernames to this registered service.
|
||||
*
|
||||
* <p>Note: The username attribute will have no affect on services that are marked for anonymous access.
|
||||
*
|
||||
* @param username attribute to release for this service that may be one of the following values:
|
||||
* <ul>
|
||||
* <li>name of the attribute this service prefers to consume as username</li>.
|
||||
* <li><code>null</code> to enforce default CAS behavior</li>
|
||||
* </ul>
|
||||
* @see #isAnonymousAccess()
|
||||
*/
|
||||
public void setUsernameAttribute(final String username) {
|
||||
if (StringUtils.isBlank(username)) {
|
||||
this.usernameAttribute = null;
|
||||
} else {
|
||||
this.usernameAttribute = username;
|
||||
}
|
||||
}
|
||||
|
||||
public Object clone() throws CloneNotSupportedException {
|
||||
final AbstractRegisteredService clone = newInstance();
|
||||
clone.copyFrom(this);
|
||||
return clone;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies the properties of the source service into this instance.
|
||||
*
|
||||
* @param source Source service from which to copy properties.
|
||||
*/
|
||||
public void copyFrom(final RegisteredService source) {
|
||||
this.setId(source.getId());
|
||||
this.setAllowedAttributes(new ArrayList<String>(source.getAllowedAttributes()));
|
||||
this.setAllowedToProxy(source.isAllowedToProxy());
|
||||
this.setDescription(source.getDescription());
|
||||
this.setEnabled(source.isEnabled());
|
||||
this.setName(source.getName());
|
||||
this.setServiceId(source.getServiceId());
|
||||
this.setSsoEnabled(source.isSsoEnabled());
|
||||
this.setTheme(source.getTheme());
|
||||
this.setAnonymousAccess(source.isAnonymousAccess());
|
||||
this.setIgnoreAttributes(source.isIgnoreAttributes());
|
||||
this.setEvaluationOrder(source.getEvaluationOrder());
|
||||
this.setUsernameAttribute(source.getUsernameAttribute());
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares this instance with the <code>other</code> registered service based on
|
||||
* evaluation order, name. The name comparison is case insensitive.
|
||||
*
|
||||
* @see #getEvaluationOrder()
|
||||
*/
|
||||
public int compareTo(final RegisteredService other) {
|
||||
return new CompareToBuilder()
|
||||
.append(this.getEvaluationOrder(), other.getEvaluationOrder())
|
||||
.append(this.getName().toLowerCase(), other.getName().toLowerCase())
|
||||
.toComparison();
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
final ToStringBuilder toStringBuilder = new ToStringBuilder(null, ToStringStyle.SHORT_PREFIX_STYLE);
|
||||
toStringBuilder.append("id", this.id);
|
||||
toStringBuilder.append("name", this.name);
|
||||
toStringBuilder.append("description", this.description);
|
||||
toStringBuilder.append("serviceId", this.serviceId);
|
||||
toStringBuilder.append("usernameAttribute", this.usernameAttribute);
|
||||
toStringBuilder.append("attributes", this.allowedAttributes.toArray());
|
||||
|
||||
return toStringBuilder.toString();
|
||||
}
|
||||
|
||||
protected abstract AbstractRegisteredService newInstance();
|
||||
}
|
@ -0,0 +1,170 @@
|
||||
/*
|
||||
* Licensed to Jasig under one or more contributor license
|
||||
* agreements. See the NOTICE file distributed with this work
|
||||
* for additional information regarding copyright ownership.
|
||||
* Jasig licenses this file to you under the Apache License,
|
||||
* Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a
|
||||
* copy of the License at the following location:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.jasig.cas.services;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import com.github.inspektr.audit.annotation.Audit;
|
||||
import org.jasig.cas.authentication.principal.Service;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
/**
|
||||
* Default implementation of the {@link ServicesManager} interface. If there are
|
||||
* no services registered with the server, it considers the ServicecsManager
|
||||
* disabled and will not prevent any service from using CAS.
|
||||
*
|
||||
* @author Scott Battaglia
|
||||
* @version $Revision$ $Date$
|
||||
* @since 3.1
|
||||
*/
|
||||
public final class DefaultServicesManagerImpl implements ReloadableServicesManager {
|
||||
|
||||
private final Logger log = LoggerFactory.getLogger(getClass());
|
||||
|
||||
/** Instance of ServiceRegistryDao. */
|
||||
@NotNull
|
||||
private ServiceRegistryDao serviceRegistryDao;
|
||||
|
||||
/** Map to store all services. */
|
||||
private ConcurrentHashMap<Long, RegisteredService> services = new ConcurrentHashMap<Long, RegisteredService>();
|
||||
|
||||
/** Default service to return if none have been registered. */
|
||||
private RegisteredService disabledRegisteredService;
|
||||
|
||||
public DefaultServicesManagerImpl(
|
||||
final ServiceRegistryDao serviceRegistryDao) {
|
||||
this(serviceRegistryDao, new ArrayList<String>());
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an instance of the {@link DefaultServicesManagerImpl} where the default RegisteredService
|
||||
* can include a set of default attributes to use if no services are defined in the registry.
|
||||
*
|
||||
* @param serviceRegistryDao the Service Registry Dao.
|
||||
* @param defaultAttributes the list of default attributes to use.
|
||||
*/
|
||||
public DefaultServicesManagerImpl(final ServiceRegistryDao serviceRegistryDao, final List<String> defaultAttributes) {
|
||||
this.serviceRegistryDao = serviceRegistryDao;
|
||||
this.disabledRegisteredService = constructDefaultRegisteredService(defaultAttributes);
|
||||
|
||||
load();
|
||||
}
|
||||
|
||||
@Transactional(readOnly = false)
|
||||
@Audit(action = "DELETE_SERVICE", actionResolverName = "DELETE_SERVICE_ACTION_RESOLVER", resourceResolverName = "DELETE_SERVICE_RESOURCE_RESOLVER")
|
||||
public synchronized RegisteredService delete(final long id) {
|
||||
final RegisteredService r = findServiceBy(id);
|
||||
if (r == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
this.serviceRegistryDao.delete(r);
|
||||
this.services.remove(id);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
* Note, if the repository is empty, this implementation will return a default service to grant all access.
|
||||
* <p>
|
||||
* This preserves default CAS behavior.
|
||||
*/
|
||||
public RegisteredService findServiceBy(final Service service) {
|
||||
final Collection<RegisteredService> c = convertToTreeSet();
|
||||
|
||||
if (c.isEmpty()) {
|
||||
return this.disabledRegisteredService;
|
||||
}
|
||||
|
||||
for (final RegisteredService r : c) {
|
||||
if (r.matches(service)) {
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public RegisteredService findServiceBy(final long id) {
|
||||
final RegisteredService r = this.services.get(id);
|
||||
|
||||
try {
|
||||
return r == null ? null : (RegisteredService) r.clone();
|
||||
} catch (final CloneNotSupportedException e) {
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
protected TreeSet<RegisteredService> convertToTreeSet() {
|
||||
return new TreeSet<RegisteredService>(this.services.values());
|
||||
}
|
||||
|
||||
public Collection<RegisteredService> getAllServices() {
|
||||
return Collections.unmodifiableCollection(convertToTreeSet());
|
||||
}
|
||||
|
||||
public boolean matchesExistingService(final Service service) {
|
||||
return findServiceBy(service) != null;
|
||||
}
|
||||
|
||||
@Transactional(readOnly = false)
|
||||
@Audit(action = "SAVE_SERVICE", actionResolverName = "SAVE_SERVICE_ACTION_RESOLVER", resourceResolverName = "SAVE_SERVICE_RESOURCE_RESOLVER")
|
||||
public synchronized RegisteredService save(final RegisteredService registeredService) {
|
||||
final RegisteredService r = this.serviceRegistryDao.save(registeredService);
|
||||
this.services.put(r.getId(), r);
|
||||
return r;
|
||||
}
|
||||
|
||||
public void reload() {
|
||||
log.info("Reloading registered services.");
|
||||
load();
|
||||
}
|
||||
|
||||
private void load() {
|
||||
final ConcurrentHashMap<Long, RegisteredService> localServices = new ConcurrentHashMap<Long, RegisteredService>();
|
||||
|
||||
for (final RegisteredService r : this.serviceRegistryDao.load()) {
|
||||
log.debug("Adding registered service " + r.getServiceId());
|
||||
localServices.put(r.getId(), r);
|
||||
}
|
||||
|
||||
this.services = localServices;
|
||||
log.info(String.format("Loaded %s services.", this.services.size()));
|
||||
}
|
||||
|
||||
private RegisteredService constructDefaultRegisteredService(final List<String> attributes) {
|
||||
final RegisteredServiceImpl r = new RegisteredServiceImpl();
|
||||
r.setAllowedToProxy(true);
|
||||
r.setAnonymousAccess(false);
|
||||
r.setEnabled(true);
|
||||
r.setSsoEnabled(true);
|
||||
r.setAllowedAttributes(attributes);
|
||||
|
||||
if (attributes == null || attributes.isEmpty()) {
|
||||
r.setIgnoreAttributes(true);
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
}
|
@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Licensed to Jasig under one or more contributor license
|
||||
* agreements. See the NOTICE file distributed with this work
|
||||
* for additional information regarding copyright ownership.
|
||||
* Jasig licenses this file to you under the Apache License,
|
||||
* Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a
|
||||
* copy of the License at the following location:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.jasig.cas.services;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Default In Memory Service Registry Dao for test/demonstration purposes.
|
||||
*
|
||||
* @author Scott Battaglia
|
||||
* @version $Revision: 1.1 $ $Date: 2005/08/19 18:27:17 $
|
||||
* @since 3.1
|
||||
*
|
||||
*/
|
||||
public final class InMemoryServiceRegistryDaoImpl implements ServiceRegistryDao {
|
||||
|
||||
@NotNull
|
||||
private List<RegisteredService> registeredServices = new ArrayList<RegisteredService>();
|
||||
|
||||
public boolean delete(RegisteredService registeredService) {
|
||||
return this.registeredServices.remove(registeredService);
|
||||
}
|
||||
|
||||
public RegisteredService findServiceById(final long id) {
|
||||
for (final RegisteredService r : this.registeredServices) {
|
||||
if (r.getId() == id) {
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public List<RegisteredService> load() {
|
||||
return this.registeredServices;
|
||||
}
|
||||
|
||||
public RegisteredService save(final RegisteredService registeredService) {
|
||||
if (registeredService.getId() == -1) {
|
||||
((AbstractRegisteredService) registeredService).setId(findHighestId()+1);
|
||||
}
|
||||
|
||||
this.registeredServices.remove(registeredService);
|
||||
this.registeredServices.add(registeredService);
|
||||
|
||||
return registeredService;
|
||||
}
|
||||
|
||||
public void setRegisteredServices(final List<RegisteredService> registeredServices) {
|
||||
this.registeredServices = registeredServices;
|
||||
}
|
||||
|
||||
/**
|
||||
* This isn't super-fast but I don't expect thousands of services.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
private long findHighestId() {
|
||||
long id = 0;
|
||||
|
||||
for (final RegisteredService r : this.registeredServices) {
|
||||
if (r.getId() > id) {
|
||||
id = r.getId();
|
||||
}
|
||||
}
|
||||
|
||||
return id;
|
||||
}
|
||||
}
|
@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Licensed to Jasig under one or more contributor license
|
||||
* agreements. See the NOTICE file distributed with this work
|
||||
* for additional information regarding copyright ownership.
|
||||
* Jasig licenses this file to you under the Apache License,
|
||||
* Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a
|
||||
* copy of the License at the following location:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.jasig.cas.services;
|
||||
|
||||
import org.springframework.orm.jpa.support.JpaDaoSupport;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Implementation of the ServiceRegistryDao based on JPA.
|
||||
*
|
||||
* @author Scott Battaglia
|
||||
* @version $Revision$ $Date$
|
||||
* @since 3.1
|
||||
*/
|
||||
public final class JpaServiceRegistryDaoImpl extends JpaDaoSupport implements
|
||||
ServiceRegistryDao {
|
||||
|
||||
public boolean delete(final RegisteredService registeredService) {
|
||||
getJpaTemplate().remove(
|
||||
getJpaTemplate().contains(registeredService) ? registeredService
|
||||
: getJpaTemplate().merge(registeredService));
|
||||
return true;
|
||||
}
|
||||
|
||||
public List<RegisteredService> load() {
|
||||
return getJpaTemplate().find("select r from AbstractRegisteredService r");
|
||||
}
|
||||
|
||||
public RegisteredService save(final RegisteredService registeredService) {
|
||||
final boolean isNew = registeredService.getId() == -1;
|
||||
|
||||
final RegisteredService r = getJpaTemplate().merge(registeredService);
|
||||
|
||||
if (!isNew) {
|
||||
getJpaTemplate().persist(r);
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
public RegisteredService findServiceById(final long id) {
|
||||
return getJpaTemplate().find(AbstractRegisteredService.class, id);
|
||||
}
|
||||
}
|
@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Licensed to Jasig under one or more contributor license
|
||||
* agreements. See the NOTICE file distributed with this work
|
||||
* for additional information regarding copyright ownership.
|
||||
* Jasig licenses this file to you under the Apache License,
|
||||
* Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a
|
||||
* copy of the License at the following location:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.jasig.cas.services;
|
||||
|
||||
import org.jasig.cas.authentication.principal.Service;
|
||||
|
||||
import javax.persistence.DiscriminatorValue;
|
||||
import javax.persistence.Entity;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* Mutable registered service that uses Java regular expressions for service matching.
|
||||
*
|
||||
* @author Marvin S. Addison
|
||||
* @version $Revision: $
|
||||
*/
|
||||
@Entity
|
||||
@DiscriminatorValue("regex")
|
||||
public class RegexRegisteredService extends AbstractRegisteredService {
|
||||
/** Serialization version marker */
|
||||
private static final long serialVersionUID = -8258660210826975771L;
|
||||
|
||||
private transient Pattern servicePattern;
|
||||
|
||||
public void setServiceId(final String id) {
|
||||
servicePattern = createPattern(id);
|
||||
serviceId = id;
|
||||
}
|
||||
|
||||
public boolean matches(final Service service) {
|
||||
if (servicePattern == null) {
|
||||
servicePattern = createPattern(serviceId);
|
||||
}
|
||||
return service != null && servicePattern.matcher(service.getId()).matches();
|
||||
}
|
||||
|
||||
protected AbstractRegisteredService newInstance() {
|
||||
return new RegexRegisteredService();
|
||||
}
|
||||
|
||||
private Pattern createPattern(final String pattern) {
|
||||
if (pattern == null) {
|
||||
throw new IllegalArgumentException("Pattern cannot be null.");
|
||||
}
|
||||
return Pattern.compile(pattern);
|
||||
}
|
||||
}
|
@ -0,0 +1,151 @@
|
||||
/*
|
||||
* Licensed to Jasig under one or more contributor license
|
||||
* agreements. See the NOTICE file distributed with this work
|
||||
* for additional information regarding copyright ownership.
|
||||
* Jasig licenses this file to you under the Apache License,
|
||||
* Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a
|
||||
* copy of the License at the following location:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.jasig.cas.services;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
import org.jasig.cas.authentication.principal.Service;
|
||||
|
||||
/**
|
||||
* Interface for a service that can be registered by the Services Management
|
||||
* interface.
|
||||
*
|
||||
* @author Scott Battaglia
|
||||
* @version $Revision$ $Date$
|
||||
* @since 3.1
|
||||
*/
|
||||
public interface RegisteredService extends Cloneable, Serializable {
|
||||
/**
|
||||
* Is this application currently allowed to use CAS?
|
||||
*
|
||||
* @return true if it can use CAS, false otherwise.
|
||||
*/
|
||||
boolean isEnabled();
|
||||
|
||||
/**
|
||||
* Determines whether the service is allowed anonymous or privileged access
|
||||
* to user information. Anonymous access should not return any identifying
|
||||
* information such as user id.
|
||||
*
|
||||
* @return if we should use a pseudo random identifier instead of their real id
|
||||
*/
|
||||
boolean isAnonymousAccess();
|
||||
|
||||
/**
|
||||
* Sets whether we should bother to read the attribute list or not.
|
||||
*
|
||||
* @return true if we should read it, false otherwise.
|
||||
*/
|
||||
boolean isIgnoreAttributes();
|
||||
|
||||
/**
|
||||
* Returns the list of allowed attributes.
|
||||
*
|
||||
* @return the list of attributes
|
||||
*/
|
||||
List<String> getAllowedAttributes();
|
||||
|
||||
/**
|
||||
* Is this application allowed to take part in the proxying capabilities of
|
||||
* CAS?
|
||||
*
|
||||
* @return true if it can, false otherwise.
|
||||
*/
|
||||
boolean isAllowedToProxy();
|
||||
|
||||
/**
|
||||
* The unique identifier for this service.
|
||||
*
|
||||
* @return the unique identifier for this service.
|
||||
*/
|
||||
String getServiceId();
|
||||
|
||||
/**
|
||||
* The numeric identifier for this service.
|
||||
*
|
||||
* @return the numeric identifier for this service.
|
||||
*/
|
||||
long getId();
|
||||
|
||||
/**
|
||||
* Returns the name of the service.
|
||||
*
|
||||
* @return the name of the service.
|
||||
*/
|
||||
String getName();
|
||||
|
||||
/**
|
||||
* Returns a short theme name. Services do not need to have unique theme
|
||||
* names.
|
||||
*
|
||||
* @return the theme name associated with this service.
|
||||
*/
|
||||
String getTheme();
|
||||
|
||||
/**
|
||||
* Does this application participate in the SSO session?
|
||||
*
|
||||
* @return true if it does, false otherwise.
|
||||
*/
|
||||
boolean isSsoEnabled();
|
||||
|
||||
/**
|
||||
* Returns the description of the service.
|
||||
*
|
||||
* @return the description of the service.
|
||||
*/
|
||||
String getDescription();
|
||||
|
||||
/**
|
||||
* Gets the relative evaluation order of this service when determining
|
||||
* matches.
|
||||
* @return Evaluation order relative to other registered services.
|
||||
* Services with lower values will be evaluated for a match before others.
|
||||
*/
|
||||
int getEvaluationOrder();
|
||||
|
||||
/**
|
||||
* Sets the relative evaluation order of this service when determining
|
||||
* matches.
|
||||
*/
|
||||
void setEvaluationOrder(final int evaluationOrder);
|
||||
|
||||
/**
|
||||
* Get the name of the attribute this service prefers to consume as username.
|
||||
*
|
||||
* @return Either of the following values:
|
||||
* <ul>
|
||||
* <li><code>String</code> representing the name of the attribute to consume as username</li>
|
||||
* <li><code>null</code> indicating the default username</li>
|
||||
* </ul>
|
||||
*/
|
||||
public String getUsernameAttribute();
|
||||
|
||||
/**
|
||||
* Returns whether the service matches the registered service.
|
||||
* <p>Note, as of 3.1.2, matches are case insensitive.
|
||||
*
|
||||
* @param service the service to match.
|
||||
* @return true if they match, false otherwise.
|
||||
*/
|
||||
boolean matches(final Service service);
|
||||
|
||||
Object clone() throws CloneNotSupportedException;
|
||||
}
|
@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Licensed to Jasig under one or more contributor license
|
||||
* agreements. See the NOTICE file distributed with this work
|
||||
* for additional information regarding copyright ownership.
|
||||
* Jasig licenses this file to you under the Apache License,
|
||||
* Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a
|
||||
* copy of the License at the following location:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.jasig.cas.services;
|
||||
|
||||
import org.jasig.cas.authentication.principal.Service;
|
||||
import org.springframework.util.AntPathMatcher;
|
||||
import org.springframework.util.PathMatcher;
|
||||
|
||||
import javax.persistence.DiscriminatorValue;
|
||||
import javax.persistence.Entity;
|
||||
|
||||
/**
|
||||
* Mutable registered service that uses Ant path patterns for service matching.
|
||||
*
|
||||
* @author Scott Battaglia
|
||||
* @author Marvin S. Addison
|
||||
* @version $Revision$ $Date$
|
||||
* @since 3.1
|
||||
*/
|
||||
@Entity
|
||||
@DiscriminatorValue("ant")
|
||||
public class RegisteredServiceImpl extends AbstractRegisteredService {
|
||||
|
||||
/** Unique Id for serialization. */
|
||||
private static final long serialVersionUID = -5906102762271197627L;
|
||||
|
||||
private static final PathMatcher PATH_MATCHER = new AntPathMatcher();
|
||||
|
||||
public void setServiceId(final String id) {
|
||||
this.serviceId = id;
|
||||
}
|
||||
|
||||
public boolean matches(final Service service) {
|
||||
return service != null && PATH_MATCHER.match(serviceId.toLowerCase(), service.getId().toLowerCase());
|
||||
}
|
||||
|
||||
protected AbstractRegisteredService newInstance() {
|
||||
return new RegisteredServiceImpl();
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Licensed to Jasig under one or more contributor license
|
||||
* agreements. See the NOTICE file distributed with this work
|
||||
* for additional information regarding copyright ownership.
|
||||
* Jasig licenses this file to you under the Apache License,
|
||||
* Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a
|
||||
* copy of the License at the following location:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.jasig.cas.services;
|
||||
|
||||
/**
|
||||
* Interface to allow for ServicesManagers to attempt to reload their list of
|
||||
* services.
|
||||
*
|
||||
* @author Scott Battaglia
|
||||
* @version $Revision: 1.1 $ $Date: 2005/08/19 18:27:17 $
|
||||
* @since 3.1
|
||||
*/
|
||||
public interface ReloadableServicesManager extends ServicesManager {
|
||||
|
||||
/**
|
||||
* Inform the ServicesManager to reload its list of services if its cached
|
||||
* them. Note that this is a suggestion and that ServicesManagers are free
|
||||
* to reload whenever they want.
|
||||
*/
|
||||
void reload();
|
||||
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user