Compare commits

...

627 Commits

Author SHA1 Message Date
Alexander Buntakov c516025070
Merge pull request #1 from TouchInstinct/feature/skip-internal-ip
support internal requests skip
2019-12-27 18:49:12 +03:00
Alexander Buntakov 71e71f15ff support internal requests skip 2019-12-27 17:53:03 +03:00
dependabot-preview[bot] 448b08c43c build(deps): bump jetty.version (#409)
Bumps `jetty.version` from 9.4.24.v20191120 to 9.4.25.v20191220.

Updates `jetty-security` from 9.4.24.v20191120 to 9.4.25.v20191220
- [Release notes](https://github.com/eclipse/jetty.project/releases)
- [Commits](https://github.com/eclipse/jetty.project/compare/jetty-9.4.24.v20191120...jetty-9.4.25.v20191220)

Updates `jetty-webapp` from 9.4.24.v20191120 to 9.4.25.v20191220
- [Release notes](https://github.com/eclipse/jetty.project/releases)
- [Commits](https://github.com/eclipse/jetty.project/compare/jetty-9.4.24.v20191120...jetty-9.4.25.v20191220)

Updates `jetty-plus` from 9.4.24.v20191120 to 9.4.25.v20191220
- [Release notes](https://github.com/eclipse/jetty.project/releases)
- [Commits](https://github.com/eclipse/jetty.project/compare/jetty-9.4.24.v20191120...jetty-9.4.25.v20191220)

Updates `jetty-annotations` from 9.4.24.v20191120 to 9.4.25.v20191220
- [Release notes](https://github.com/eclipse/jetty.project/releases)
- [Commits](https://github.com/eclipse/jetty.project/compare/jetty-9.4.24.v20191120...jetty-9.4.25.v20191220)

Updates `apache-jsp` from 9.4.24.v20191120 to 9.4.25.v20191220
- [Release notes](https://github.com/eclipse/jetty.project/releases)
- [Commits](https://github.com/eclipse/jetty.project/compare/jetty-9.4.24.v20191120...jetty-9.4.25.v20191220)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-12-24 05:46:06 +00:00
dependabot-preview[bot] 06f87f85fc build(deps): bump maven-source-plugin from 3.2.0 to 3.2.1 (#408)
Bumps [maven-source-plugin](https://github.com/apache/maven-source-plugin) from 3.2.0 to 3.2.1.
- [Release notes](https://github.com/apache/maven-source-plugin/releases)
- [Commits](https://github.com/apache/maven-source-plugin/compare/maven-source-plugin-3.2.0...maven-source-plugin-3.2.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-12-23 05:41:20 +00:00
renovate[bot] f2c44b7e74 renovatebot(deps): update dependency org.apache.tomcat:tomcat-catalina to v7.0.99 (#406) 2019-12-17 09:33:26 +00:00
renovate[bot] 94d81c32ba renovatebot(deps): update slf4j.version to v1.7.30 (#405) 2019-12-16 21:42:40 +00:00
renovate[bot] a96a13c630 renovatebot(deps): update dependency org.apache.tomcat:tomcat-catalina to v8.5.50 (#403) 2019-12-12 12:46:16 +00:00
renovate[bot] 06f3ebc7c2 renovatebot(deps): update dependency org.apache.tomcat.embed:tomcat-embed-core to v8.5.50 (#402) 2019-12-12 12:46:08 +00:00
renovate[bot] 0dce0aa69e renovatebot(deps): update tomcat.version to v9.0.30 (#401) 2019-12-12 10:02:06 +00:00
renovate[bot] 8a665e1cb1 renovatebot(deps): update spring boot to v2.2.2.release (#400) 2019-12-06 12:42:38 +00:00
renovate[bot] dce1a94d9a renovatebot(deps): update spring core to v5.2.2.release (#399) 2019-12-03 13:17:34 +00:00
Petr Bodnar 76fb6a4f9c README.md - Only list used properties for Single Log Out (#398)
* README.md - Only list used properties for Single Log Out

Properties `casServerUrlPrefix` and `frontLogoutParameterName` are not really read by the SLO filter. Mainly the 1st one has no usage in this filter by design.

* README.md - Only list used properties for Single Log Out

Also removing unused `casServerUrlPrefix` from the code examples.
2019-11-30 12:21:06 +04:00
dependabot-preview[bot] 8d38080354 build(deps): bump jetty.version (#397)
Bumps `jetty.version` from 9.4.22.v20191022 to 9.4.24.v20191120.

Updates `jetty-security` from 9.4.22.v20191022 to 9.4.24.v20191120
- [Release notes](https://github.com/eclipse/jetty.project/releases)
- [Commits](https://github.com/eclipse/jetty.project/compare/jetty-9.4.22.v20191022...jetty-9.4.24.v20191120)

Updates `jetty-webapp` from 9.4.22.v20191022 to 9.4.24.v20191120
- [Release notes](https://github.com/eclipse/jetty.project/releases)
- [Commits](https://github.com/eclipse/jetty.project/compare/jetty-9.4.22.v20191022...jetty-9.4.24.v20191120)

Updates `jetty-plus` from 9.4.22.v20191022 to 9.4.24.v20191120
- [Release notes](https://github.com/eclipse/jetty.project/releases)
- [Commits](https://github.com/eclipse/jetty.project/compare/jetty-9.4.22.v20191022...jetty-9.4.24.v20191120)

Updates `jetty-annotations` from 9.4.22.v20191022 to 9.4.24.v20191120
- [Release notes](https://github.com/eclipse/jetty.project/releases)
- [Commits](https://github.com/eclipse/jetty.project/compare/jetty-9.4.22.v20191022...jetty-9.4.24.v20191120)

Updates `apache-jsp` from 9.4.22.v20191022 to 9.4.24.v20191120
- [Release notes](https://github.com/eclipse/jetty.project/releases)
- [Commits](https://github.com/eclipse/jetty.project/compare/jetty-9.4.22.v20191022...jetty-9.4.24.v20191120)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-11-22 05:38:31 +00:00
renovate[bot] be803939d8 renovatebot(deps): update dependency org.apache.tomcat:tomcat-catalina to v8.5.49 (#393) 2019-11-21 13:42:30 +00:00
renovate[bot] af1bbb2f32 renovatebot(deps): update dependency org.apache.tomcat.embed:tomcat-embed-core to v8.5.49 (#392) 2019-11-21 13:42:21 +00:00
renovate[bot] c5a5a9961b renovatebot(deps): update dependency com.fasterxml.jackson.core:jackson-databind to v2.10.1 (#390) 2019-11-21 13:42:15 +00:00
renovate[bot] 6e2fbec2a4 renovatebot(deps): update tomcat.version to v9.0.29 (#394) 2019-11-21 13:39:17 +00:00
Misagh Moayyed 638c2d6fe4
fix maven jar plugin version 2019-11-21 17:31:58 +04:00
dependabot-preview[bot] efd6dbb491 Bump maven-source-plugin from 3.1.0 to 3.2.0 (#387)
Bumps [maven-source-plugin](https://github.com/apache/maven-source-plugin) from 3.1.0 to 3.2.0.
- [Release notes](https://github.com/apache/maven-source-plugin/releases)
- [Commits](https://github.com/apache/maven-source-plugin/compare/maven-source-plugin-3.1.0...maven-source-plugin-3.2.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-11-07 13:22:49 +04:00
renovate[bot] 905ce61e82 renovatebot(deps): update dependency org.apache.maven.plugins:ma… (#383) 2019-11-07 13:22:32 +04:00
dependabot-preview[bot] 3ba892e482 Bump maven-jar-plugin from 3.1.1 to 3.2.0 (#385)
Bumps [maven-jar-plugin](https://github.com/apache/maven-jar-plugin) from 3.1.1 to 3.2.0.
- [Release notes](https://github.com/apache/maven-jar-plugin/releases)
- [Commits](https://github.com/apache/maven-jar-plugin/compare/maven-jar-plugin-3.1.1...maven-jar-plugin-3.2.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-11-07 13:22:15 +04:00
Gahon 62cc93399f add central logout support for springboot (#388)
* add dependence to generated metadata for springboot

* add central logout support for springboot
2019-11-07 11:56:45 +04:00
renovate[bot] cd67d874a2 renovatebot(deps): update dependency org.springframework.boot:spring-boot-starter to v2.2.1.release (#389) 2019-11-07 00:58:45 +00:00
renovate[bot] 46381476e9 renovatebot(deps): update dependency org.jasig.cas.client:cas-client to v3.6.1 (#369) 2019-11-04 18:25:30 +00:00
renovate[bot] d2538f378d renovatebot(deps): update spring core to v5.2.1.release (#381) 2019-11-04 18:23:06 +00:00
dependabot-preview[bot] f14d836e03 Bump spring.version from 5.2.0.RELEASE to 5.2.1.RELEASE (#384)
Bumps `spring.version` from 5.2.0.RELEASE to 5.2.1.RELEASE.

Updates `spring-core` from 5.2.0.RELEASE to 5.2.1.RELEASE
- [Release notes](https://github.com/spring-projects/spring-framework/releases)
- [Commits](https://github.com/spring-projects/spring-framework/compare/v5.2.0.RELEASE...v5.2.1.RELEASE)

Updates `spring-context` from 5.2.0.RELEASE to 5.2.1.RELEASE
- [Release notes](https://github.com/spring-projects/spring-framework/releases)
- [Commits](https://github.com/spring-projects/spring-framework/compare/v5.2.0.RELEASE...v5.2.1.RELEASE)

Updates `spring-web` from 5.2.0.RELEASE to 5.2.1.RELEASE
- [Release notes](https://github.com/spring-projects/spring-framework/releases)
- [Commits](https://github.com/spring-projects/spring-framework/compare/v5.2.0.RELEASE...v5.2.1.RELEASE)

Updates `spring-test` from 5.2.0.RELEASE to 5.2.1.RELEASE
- [Release notes](https://github.com/spring-projects/spring-framework/releases)
- [Commits](https://github.com/spring-projects/spring-framework/compare/v5.2.0.RELEASE...v5.2.1.RELEASE)

Updates `spring-beans` from 5.2.0.RELEASE to 5.2.1.RELEASE
- [Release notes](https://github.com/spring-projects/spring-framework/releases)
- [Commits](https://github.com/spring-projects/spring-framework/compare/v5.2.0.RELEASE...v5.2.1.RELEASE)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-11-04 18:23:02 +00:00
renovate[bot] e2e4ea9fa1 renovatebot(deps): update dependency org.apache.maven.plugins:ma… (#382) 2019-11-04 22:22:45 +04:00
dependabot-preview[bot] df89820368 Bump maven-assembly-plugin from 3.1.1 to 3.2.0 (#386)
Bumps [maven-assembly-plugin](https://github.com/apache/maven-assembly-plugin) from 3.1.1 to 3.2.0.
- [Release notes](https://github.com/apache/maven-assembly-plugin/releases)
- [Commits](https://github.com/apache/maven-assembly-plugin/compare/maven-assembly-plugin-3.1.1...maven-assembly-plugin-3.2.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-11-04 22:22:26 +04:00
Misagh Moayyed 3005cc8607
Update .mergify.yml 2019-11-04 22:21:59 +04:00
renovate[bot] e0374d61ac renovatebot(deps): update dependency joda-time:joda-time to v2.1… (#378) 2019-10-31 23:37:23 +04:00
renovate[bot] 360ff59ddd renovatebot(deps): update dependency org.apache.tomcat:tomcat-ca… (#372) 2019-10-31 23:37:03 +04:00
renovate[bot] 59f42b7edf renovatebot(deps): update tomcat.version to v9.0.27 (#370) 2019-10-31 23:36:44 +04:00
dependabot-preview[bot] 409bd553ba Bump jetty.version from 9.4.21.v20190926 to 9.4.22.v20191022 (#377)
Bumps `jetty.version` from 9.4.21.v20190926 to 9.4.22.v20191022.

Updates `jetty-security` from 9.4.21.v20190926 to 9.4.22.v20191022
- [Release notes](https://github.com/eclipse/jetty.project/releases)
- [Commits](https://github.com/eclipse/jetty.project/compare/jetty-9.4.21.v20190926...jetty-9.4.22.v20191022)

Updates `jetty-webapp` from 9.4.21.v20190926 to 9.4.22.v20191022
- [Release notes](https://github.com/eclipse/jetty.project/releases)
- [Commits](https://github.com/eclipse/jetty.project/compare/jetty-9.4.21.v20190926...jetty-9.4.22.v20191022)

Updates `jetty-plus` from 9.4.21.v20190926 to 9.4.22.v20191022
- [Release notes](https://github.com/eclipse/jetty.project/releases)
- [Commits](https://github.com/eclipse/jetty.project/compare/jetty-9.4.21.v20190926...jetty-9.4.22.v20191022)

Updates `jetty-annotations` from 9.4.21.v20190926 to 9.4.22.v20191022
- [Release notes](https://github.com/eclipse/jetty.project/releases)
- [Commits](https://github.com/eclipse/jetty.project/compare/jetty-9.4.21.v20190926...jetty-9.4.22.v20191022)

Updates `apache-jsp` from 9.4.21.v20190926 to 9.4.22.v20191022
- [Release notes](https://github.com/eclipse/jetty.project/releases)
- [Commits](https://github.com/eclipse/jetty.project/compare/jetty-9.4.21.v20190926...jetty-9.4.22.v20191022)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-10-31 23:36:23 +04:00
dependabot-preview[bot] 3ec16e8aaf Bump joda-time from 2.10.4 to 2.10.5 (#379)
Bumps [joda-time](https://github.com/JodaOrg/joda-time) from 2.10.4 to 2.10.5.
- [Release notes](https://github.com/JodaOrg/joda-time/releases)
- [Changelog](https://github.com/JodaOrg/joda-time/blob/master/RELEASE-NOTES.txt)
- [Commits](https://github.com/JodaOrg/joda-time/compare/v2.10.4...v2.10.5)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-10-31 23:35:14 +04:00
renovate[bot] 08bedcf889 renovatebot(deps): update slf4j.version to v1.7.29 (#380) 2019-10-31 23:34:59 +04:00
Misagh Moayyed da7ff03cff
Update .mergify.yml 2019-10-24 19:04:44 +04:00
renovate[bot] 5aaf09b3e4 renovatebot(deps): update dependency org.apache.tomcat.embed:tom… (#371) 2019-10-24 19:04:14 +04:00
dependabot-preview[bot] fd176bc1a7 Bump spring-boot-starter from 2.1.9.RELEASE to 2.2.0.RELEASE (#376)
Bumps [spring-boot-starter](https://github.com/spring-projects/spring-boot) from 2.1.9.RELEASE to 2.2.0.RELEASE.
- [Release notes](https://github.com/spring-projects/spring-boot/releases)
- [Commits](https://github.com/spring-projects/spring-boot/compare/v2.1.9.RELEASE...v2.2.0.RELEASE)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-10-17 17:51:43 +04:00
renovate[bot] 9f09c15673 renovatebot(deps): update dependency org.bouncycastle:bcpkix-jdk15on to v1.64 (#373) 2019-10-12 10:20:46 +04:00
Misagh Moayyed e4c1df0280
[maven-release-plugin] prepare for next development iteration 2019-10-08 17:22:31 +04:00
Misagh Moayyed a00064d1d8
[maven-release-plugin] prepare release cas-client-3.6.1 2019-10-08 17:22:16 +04:00
Misagh Moayyed 21d5f37322
Updated: code cleanup and styling; fixes test cases 2019-10-08 17:20:43 +04:00
Misagh Moayyed 872fc49fb7
ensure API compatibility 2019-10-08 17:19:45 +04:00
Jérôme LELEU 18c79fcf00 [maven-release-plugin] prepare for next development iteration 2019-10-07 11:02:29 +02:00
Jérôme LELEU 9394a6e190 [maven-release-plugin] prepare release cas-client-3.6.0 2019-10-07 11:02:21 +02:00
LELEU Jérôme 3e99e678ca
fix notice and license issues (#368) 2019-10-07 10:25:43 +02:00
mergify[bot] 2beda557e1
Merge pull request #367 from apereo/renovate/spring-boot
renovatebot(deps): update dependency org.springframework.boot:spring-boot-starter to v2.1.9.release
2019-10-02 17:42:25 +00:00
Renovate Bot a233009f68
renovatebot(deps): update dependency org.springframework.boot:spring-boot-starter to v2.1.9.release 2019-10-02 17:29:14 +00:00
mergify[bot] e7d2c87668
Merge pull request #366 from apereo/dependabot/maven/jetty.version-9.4.21.v20190926
Bump jetty.version from 9.4.20.v20190813 to 9.4.21.v20190926
2019-10-02 06:54:38 +00:00
dependabot-preview[bot] 8a972d38e1
Bump jetty.version from 9.4.20.v20190813 to 9.4.21.v20190926
Bumps `jetty.version` from 9.4.20.v20190813 to 9.4.21.v20190926.

Updates `jetty-security` from 9.4.20.v20190813 to 9.4.21.v20190926
- [Release notes](https://github.com/eclipse/jetty.project/releases)
- [Commits](https://github.com/eclipse/jetty.project/compare/jetty-9.4.20.v20190813...jetty-9.4.21.v20190926)

Updates `jetty-webapp` from 9.4.20.v20190813 to 9.4.21.v20190926
- [Release notes](https://github.com/eclipse/jetty.project/releases)
- [Commits](https://github.com/eclipse/jetty.project/compare/jetty-9.4.20.v20190813...jetty-9.4.21.v20190926)

Updates `jetty-plus` from 9.4.20.v20190813 to 9.4.21.v20190926
- [Release notes](https://github.com/eclipse/jetty.project/releases)
- [Commits](https://github.com/eclipse/jetty.project/compare/jetty-9.4.20.v20190813...jetty-9.4.21.v20190926)

Updates `jetty-annotations` from 9.4.20.v20190813 to 9.4.21.v20190926
- [Release notes](https://github.com/eclipse/jetty.project/releases)
- [Commits](https://github.com/eclipse/jetty.project/compare/jetty-9.4.20.v20190813...jetty-9.4.21.v20190926)

Updates `apache-jsp` from 9.4.20.v20190813 to 9.4.21.v20190926
- [Release notes](https://github.com/eclipse/jetty.project/releases)
- [Commits](https://github.com/eclipse/jetty.project/compare/jetty-9.4.20.v20190813...jetty-9.4.21.v20190926)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-10-02 06:52:04 +00:00
mergify[bot] 2ac1e1b7a6
Merge pull request #365 from apereo/renovate/spring-core
renovatebot(deps): update spring core to v5.2.0.release
2019-09-30 11:26:29 +00:00
Renovate Bot bca6d9b830
renovatebot(deps): update spring core to v5.2.0.release 2019-09-30 10:39:50 +00:00
mergify[bot] 9e89fe960a
Merge pull request #364 from apereo/renovate/spring-core
renovatebot(deps): update spring core to v5.1.10.release
2019-09-28 14:07:13 +00:00
Renovate Bot 15567ef2a6
renovatebot(deps): update spring core to v5.1.10.release 2019-09-28 12:38:49 +00:00
mergify[bot] 5b47efa407
Merge pull request #363 from apereo/renovate/jackson.version
renovatebot(deps): update dependency com.fasterxml.jackson.core:jackson-databind to v2.10.0
2019-09-26 04:47:17 +00:00
Renovate Bot 3ff317846f
renovatebot(deps): update dependency com.fasterxml.jackson.core:jackson-databind to v2.10.0 2019-09-26 04:44:45 +00:00
mergify[bot] e39d35fbd7
Merge pull request #362 from apereo/renovate/jackson.version
renovatebot(deps): update dependency com.fasterxml.jackson.core:jackson-databind to v2.9.10
2019-09-21 21:25:54 +00:00
Renovate Bot 0fbe33a7e5
renovatebot(deps): update dependency com.fasterxml.jackson.core:jackson-databind to v2.9.10 2019-09-21 18:44:15 +00:00
mergify[bot] b531896715
Merge pull request #361 from apereo/renovate/joda-time-joda-time-2.x
renovatebot(deps): update dependency joda-time:joda-time to v2.10.4
2019-09-20 12:41:57 +00:00
Renovate Bot e3b109264c
renovatebot(deps): update dependency joda-time:joda-time to v2.10.4 2019-09-20 12:39:21 +00:00
mergify[bot] 81cdceca8f
Merge pull request #359 from apereo/renovate/tomcat.version
renovatebot(deps): update tomcat.version to v9.0.26
2019-09-20 01:44:36 +00:00
Renovate Bot 5b5ca68d05
renovatebot(deps): update tomcat.version to v9.0.26 2019-09-20 01:41:57 +00:00
mergify[bot] 2728f0597d
Merge pull request #358 from apereo/renovate/org.apache.tomcat-tomcat-catalina-8.x
renovatebot(deps): update dependency org.apache.tomcat:tomcat-catalina to v8.5.46
2019-09-20 01:41:32 +00:00
Renovate Bot 5bd4465298
renovatebot(deps): update dependency org.apache.tomcat:tomcat-catalina to v8.5.46 2019-09-20 00:15:58 +00:00
mergify[bot] 7d9ee60b73
Merge pull request #357 from apereo/renovate/org.apache.tomcat.embed-tomcat-embed-core-8.x
renovatebot(deps): update dependency org.apache.tomcat.embed:tomcat-embed-core to v8.5.46
2019-09-20 00:15:33 +00:00
Renovate Bot 5f82143b00
renovatebot(deps): update dependency org.apache.tomcat.embed:tomcat-embed-core to v8.5.46 2019-09-19 21:34:10 +00:00
mergify[bot] 1fad31d8b0
Merge pull request #356 from apereo/dependabot/maven/org.bouncycastle-bcpkix-jdk15on-1.63
Bump bcpkix-jdk15on from 1.62 to 1.63
2019-09-11 05:41:38 +00:00
dependabot-preview[bot] 3d391b62b8
Bump bcpkix-jdk15on from 1.62 to 1.63
Bumps [bcpkix-jdk15on](https://github.com/bcgit/bc-java) from 1.62 to 1.63.
- [Release notes](https://github.com/bcgit/bc-java/releases)
- [Changelog](https://github.com/bcgit/bc-java/blob/master/docs/releasenotes.html)
- [Commits](https://github.com/bcgit/bc-java/commits)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-09-11 05:39:18 +00:00
mergify[bot] 913c412fba
Merge pull request #354 from apereo/renovate/spring-boot
renovatebot(deps): update dependency org.springframework.boot:spring-boot-starter to v2.1.8.release
2019-09-05 22:59:47 +00:00
Renovate Bot b355b526d6
renovatebot(deps): update dependency org.springframework.boot:spring-boot-starter to v2.1.8.release 2019-09-05 22:57:35 +00:00
mergify[bot] 858b0ca77d
Merge pull request #351 from apereo/renovate/javax.servlet-javax.servlet-api-4.x
renovatebot(deps): update dependency javax.servlet:javax.servlet-api to v4
2019-08-22 05:54:16 +00:00
Renovate Bot c00ee02f44
renovatebot(deps): update dependency javax.servlet:javax.servlet-api to v4 2019-08-22 05:52:05 +00:00
mergify[bot] 40848d251e
Merge pull request #350 from apereo/renovate/com.atlassian.user-atlassian-user-5.x
renovatebot(deps): update dependency com.atlassian.user:atlassian-user to v5
2019-08-22 05:51:40 +00:00
Renovate Bot a7b7660772
renovatebot(deps): update dependency com.atlassian.user:atlassian-user to v5 2019-08-22 05:49:27 +00:00
mergify[bot] 440f2edaa6
Merge pull request #349 from apereo/renovate/com.atlassian.seraph-atlassian-seraph-4.x
renovatebot(deps): update dependency com.atlassian.seraph:atlassian-seraph to v4
2019-08-22 05:49:00 +00:00
Renovate Bot 8667f0b946
renovatebot(deps): update dependency com.atlassian.seraph:atlassian-seraph to v4 2019-08-22 05:46:54 +00:00
renovate[bot] 60a8cb3825 Update dependency org.apache.tomcat:tomcat-catalina to v8.5.45 (#347) 2019-08-22 10:16:11 +04:30
Misagh Moayyed 11a53a6fc2
Update renovate.json 2019-08-22 10:15:46 +04:30
renovate[bot] 58a54c7372 Update dependency org.apache.tomcat.embed:tomcat-embed-core to v8.5.45 (#346) 2019-08-21 20:31:25 +04:30
renovate[bot] 53f34e175e Update tomcat.version to v9.0.24 (#344) 2019-08-18 08:04:29 +04:30
mergify[bot] 9279ab8d54
Merge pull request #343 from apereo/dependabot/maven/jetty.version-9.4.20.v20190813
Bump jetty.version from 9.4.18.v20190429 to 9.4.20.v20190813
2019-08-15 05:59:08 +00:00
dependabot-preview[bot] 6352b7991a
Bump jetty.version from 9.4.18.v20190429 to 9.4.20.v20190813
Bumps `jetty.version` from 9.4.18.v20190429 to 9.4.20.v20190813.

Updates `jetty-security` from 9.4.18.v20190429 to 9.4.20.v20190813
- [Release notes](https://github.com/eclipse/jetty.project/releases)
- [Commits](https://github.com/eclipse/jetty.project/compare/jetty-9.4.18.v20190429...jetty-9.4.20.v20190813)

Updates `jetty-webapp` from 9.4.18.v20190429 to 9.4.20.v20190813
- [Release notes](https://github.com/eclipse/jetty.project/releases)
- [Commits](https://github.com/eclipse/jetty.project/compare/jetty-9.4.18.v20190429...jetty-9.4.20.v20190813)

Updates `jetty-plus` from 9.4.18.v20190429 to 9.4.20.v20190813
- [Release notes](https://github.com/eclipse/jetty.project/releases)
- [Commits](https://github.com/eclipse/jetty.project/compare/jetty-9.4.18.v20190429...jetty-9.4.20.v20190813)

Updates `jetty-annotations` from 9.4.18.v20190429 to 9.4.20.v20190813
- [Release notes](https://github.com/eclipse/jetty.project/releases)
- [Commits](https://github.com/eclipse/jetty.project/compare/jetty-9.4.18.v20190429...jetty-9.4.20.v20190813)

Updates `apache-jsp` from 9.4.18.v20190429 to 9.4.20.v20190813
- [Release notes](https://github.com/eclipse/jetty.project/releases)
- [Commits](https://github.com/eclipse/jetty.project/compare/jetty-9.4.18.v20190429...jetty-9.4.20.v20190813)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-08-15 05:52:39 +00:00
mergify[bot] db9f0a3301
Merge pull request #342 from apereo/dependabot/maven/slf4j.version-1.7.28
Bump slf4j.version from 1.7.27 to 1.7.28
2019-08-12 07:59:51 +00:00
dependabot-preview[bot] 4c4202de24
Bump slf4j.version from 1.7.27 to 1.7.28
Bumps `slf4j.version` from 1.7.27 to 1.7.28.

Updates `slf4j-api` from 1.7.27 to 1.7.28
- [Release notes](https://github.com/qos-ch/slf4j/releases)
- [Commits](https://github.com/qos-ch/slf4j/compare/v_1.7.27...v_1.7.28)

Updates `jcl-over-slf4j` from 1.7.27 to 1.7.28
- [Release notes](https://github.com/qos-ch/slf4j/releases)
- [Commits](https://github.com/qos-ch/slf4j/compare/v_1.7.27...v_1.7.28)

Updates `slf4j-simple` from 1.7.27 to 1.7.28
- [Release notes](https://github.com/qos-ch/slf4j/releases)
- [Commits](https://github.com/qos-ch/slf4j/compare/v_1.7.27...v_1.7.28)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-08-12 06:52:55 +00:00
Misagh Moayyed 6f7ef142bc
add tomcat 9.0.x 2019-08-09 15:04:33 +04:30
Misagh Moayyed 7e34235578
fix license headers 2019-08-09 14:55:39 +04:30
mergify[bot] 07a700f531
Merge pull request #335 from apereo/dependabot/maven/spring.version-5.1.9.RELEASE
[Security] Bump spring.version from 3.1.3.RELEASE to 5.1.9.RELEASE
2019-08-08 19:57:20 +00:00
Misagh Moayyed 31756bd6fc
Merge branch 'master' into dependabot/maven/spring.version-5.1.9.RELEASE 2019-08-09 00:25:10 +04:30
Misagh Moayyed 95583500c0
Update dependency org.springframework.boot:spring-boot-starter t… (#338)
Update dependency org.springframework.boot:spring-boot-starter to v2.1.7.RELEASE
2019-08-08 22:22:26 +04:30
mergify[bot] c096b4c82b
Merge pull request #339 from apereo/dependabot/maven/org.springframework.boot-spring-boot-starter-2.1.7.RELEASE
Bump spring-boot-starter from 2.1.4.RELEASE to 2.1.7.RELEASE
2019-08-08 17:45:23 +00:00
dependabot-preview[bot] 63d638b452
Bump spring-boot-starter from 2.1.4.RELEASE to 2.1.7.RELEASE
Bumps [spring-boot-starter](https://github.com/spring-projects/spring-boot) from 2.1.4.RELEASE to 2.1.7.RELEASE.
- [Release notes](https://github.com/spring-projects/spring-boot/releases)
- [Commits](https://github.com/spring-projects/spring-boot/compare/v2.1.4.RELEASE...v2.1.7.RELEASE)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-08-08 17:43:17 +00:00
Renovate Bot ee21f2874a
Update dependency org.springframework.boot:spring-boot-starter to v2.1.7.RELEASE 2019-08-08 17:42:26 +00:00
Misagh Moayyed 24c3f92030
updated 2019-08-08 22:11:54 +04:30
Misagh Moayyed 3b312e1cff
Merge pull request #340 from apereo/boot-module-javadoc-polish
Correct `@since`
2019-08-08 20:25:56 +04:30
Dmitriy Kopylenko 7f0b42df31 Correct @since 2019-08-08 08:42:09 -04:00
Misagh Moayyed 4d84e02c5f
updated 2019-08-07 21:41:29 +04:30
Misagh Moayyed ca5e5f1f06
add springboot autocfg support 2019-08-07 21:39:44 +04:30
Misagh Moayyed 387e7249e0 Merge branch 'master' of github.com:Jasig/java-cas-client 2019-08-07 19:10:37 +04:30
Misagh Moayyed 8a7e04d7cf
updated 2019-08-07 19:09:42 +04:30
Misagh Moayyed 11d3c21889
Update slf4j.version to v1.7.27 (#337)
Update slf4j.version to v1.7.27
2019-08-06 17:45:51 +04:30
Renovate Bot a51fd8f8f8
Update slf4j.version to v1.7.27 2019-08-06 09:38:46 +00:00
Misagh Moayyed 1a6da20b3e
Merge pull request #336 from apereo/renovate/jackson.version
Update dependency com.fasterxml.jackson.core:jackson-databind to v2.9.9.3
2019-08-06 06:24:53 +04:30
Renovate Bot 2a3adb4ec4
Update dependency com.fasterxml.jackson.core:jackson-databind to v2.9.9.3 2019-08-06 01:52:43 +00:00
Misagh Moayyed a5a7d30791
Merge branch 'master' into dependabot/maven/spring.version-5.1.9.RELEASE 2019-08-05 14:34:19 +04:30
Misagh Moayyed bab29c84f4
fix compile errors 2019-08-05 14:14:59 +04:30
Misagh Moayyed 8eaec09704
disable attlassian from build - unmaintained 2019-08-05 13:54:06 +04:30
dependabot-preview[bot] da07e4815b
[Security] Bump spring.version from 3.1.3.RELEASE to 5.1.9.RELEASE
Bumps `spring.version` from 3.1.3.RELEASE to 5.1.9.RELEASE.

Updates `spring-core` from 3.1.3.RELEASE to 5.1.9.RELEASE
- [Release notes](https://github.com/spring-projects/spring-framework/releases)
- [Commits](https://github.com/spring-projects/spring-framework/compare/v3.1.3.RELEASE...v5.1.9.RELEASE)

Updates `spring-context` from 3.1.3.RELEASE to 5.1.9.RELEASE
- [Release notes](https://github.com/spring-projects/spring-framework/releases)
- [Commits](https://github.com/spring-projects/spring-framework/compare/v3.1.3.RELEASE...v5.1.9.RELEASE)

Updates `spring-test` from 3.1.3.RELEASE to 5.1.9.RELEASE
- [Release notes](https://github.com/spring-projects/spring-framework/releases)
- [Commits](https://github.com/spring-projects/spring-framework/compare/v3.1.3.RELEASE...v5.1.9.RELEASE)

Updates `spring-beans` from 3.1.3.RELEASE to 5.1.9.RELEASE
- [Release notes](https://github.com/spring-projects/spring-framework/releases)
- [Commits](https://github.com/spring-projects/spring-framework/compare/v3.1.3.RELEASE...v5.1.9.RELEASE)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-08-05 06:38:36 +00:00
Misagh Moayyed de1f05dc8b
Merge pull request #334 from apereo/renovate/maven-com.fasterxml.jackson.core-jackson-databind-vulnerability
Update dependency com.fasterxml.jackson.core:jackson-databind to v2.9.9.2 [SECURITY]
2019-08-02 05:26:25 +04:30
Renovate Bot 1300774928
Update dependency com.fasterxml.jackson.core:jackson-databind to v2.9.9.2 [SECURITY] 2019-08-01 20:56:04 +00:00
Misagh Moayyed f946c2845b
Update dependency org.apache.tomcat:tomcat-catalina to v7.0.96 (#333)
Update dependency org.apache.tomcat:tomcat-catalina to v7.0.96
2019-07-29 22:37:59 +04:30
Renovate Bot 3cd4e12fa9
Update dependency org.apache.tomcat:tomcat-catalina to v7.0.96 2019-07-29 18:00:07 +00:00
Misagh Moayyed 3e5eeaabe1
Merge pull request #331 from larsgrefer/gh-329
Remove the unused 'casServerUrlPrefix' parameter
2019-07-26 08:54:28 +04:30
Lars Grefer fdc948b8ec Remove the unused 'casServerUrlPrefix' parameter
fixes #329
2019-07-25 22:54:58 +02:00
Misagh Moayyed 1966a26d6f
Update dependency commons-codec:commons-codec to v1.13 (#330)
Update dependency commons-codec:commons-codec to v1.13
2019-07-23 17:46:00 +04:30
Misagh Moayyed c2886ea70c
Update dependency org.apache.tomcat.embed:tomcat-embed-core to v… (#326)
Update dependency org.apache.tomcat.embed:tomcat-embed-core to v8.5.43
2019-07-23 17:44:45 +04:30
Renovate Bot 850a6c0373
Update dependency commons-codec:commons-codec to v1.13 2019-07-23 12:42:59 +00:00
Misagh Moayyed 764d2220d6
Merge pull request #327 from apereo/renovate/org.apache.tomcat-tomcat-catalina-8.x
Update dependency org.apache.tomcat:tomcat-catalina to v8.5.43
2019-07-18 09:42:37 +04:30
Misagh Moayyed 77abda055b
Create FUNDING.yml 2019-07-13 23:10:19 +04:30
Renovate Bot 505160b15e
Update dependency org.apache.tomcat:tomcat-catalina to v8.5.43 2019-07-09 15:53:24 +00:00
Renovate Bot fdab7aea5b
Update dependency org.apache.tomcat.embed:tomcat-embed-core to v8.5.43 2019-07-09 15:53:17 +00:00
Misagh Moayyed 9e95c8a10c
Bump maven-javadoc-plugin from 3.1.0 to 3.1.1 (#325)
Bump maven-javadoc-plugin from 3.1.0 to 3.1.1
2019-07-08 11:56:02 +04:30
Misagh Moayyed f7234f9aea
Update dependency org.apache.maven.plugins:maven-javadoc-plugin… (#324)
Update dependency org.apache.maven.plugins:maven-javadoc-plugin to v3.1.1
2019-07-08 11:55:56 +04:30
Misagh Moayyed 0e4c82cc94
Merge pull request #323 from apereo/dependabot/maven/joda-time-joda-time-2.10.3
Bump joda-time from 2.10.2 to 2.10.3
2019-07-08 11:55:48 +04:30
dependabot-preview[bot] 8596db4de3
Bump maven-javadoc-plugin from 3.1.0 to 3.1.1
Bumps [maven-javadoc-plugin](https://github.com/apache/maven-javadoc-plugin) from 3.1.0 to 3.1.1.
- [Release notes](https://github.com/apache/maven-javadoc-plugin/releases)
- [Commits](https://github.com/apache/maven-javadoc-plugin/compare/maven-javadoc-plugin-3.1.0...maven-javadoc-plugin-3.1.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-07-08 05:57:27 +00:00
Renovate Bot ccf8b89dee
Update dependency org.apache.maven.plugins:maven-javadoc-plugin to v3.1.1 2019-07-07 09:49:25 +00:00
Misagh Moayyed 3f45530e0e
Merge pull request #322 from apereo/renovate/joda-time-joda-time-2.x
Update dependency joda-time:joda-time to v2.10.3
2019-07-05 10:21:42 +04:30
Misagh Moayyed 46341d3e42
Merge pull request #321 from apereo/renovate/com.fasterxml.jackson.core-jackson-databind-2.x
Update dependency com.fasterxml.jackson.core:jackson-databind to v2.9.9.1
2019-07-05 10:21:14 +04:30
dependabot-preview[bot] 9fabd9fbf1
Bump joda-time from 2.10.2 to 2.10.3
Bumps [joda-time](https://github.com/JodaOrg/joda-time) from 2.10.2 to 2.10.3.
- [Release notes](https://github.com/JodaOrg/joda-time/releases)
- [Changelog](https://github.com/JodaOrg/joda-time/blob/master/RELEASE-NOTES.txt)
- [Commits](https://github.com/JodaOrg/joda-time/compare/v2.10.2...v2.10.3)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-07-05 05:49:20 +00:00
Renovate Bot be29e420c0
Update dependency joda-time:joda-time to v2.10.3 2019-07-04 15:44:58 +00:00
Renovate Bot 2734d45f3e
Update dependency com.fasterxml.jackson.core:jackson-databind to v2.9.9.1 2019-07-03 01:36:11 +00:00
Misagh Moayyed 601959f85c
Update .travis.yml 2019-06-26 01:54:56 -07:00
Misagh Moayyed bf4e1e60b6 Update .travis.yml 2019-06-26 01:42:56 -07:00
Misagh Moayyed 0c041d5376 Update .travis.yml 2019-06-26 01:40:02 -07:00
Misagh Moayyed a7101b6cc8 Provide for secure XML processing. (#318)
Provide for secure XML processing.
2019-06-26 13:09:36 +04:30
Marvin S. Addison 7ce4cb8aa5 Provide for secure XML processing.
Follow recommendations at https://wiki.shibboleth.net/confluence/x/XoEYAw
which are consistent with recommendations on #191 to prevent XXE vectors.

Resolves #191
See https://github.com/apereo/java-cas-client/issues/191
2019-06-25 08:01:46 -04:00
Misagh Moayyed a95a98dd9b Merge pull request #313 from apereo/renovate/org.apache.tomcat.embed-tomcat-embed-core-8.x
Update dependency org.apache.tomcat.embed:tomcat-embed-core to v8.5.42
2019-06-14 08:32:07 +04:30
Renovate Bot a3dbe594c3 Update dependency org.apache.tomcat.embed:tomcat-embed-core to v8.5.42 2019-06-07 21:33:49 +00:00
Misagh Moayyed 49f9a4e309 Merge pull request #311 from apereo/renovate/org.bouncycastle-bcpkix-jdk15on-1.x
Update dependency org.bouncycastle:bcpkix-jdk15on to v1.62
2019-06-07 07:41:38 -07:00
Misagh Moayyed fd72cb6bfc Bump bcpkix-jdk15on from 1.61 to 1.62 (#312)
Bump bcpkix-jdk15on from 1.61 to 1.62
2019-06-07 07:41:23 -07:00
dependabot-preview[bot] 78b2997c5d Bump bcpkix-jdk15on from 1.61 to 1.62
Bumps [bcpkix-jdk15on](https://github.com/bcgit/bc-java) from 1.61 to 1.62.
- [Release notes](https://github.com/bcgit/bc-java/releases)
- [Changelog](https://github.com/bcgit/bc-java/blob/master/docs/releasenotes.html)
- [Commits](https://github.com/bcgit/bc-java/commits)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-06-07 10:33:56 +00:00
Renovate Bot cfebf0acc7 Update dependency org.bouncycastle:bcpkix-jdk15on to v1.62 2019-06-07 04:36:32 +00:00
Misagh Moayyed 874958641a Merge pull request #307 from apereo/dependabot/maven/jetty.version-9.4.18.v20190429
Bump jetty.version from 9.2.14.v20151106 to 9.4.18.v20190429
2019-06-04 06:06:54 -07:00
Misagh Moayyed 691bf12697 Merge pull request #310 from apereo/dependabot/maven/net.sf.ehcache-ehcache-core-2.6.11
Bump ehcache-core from 2.2.0 to 2.6.11
2019-06-04 06:06:17 -07:00
Misagh Moayyed 4332186ea7 Merge pull request #308 from apereo/dependabot/maven/org.apache.maven.plugins-maven-source-plugin-3.1.0
Bump maven-source-plugin from 2.2.1 to 3.1.0
2019-06-04 06:04:38 -07:00
Hal Deadman 52274f828f Merge pull request #251 from inghamn/patch-1
Prioritize X-Forwarded-Host when choosing the service parameter
2019-05-29 19:15:12 -04:00
dependabot-preview[bot] 5c3d185e8d Bump ehcache-core from 2.2.0 to 2.6.11
Bumps ehcache-core from 2.2.0 to 2.6.11.
2019-05-28 10:50:55 +00:00
dependabot-preview[bot] 35d611b8e8 Bump maven-source-plugin from 2.2.1 to 3.1.0
Bumps [maven-source-plugin](https://github.com/apache/maven-source-plugin) from 2.2.1 to 3.1.0.
- [Release notes](https://github.com/apache/maven-source-plugin/releases)
- [Commits](https://github.com/apache/maven-source-plugin/compare/maven-source-plugin-2.2.1...maven-source-plugin-3.1.0)
2019-05-28 10:50:13 +00:00
dependabot-preview[bot] d940cfd417 Bump jetty.version from 9.2.14.v20151106 to 9.4.18.v20190429
Bumps `jetty.version` from 9.2.14.v20151106 to 9.4.18.v20190429.

Updates `jetty-security` from 9.2.14.v20151106 to 9.4.18.v20190429
- [Release notes](https://github.com/eclipse/jetty.project/releases)
- [Commits](https://github.com/eclipse/jetty.project/compare/jetty-9.2.14.v20151106...jetty-9.4.18.v20190429)

Updates `jetty-webapp` from 9.2.14.v20151106 to 9.4.18.v20190429
- [Release notes](https://github.com/eclipse/jetty.project/releases)
- [Commits](https://github.com/eclipse/jetty.project/compare/jetty-9.2.14.v20151106...jetty-9.4.18.v20190429)

Updates `jetty-plus` from 9.2.14.v20151106 to 9.4.18.v20190429
- [Release notes](https://github.com/eclipse/jetty.project/releases)
- [Commits](https://github.com/eclipse/jetty.project/compare/jetty-9.2.14.v20151106...jetty-9.4.18.v20190429)

Updates `jetty-annotations` from 9.2.14.v20151106 to 9.4.18.v20190429
- [Release notes](https://github.com/eclipse/jetty.project/releases)
- [Commits](https://github.com/eclipse/jetty.project/compare/jetty-9.2.14.v20151106...jetty-9.4.18.v20190429)

Updates `apache-jsp` from 9.2.14.v20151106 to 9.4.18.v20190429
- [Release notes](https://github.com/eclipse/jetty.project/releases)
- [Commits](https://github.com/eclipse/jetty.project/compare/jetty-9.2.14.v20151106...jetty-9.4.18.v20190429)
2019-05-27 13:32:43 +00:00
Misagh Moayyed 1d78f74b2a Update dependency org.apache.tomcat.embed:tomcat-embed-core to v8.5.41 (#299)
Update dependency org.apache.tomcat.embed:tomcat-embed-core to v8.5.41
2019-05-23 04:39:18 -07:00
Misagh Moayyed 12da0340a1 Update dependency com.fasterxml.jackson.core:jackson-databind to v2.9.9 [SECURITY] (#302)
Update dependency com.fasterxml.jackson.core:jackson-databind to v2.9.9 [SECURITY]
2019-05-23 04:38:44 -07:00
Renovate Bot e283a9a7a5 Update dependency com.fasterxml.jackson.core:jackson-databind to v2.9.9 [SECURITY] 2019-05-23 10:35:34 +00:00
Renovate Bot 1c29fa7ebd Update dependency org.apache.tomcat.embed:tomcat-embed-core to v8.5.41 2019-05-14 20:54:21 +00:00
Misagh Moayyed 7bea9bb258 Update dependency joda-time:joda-time to v2.10.2 (#297)
Update dependency joda-time:joda-time to v2.10.2
2019-05-09 09:03:56 -07:00
Renovate Bot 4ada1b1327 Update dependency joda-time:joda-time to v2.10.2 2019-05-09 14:39:32 +00:00
Misagh Moayyed 32d14893ae Merge pull request #292 from apereo/renovate/org.jasig.parent-jasig-parent-41.x
Update dependency org.jasig.parent:jasig-parent to v41
2019-05-02 20:00:06 -07:00
Misagh Moayyed 0f395b3a2c Merge pull request #294 from apereo/renovate/org.apache.maven.plugins-maven-compiler-plugin-3.x
Update dependency org.apache.maven.plugins:maven-compiler-plugin to v3.8.1
2019-05-02 19:59:45 -07:00
Misagh Moayyed 0e750de5f5 Merge pull request #295 from apereo/renovate/org.apache.maven.plugins-maven-surefire-plugin-2.x
Update dependency org.apache.maven.plugins:maven-surefire-plugin to v2.22.2
2019-05-02 19:59:13 -07:00
Renovate Bot 26479f3d99 Update dependency org.apache.maven.plugins:maven-surefire-plugin to v2.22.2 2019-05-02 20:54:26 +00:00
Renovate Bot 11e9b543e5 Update dependency org.apache.maven.plugins:maven-compiler-plugin to v3.8.1 2019-05-02 18:54:12 +00:00
Misagh Moayyed 5c2c6b00aa Update dependency org.apache.maven.plugins:maven-assembly-plugin to v3 (#288)
Update dependency org.apache.maven.plugins:maven-assembly-plugin to v3
2019-05-02 06:44:53 -07:00
Misagh Moayyed f0bd481a13 Update dependency org.apache.maven.plugins:maven-jar-plugin to v3 (#289)
Update dependency org.apache.maven.plugins:maven-jar-plugin to v3
2019-05-02 06:44:42 -07:00
Misagh Moayyed 8fb8e9d0e4 Merge pull request #277 from apereo/renovate/org.apache.tomcat.embed-tomcat-embed-core-8.x
Update dependency org.apache.tomcat.embed:tomcat-embed-core to v8.5.40
2019-05-02 06:44:30 -07:00
Misagh Moayyed 3213920bff Merge pull request #278 from apereo/renovate/org.apache.tomcat-catalina-6.x
Update dependency org.apache.tomcat:catalina to v6.0.53
2019-05-02 06:44:06 -07:00
Misagh Moayyed 01812e755d Update dependency org.slf4j:slf4j-simple to v1.7.26 (#283)
Update dependency org.slf4j:slf4j-simple to v1.7.26
2019-04-30 14:27:25 -07:00
Misagh Moayyed d35172dff9 Update dependency org.slf4j:jcl-over-slf4j to v1.7.26 (#281)
Update dependency org.slf4j:jcl-over-slf4j to v1.7.26
2019-04-30 14:27:11 -07:00
Misagh Moayyed 1999bd4670 Update dependency org.slf4j:slf4j-api to v1.7.26 (#282)
Update dependency org.slf4j:slf4j-api to v1.7.26
2019-04-30 14:26:58 -07:00
Renovate Bot 4f411c4342 Update dependency org.jasig.parent:jasig-parent to v41 2019-04-30 20:56:06 +00:00
Renovate Bot c6a46da7fa Update dependency org.apache.maven.plugins:maven-jar-plugin to v3 2019-04-30 19:40:11 +00:00
Renovate Bot c8c0d844b4 Update dependency org.apache.maven.plugins:maven-assembly-plugin to v3 2019-04-30 18:34:17 +00:00
Renovate Bot cf7e09b1c4 Update dependency org.slf4j:slf4j-simple to v1.7.26 2019-04-30 16:48:14 +00:00
Renovate Bot 68a0cc0433 Update dependency org.slf4j:slf4j-api to v1.7.26 2019-04-30 15:36:57 +00:00
Renovate Bot c8eb5b4e5a Update dependency org.slf4j:jcl-over-slf4j to v1.7.26 2019-04-30 15:36:50 +00:00
Renovate Bot 0f69d262e8 Update dependency org.apache.tomcat:catalina to v6.0.53 2019-04-30 13:15:29 +00:00
Renovate Bot 748a7172f5 Update dependency org.apache.tomcat.embed:tomcat-embed-core to v8.5.40 2019-04-30 13:15:22 +00:00
Misagh Moayyed d1c3660cda Update dependency javax.servlet:javax.servlet-api to v3.1.0 (#266)
Update dependency javax.servlet:javax.servlet-api to v3.1.0
2019-04-30 06:14:59 -07:00
Misagh Moayyed 78470351f6 Update dependency joda-time:joda-time to v2.10.1 (#267)
Update dependency joda-time:joda-time to v2.10.1
2019-04-30 06:14:50 -07:00
Misagh Moayyed 9e7ad3f046 Update dependency org.apache.maven.plugins:maven-javadoc-plugin to v3.1.0 (#275)
Update dependency org.apache.maven.plugins:maven-javadoc-plugin to v3.1.0
2019-04-30 06:14:37 -07:00
Misagh Moayyed 3688949646 Update dependency org.apache.maven.plugins:maven-surefire-plugin to v2.22.1 (#276)
Update dependency org.apache.maven.plugins:maven-surefire-plugin to v2.22.1
2019-04-30 06:14:29 -07:00
Renovate Bot a091c2795b Update dependency org.apache.maven.plugins:maven-surefire-plugin to v2.22.1 2019-04-30 12:49:37 +00:00
Renovate Bot 411a105fb1 Update dependency org.apache.maven.plugins:maven-javadoc-plugin to v3.1.0 2019-04-30 12:49:30 +00:00
Renovate Bot bd7ebc11c7 Update dependency joda-time:joda-time to v2.10.1 2019-04-30 11:26:23 +00:00
Renovate Bot 61c842124e Update dependency javax.servlet:javax.servlet-api to v3.1.0 2019-04-30 11:26:17 +00:00
Misagh Moayyed bb95fd733f Update dependency org.apache.maven.plugins:maven-compiler-plugin to v3.8.0 (#273)
Update dependency org.apache.maven.plugins:maven-compiler-plugin to v3.8.0
2019-04-30 04:25:46 -07:00
Misagh Moayyed 2b61ca1df3 Update dependency org.apache.maven.plugins:maven-enforcer-plugin to v1.4.1 (#274)
Update dependency org.apache.maven.plugins:maven-enforcer-plugin to v1.4.1
2019-04-30 04:25:38 -07:00
Misagh Moayyed b61487766c Update dependency junit:junit to v4.12 (#268)
Update dependency junit:junit to v4.12
2019-04-30 04:25:28 -07:00
Renovate Bot 1f6881829b Update dependency org.apache.maven.plugins:maven-enforcer-plugin to v1.4.1 2019-04-30 11:12:13 +00:00
Renovate Bot a8ec3de36e Update dependency org.apache.maven.plugins:maven-compiler-plugin to v3.8.0 2019-04-30 11:12:07 +00:00
Renovate Bot a4cde4359e Update dependency junit:junit to v4.12 2019-04-30 11:12:01 +00:00
Misagh Moayyed 44adee82ec Update dependency net.spy:spymemcached to v2.12.3 (#271)
Update dependency net.spy:spymemcached to v2.12.3
2019-04-30 04:11:21 -07:00
Misagh Moayyed 97632483aa Update dependency org.apache.maven.plugins:maven-assembly-plugin to v2.6 (#272)
Update dependency org.apache.maven.plugins:maven-assembly-plugin to v2.6
2019-04-30 04:11:12 -07:00
Misagh Moayyed 2362481941 Update dependency log4j:log4j to v1.2.17 (#269)
Update dependency log4j:log4j to v1.2.17
2019-04-30 04:10:59 -07:00
Renovate Bot 733ce5ba5d Update dependency org.apache.maven.plugins:maven-assembly-plugin to v2.6 2019-04-30 10:51:11 +00:00
Renovate Bot 66742817cc Update dependency net.spy:spymemcached to v2.12.3 2019-04-30 10:51:01 +00:00
Renovate Bot 0e333ec040 Update dependency log4j:log4j to v1.2.17 2019-04-30 09:39:34 +00:00
Misagh Moayyed a09641b184 Update dependency commons-codec:commons-codec to v1.12 (#265)
Update dependency commons-codec:commons-codec to v1.12
2019-04-30 01:02:18 -07:00
Renovate Bot 28ffa12548 Update dependency commons-codec:commons-codec to v1.12 2019-04-30 07:46:54 +00:00
Misagh Moayyed f6f20da863 Merge pull request #262 from kmnasir/jackson-patch
Updating jackson version to 2.9.8
2019-04-30 00:46:38 -07:00
Misagh Moayyed 22e77d2d12 Configure Renovate (#263)
Configure Renovate
2019-04-30 00:46:23 -07:00
Renovate Bot 93dac9b3fe Add renovate.json 2019-04-30 07:43:52 +00:00
Misagh Moayyed db0b8f8a42 Merge pull request #261 from kberzinch/master
Add login attempt events to Atlassian integration
2019-04-11 01:16:55 -07:00
Kristaps Berzinch 1c5dee3edf Add login attempt events 2019-04-11 00:51:45 -04:00
LELEU Jérôme abacb75df2 Handle encrypted PGTs (#260)
* Handle encrypted PGTs

* add tests

* stick to Java 6 and use commons-codec for Base64

* Remove the encrypted PGT after a PGT has been retrieved

* use Bouncycastle to load PEM files

* update to latest BC dependency
2019-04-03 13:53:09 +02:00
LELEU Jérôme 96f51465a8 Merge pull request #259 from leleuj/method
Support the method parameter
2019-03-14 19:11:02 +01:00
Jérôme LELEU 58de00e34b Support the method parameter 2019-03-13 09:15:07 +01:00
Hal Deadman 8cc5ad182c Merge pull request #255 from apereo/hdeadman-patch-1
Update README.md
2019-02-01 17:24:44 -05:00
Hal Deadman e3f532acde Update README.md
Add required serverName init parameter to example for Cas10TicketValidationFilter
2019-02-01 17:22:11 -05:00
Misagh Moayyed 86b93cbb26 clean up 2019-01-31 01:43:33 -07:00
Misagh Moayyed cc756cb72d update readme; add full-regex 2019-01-31 01:39:55 -07:00
Misagh Moayyed e2798c09cb Merge pull request #253 from apereo/inlined-attributes
Extract inlined CAS attributes in protocol 3 Ticket Validator
2019-01-29 23:12:07 +03:30
tsschmidt f06895bc18 Refactored and added unit test. 2019-01-24 16:31:54 -08:00
tsschmidt 18d981efaa Refactor 2019-01-23 10:24:01 -08:00
tsschmidt 080405b4c0 Extract inlined CAS attributes in protocol 3 Ticket Validator 2019-01-23 08:26:35 -08:00
Misagh Moayyed 45d4180a7f Merge pull request #252 from alterdego/master
Fixed typos in README.md
2019-01-14 06:53:40 -06:00
Document Doctor 77c013b03b Fixed typos in README.md 2019-01-12 01:18:14 -05:00
Document Doctor 7513f94877 Fixed typos in README.md 2019-01-11 21:42:00 -05:00
Cliff Ingham 2b1b7a142a Prioritize X-Forwarded-Host when choosing the service parameter
Use X-Forwarded-Host whenever it's available.
2018-12-14 16:28:55 -05:00
Dmitriy Kopylenko ba50664582 [maven-release-plugin] prepare for next development iteration 2018-11-01 10:32:59 -04:00
Dmitriy Kopylenko bafe64e7cd [maven-release-plugin] prepare release cas-client-3.5.1 2018-11-01 10:32:53 -04:00
Misagh Moayyed b2e1643893 Update pom.xml 2018-10-20 23:08:22 +03:30
Misagh Moayyed e155261a6b Merge pull request #248 from SmithJosh/respect-path-in-servername-config
Include serverName path when constructing service url
2018-10-10 09:52:17 +03:30
Joshua Smith c39735729d Include serverName path when constructing service url
Commit be2a641 introduced a bug which overwrites the serverName path component
when constructing service urls. This makes it impossible to deploy a CAS-
protected application behind a reverse proxy with a path prefix.

Now, the path from the incoming request is appended to the serverName path
instead of overwriting it.
2018-10-02 13:29:30 -07:00
Misagh Moayyed 2a570b26f1 Merge pull request #239 from mattdrees/issue-210-preserve-entity-stream-for-non-logout-requests
Add option to prevent entity stream consumption
2018-07-25 23:47:05 +04:30
Matt Drees 1d4312b64f Rename logoutPath to logoutCallbackPath 2018-07-25 13:07:29 -06:00
Misagh Moayyed af78b8703f Merge branch 'master' into issue-210-preserve-entity-stream-for-non-logout-requests 2018-07-25 10:25:51 +04:30
Misagh Moayyed 0e943179f1 Merge pull request #241 from mattdrees/support-prefix-config-for-authentication-filter
Support casServerUrlPrefix config option for AuthenticationFilter
2018-07-25 10:24:35 +04:30
Matt Drees 72e9aa9378 Tweak logoutPath docs 2018-07-24 16:08:48 -06:00
Matt Drees c5d1b1ef84 Stop using "matches" terminology 2018-07-24 16:07:44 -06:00
Matt Drees 40dcc8b34a Move utility method to CommonUtils 2018-07-24 15:19:01 -06:00
Matt Drees ba5982e1eb Add option to prevent entity stream consumption
If someone's app cannot handle the SingleSignOutFilter's consumption of entity streams
(via a `request.getParameter()` call) on all requests,
they can use this option in conjunction with setting up a service logout URL at the CAS server.
The filter will now only consume the stream on requests to this path.

Fixes https://github.com/apereo/java-cas-client/issues/210.
2018-07-24 15:19:00 -06:00
Matt Drees b6f6b5de76 Support casServerUrlPrefix config option
`casServerUrlPrefix` is used for validation and single logout,
but before this commit it couldn't be used by the auth filter.
As a result, web.xml needed to (for the typical usecase)
contain at least two references to the cas server.

Now, only one context init-param reference is necessary,
as long as the login page is hosted at {prefix}/login
(which seems to be mandated by cas protocol spec).
2018-07-24 15:18:24 -06:00
Misagh Moayyed 93561a297f Merge pull request #178 from jalios/master
Fix #177 Every other request incorrectly gatewayed
2018-07-25 00:24:13 +04:30
Misagh Moayyed c979e64006 Merge pull request #240 from mattdrees/fix-race-condition-in-http-server-tests
Fix race condition in PublicTestHttpServer tests
2018-07-25 00:22:57 +04:30
Matt Drees 306ec75569 Fix race condition in PublicTestHttpServer tests
The previous code assumed the server would start listening on the socket before tests ran, but didn't enforce this.
2018-07-24 11:29:25 -06:00
Misagh Moayyed a061764ca1 fix tests 2018-07-17 11:50:10 +04:30
Misagh Moayyed 7fbac753ee fix tests 2018-07-17 11:42:41 +04:30
Misagh Moayyed 15100f3c39 fix tests; adjust log levels for tests 2018-07-17 11:33:03 +04:30
Misagh Moayyed 87ac085dfd Rename stale.yml to .github/stale.yml 2018-07-17 11:08:37 +04:30
Misagh Moayyed a34a397a68 Create stale.yml 2018-06-08 10:48:49 -07:00
kmnasir 94b23a7f2d Updating jackson version to 2.9.5
Due to following vulnerabilities
CVE-2017-15095
CVE-2017-17485
CVE-2018-7489
2018-05-31 12:03:47 -04:00
Misagh Moayyed c015e226ba Merge pull request #231 from Unicon/urlenc-queryparams
Handle un-encoded query strings in url parameters as embedded query strings
2018-03-08 15:58:35 +01:00
Misagh Moayyed 5d18b34159 Update .travis.yml 2018-02-02 20:15:20 +01:00
Misagh Moayyed ae50749c5f Update .travis.yml 2018-01-31 21:48:55 +03:30
Misagh Moayyed 3875c39a21 handle un-encoded query strings in url parameters 2018-01-31 14:11:00 +03:30
Dmitriy Kopylenko b208e94b93 [maven-release-plugin] prepare for next development iteration 2018-01-12 11:56:32 -05:00
Dmitriy Kopylenko c00da6bb81 [maven-release-plugin] prepare release cas-client-3.5.0 2018-01-12 11:56:28 -05:00
Dmitriy Kopylenko 486aa66587 prepare for the release 2018-01-12 11:46:12 -05:00
Dmitriy Kopylenko 527f60f334 Polishing 2018-01-11 10:41:28 -05:00
Misagh Moayyed c06facd9e1 Merge pull request #209 from tkd-yas/master
Fix missing parameter key in service url (#208)
2017-10-06 04:31:21 -07:00
Misagh Moayyed 962c8185ae Merge pull request #220 from mmoayyed/tomcat85x
Add support for tomcat 8.5.x
2017-10-06 04:30:25 -07:00
Misagh Moayyed 6280319d80 Fix travis URLs: point to apereo rather than jasig 2017-07-11 16:58:14 -07:00
Misagh Moayyed 2d6b80842b updated docs 2017-07-06 14:06:24 -07:00
Misagh Moayyed b8f2e0a32c Add support for tomcat 8.5.x 2017-07-06 14:01:21 -07:00
Scott 47efae9e92 Merge pull request #213 from lxbzmy/patch-1
Add JIRA Rest API support
2017-06-21 23:20:17 -04:00
Misagh Moayyed ef2baa8983 Fixed logging issue; returning null in case principal cannot be determined 2017-06-20 09:21:04 -07:00
Misagh Moayyed 9d57eb3655 Merge pull request #188 from eghm/master
Log an error message if CAS principal has no corresponding Confluence principal
2017-06-20 09:18:46 -07:00
Misagh Moayyed f341f50cd5 Merge pull request #212 from mmoayyed/json-validator
New Json ticket validator to accept CAS responses in JSON.
2017-06-20 09:16:37 -07:00
Scott 52edf95202 Merge pull request #214 from hdeadman/master
Improve error logging when getting response from CAS server fails
2017-06-02 12:38:55 -04:00
Hal Deadman f9202b9a8a Improve error logging when getting response fails 2017-06-02 10:59:16 -04:00
Misagh Moayyed b02a122e9d Merge pull request #156 from joeschweitzer/master
Return existing user if session is already authenticated
2017-06-01 21:06:42 -04:00
Misagh Moayyed ccf8e718b2 Apply changes after code review by @serac 2017-06-01 21:03:51 -04:00
Alex Lei 雷 91dd394a08 Add JIRA Rest API support
new JIRA 6 has rest api begin with url /rest when I use cas authentication filter which skip filter /rest ,there will be thrown exception:

java.lang.NullPointerException
    at com.atlassian.jira.security.login.JiraSeraphAuthenticator.getUserFromBasicAuthentication(JiraSeraphAuthenticator.java:149) 
    at com.atlassian.seraph.auth.DefaultAuthenticator.getUser(DefaultAuthenticator.java:339) [atlassian-seraph-3.0.3.jar:?]
    at org.jasig.cas.client.integration.atlassian.Jira44CasAuthenticator.getUser(Jira44CasAuthenticator.java:76) [cas-client-integration-atlassian-3.4.1.jar:3.4.1] 
    at com.atlassian.seraph.auth.AbstractAuthenticator.getUser(AbstractAuthenticator.java:45) [atlassian-seraph-3.0.3.jar:?]
    at com.atlassian.seraph.filter.BaseLoginFilter$SecurityHttpRequestWrapper.getUserPrincipal(BaseLoginFilter.java:238) [atlassian-seraph-3.0.3.jar:?]
    at com.atlassian.seraph.filter.BaseLoginFilter$SecurityHttpRequestWrapper.getRemoteUser(BaseLoginFilter.java:225) [atlassian-seraph-3.0.3.jar:?]
    at javax.servlet.http.HttpServletRequestWrapper.getRemoteUser(HttpServletRequestWrapper.java:168) [servlet-api.jar:?]
    at com.atlassian.jira.web.filters.accesslog.AccessLogFilter.preFilterCallStep(AccessLogFilter.java:175) [classes/:?]
    at com.atlassian.jira.web.filters.accesslog.AccessLogFilter.executeRequest(AccessLogFilter.java:86) [classes/:?]
    at com.atlassian.jira.web.filters.accesslog.AccessLogFilter.doFilter(AccessLogFilter.java:78) [classes/:?]

After hard debug work I found key program flow different from default authenitcator  :

in `com.atlassian.seraph.filter.BaseLoginFilter#SecurityHttpRequestWrapper#getUserPrincipal()`

public Principal getUserPrincipal() {
            return BaseLoginFilter.this.getAuthenticator().getClass().isAnnotationPresent(AuthenticationContextAwareAuthenticator.class)?BaseLoginFilter.this.getAuthenticationContext().getUser():BaseLoginFilter.this.getAuthenticator().getUser(this.delegateHttpServletRequest);
        }

The `AuthenticationContextAwareAuthenticator` annotation cause different flow.

So, add `AuthenticationContextAwareAuthenticator` annotation can slow problem.
2017-05-27 11:13:09 +08:00
Misagh Moayyed 6468166c40 Merge pull request #124 from leleuj/casc-121
Upgrade to Java 6
2017-05-24 09:23:51 -04:00
leleuj 6f84cc2356 merge with master 2017-05-24 08:36:57 +02:00
Misagh Moayyed f5a0ee6987 Merge pull request #187 from Unicon/Frontchannel-slo
Handle front-channel SLO
2017-05-22 12:25:15 -04:00
Misagh Moayyed e56e0d2aa0 Exclude transaction dependency 2017-05-22 09:19:54 -07:00
Misagh Moayyed dfb13e5397 add test cases 2017-05-18 14:09:11 -07:00
Misagh Moayyed 552b9f9fac Fix test cases with attribute encoding 2017-05-18 12:31:44 -07:00
Misagh Moayyed 1e1a0ec5e8 update readme 2017-05-17 16:50:13 -07:00
Misagh Moayyed 24f1f9c814 clean up JIRA dependencies so project can compile 2017-05-17 16:42:09 -07:00
Misagh Moayyed 059ec7d527 clean up JIRA dependencies so project can compile 2017-05-17 16:31:50 -07:00
Misagh Moayyed f2ea4129bd allow extension points for JSON validation parsing. add filter and validator 2017-05-17 16:13:46 -07:00
Misagh Moayyed 88789ef358 allow extension points for JSON validation parsing. add filter and validator 2017-05-17 16:00:24 -07:00
Misagh Moayyed 5152f40be9 allow extension points for JSON validation parsing. add filter and validator 2017-05-17 15:59:20 -07:00
Misagh Moayyed 1fc896c458 allow extension points for JSON validation parsing. add filter and validator 2017-05-17 15:04:42 -07:00
Misagh Moayyed 1561da75ad Fix formatting issues with the markdown title 2017-04-25 09:28:10 -07:00
Yasuhiro Takada 834531c7a6 fix test faiiure 2017-04-17 20:36:40 +09:00
Yasuhiro Takada 2f7729a892 fix missing parameter key in service url when parameter value not provided. 2017-04-17 19:22:41 +09:00
Misagh Moayyed f998bb07c3 Merge pull request #200 from zhixiangli/master
add setter to ignoreUrlPatternMatcherStrategyClass
2017-01-05 19:29:56 +03:30
lizhixiang 47fb9c0fbb add setter to ignoreUrlPatternMatcherStrategyClass, with purpose of
injecting UrlPatternMatcherStrategy to AuthenticationFilter by Spring
IOC
2017-01-05 12:16:16 +08:00
Misagh Moayyed 4d1d62bd62 Merge pull request #184 from Unicon/Skew-assertion-date
Handle date equality when checking for assertion validity
2016-09-23 10:24:02 +03:30
eghm bad68332a6 Use parameterized log statement when logging CAS only principle. 2016-09-19 10:14:22 -10:00
eghm 2ae54e8d98 Log an error message if CAS principle has no corresponding Confluence principle. 2016-09-15 13:57:11 -10:00
Misagh Moayyed 6be07281d5 Fixed test cases 2016-09-09 16:22:32 +04:30
Misagh Moayyed 7db200e8c6 Updated front-channel SLO handling 2016-09-09 16:14:06 +04:30
Misagh Moayyed 527f0c6d28 Merge pull request #181 from Unicon/Tostring
Let ConfigurationKey toString() the name
2016-09-07 20:53:38 +04:30
Misagh Moayyed 7d5a9bc124 Merge pull request #185 from Unicon/Redundant-GroupId
Remove redundant groupId from POM defns
2016-09-07 20:53:21 +04:30
Misagh Moayyed 92371f794a Remove redundant groupId from POM defns 2016-09-07 16:12:34 +04:30
Misagh Moayyed 9e95ee5825 Handle date equality when checking for saml assertion validity 2016-09-07 16:10:16 +04:30
Scott 86a8f7395b Merge pull request #182 from Unicon/Refact
Minor code adjustments to CommonUtils to use String.isEmpty()
2016-09-07 07:30:43 -04:00
Misagh Moayyed 9d4cafd2c9 Let assertion validity checks to be more flexible
when comparing dates.
2016-09-07 15:47:04 +04:30
Misagh Moayyed 745fda6113 Minor code adjustments to CommonUtils to use String.isEmpty() 2016-09-07 15:38:46 +04:30
Misagh Moayyed aa6cab7d8d Merge pull request #180 from serac/logpt
Log proxy ticket returned from /proxy protocol endpoint.
2016-09-07 15:32:49 +04:30
Misagh Moayyed 9b71825e1a Let config keys log the name 2016-09-07 15:31:39 +04:30
Marvin S. Addison 2e27e09f3b Log proxy ticket returned from /proxy protocol endpoint. 2016-09-01 13:22:01 -04:00
Olivier Jaquemet b4d9570bdc Fix #177 Every other request incorrectly gatewayed
- ensure behavior of gateway is predictable (reentrant)
2016-08-09 10:27:27 +02:00
Marvin S. Addison 7cb5380e75 Issue #152 Jetty integration docs. 2016-05-24 07:53:15 -04:00
Scott e7292c78a0 Merge pull request #167 from geojs/issue-167
Wrong Maven groupId in README.md for Components
2016-05-16 12:54:07 -04:00
cobolgis 771288475f Recommended fix for #167. 2016-05-16 16:04:12 +02:00
Misagh Moayyed ee4a05d409 Merge pull request #166 from ceharris/patch-1
change git clone URL in README to reflect new org slug
2016-05-13 09:04:00 -07:00
Carl Harris f1cd2441ca change git clone URL to reflect new org slug 2016-05-13 11:03:11 -04:00
Scott 95c5d8ee73 Merge pull request #158 from BernhardLenz/cas-client-integration-tomcat-v8
Added Tomcat client v8 to readme and notice files
2016-04-01 00:05:51 -04:00
BernhardLenz f1908ba5fc Added Tomcat client v8 to readme and notice files 2016-03-28 09:02:46 -04:00
Joe Schweitzer 8e1a7789b1 Return existing user if session is already authenticated 2016-03-17 12:03:11 -04:00
Scott b20d4d241c Merge pull request #153 from serac/jetty
CAS Jetty Container Authentication Support
2016-03-08 07:20:51 -05:00
Marvin S. Addison bc586d7b4b Merge branch 'master' into jetty 2016-03-08 07:15:22 -05:00
Marvin S. Addison 06b566e2d6 Issue #152 Simplify ticket lookup. 2016-03-07 07:51:25 -05:00
Marvin S. Addison 3f0a1c6883 Issue #152 Fix javadoc typo. 2016-03-07 07:45:50 -05:00
Marvin S. Addison 812198b6a5 Issue #152 Use CommonUtils for null checks. 2016-03-07 07:45:26 -05:00
Scott 88d847102c Merge pull request #151 from BernhardLenz/cas-client-integration-tomcat-v8
Added cas-client-integration-tomcat-v8
2016-03-04 21:52:20 -05:00
Marvin S. Addison 40291a4478 Issue #152 Log authentication success at INFO. 2016-02-19 10:43:15 -05:00
Marvin S. Addison 184868b296 Issue #152 Add working Jetty context config files. 2016-02-12 16:40:05 -05:00
Marvin S. Addison 5a68c92268 Issue #152 Prevent dupe ticket validations.
The ticket parameter can linger in the URL after authentication.
Don't attempt ticket validation if we are already authenticated.
Fixes ticket validation failures on refresh and similar cases.
2016-02-12 16:20:56 -05:00
Marvin S. Addison f09ee1c0e7 Issue #152 Fix multiple ticket validation attempt. 2016-02-12 15:34:19 -05:00
Marvin S. Addison 971d4b4854 Issue #152 Remove unused jetty-maven-plugin. 2016-02-11 15:12:39 -05:00
Marvin S. Addison f04dedd9bb Issue #152 Use WeakReference to avoid resource leak.
We don't want to hold a reference to HttpSession objects in the
ticket-to-session mapping that would prevent orphaned or expired sessions
from being purged. WeakReference ensures that won't happen.
2016-02-11 15:08:00 -05:00
Marvin S. Addison 53dbb48882 Issue #152 Jetty container-based authn. 2016-02-11 14:53:14 -05:00
BernhardLenz 61bd0eeb86 Added cas-client-integration-tomcat-v8 2016-02-04 18:45:03 -05:00
Scott e4b767700a Merge pull request #143 from battags/CASC-127
CASC-127 Remove Commons Codec Dependency
2015-11-19 21:02:57 -05:00
Scott 346374ebc8 CASC-127 Remove Commons Codec Dependency
Problem: We rely on Commons Codec for some simple Base64 decoding/encoding, most of which is available in Java 1.6+
Solution: Set minimum version to Java 1.6 and rely on provided methods.

QA Notes: Unit tests pass
2015-11-18 21:58:06 -05:00
Misagh Moayyed 4b63e06418 updated docs on SSOFilter and ErrorRedirectFilter 2015-11-08 13:54:31 -07:00
Misagh Moayyed 32963967d4 updated docs on SSOFilter and ErrorRedirectFilter 2015-11-08 13:53:33 -07:00
Scott 9d9e5cad72 Merge pull request #142 from serac/issue-141-remove-content-length
Issue-141 Remove redundant Content-Length header.
2015-11-05 20:43:56 -05:00
Marvin S. Addison 598fb02dda Issue-141 Remove redundant Content-Length header. 2015-11-05 16:44:05 -05:00
Misagh Moayyed a417f78521 Fix badge link for maven version 2015-09-13 08:16:18 -07:00
Scott a5e2b8ae61 [maven-release-plugin] prepare for next development iteration 2015-09-13 00:23:55 -04:00
Scott 650cee05bc [maven-release-plugin] prepare release cas-client-3.4.1 2015-09-13 00:19:52 -04:00
Scott e5f933754b [maven-release-plugin] rollback the release of cas-client-3.4.1 2015-09-13 00:18:34 -04:00
Scott 1bdc456bf4 [maven-release-plugin] prepare for next development iteration 2015-09-13 00:13:20 -04:00
Scott 8067714256 Added missing license headers. 2015-09-13 00:11:09 -04:00
Scott 85b0454e8d Merge pull request #133 from battags/131
Issue #131 - ConfigurationStrategyName does not Properly Resolve Cust…
2015-09-10 09:27:08 -04:00
Scott 2eb132c0b4 Issue #131 - ConfigurationStrategyName does not Properly Resolve Custom classes
Problem: The assignable check was reversed, always resulting in a false return value.
Solution: Add test to confirm failure and then swap check.  Unit tests pass.
2015-09-09 23:30:53 -04:00
Scott 0022c622e1 Merge pull request #130 from mmoayyed/serviceurl-construction-method
Overload constructServiceUrl to keep backward compatibility
2015-08-19 22:28:58 -04:00
Misagh Moayyed ab105cdcfa initialize service parameter names once, statically 2015-08-19 08:51:28 -07:00
Misagh Moayyed 1f3a745ec8 overload constructServiceUrl to keep backward compatibility 2015-08-19 02:28:20 -07:00
Scott ba47157062 Merge pull request #128 from mmoayyed/uribuilder-tests
URIBuilder test cases
2015-08-13 07:37:08 -04:00
Misagh Moayyed 4f746b3b58 Update .travis.yml 2015-08-13 03:00:26 -07:00
Misagh Moayyed d7538dfd61 Update .travis.yml 2015-08-13 02:59:36 -07:00
LELEU Jérôme 335d3f3a3e Update .travis.yml 2015-08-13 11:36:24 +02:00
Misagh Moayyed 618a99a245 URIBuilder test cases 2015-08-12 12:36:50 -07:00
LELEU Jérôme 0d2740ec0c Merge pull request #125 from xuhuisheng/master
URIBuilder throws UnsupportedOperationException on adding/setting parameters
2015-08-10 10:35:13 +02:00
Xu Huisheng 69bba0c21a When serverName contains schema, the URIBuilder will throw an UnsupportedOperationException while adding a parameter. 2015-08-04 18:20:31 +08:00
Jérôme LELEU f0047eb8eb upgrade version to 3.5.0-SNAPSHOT 2015-08-03 12:53:19 +02:00
Jérôme LELEU 60b8ad70f8 Upgrade to Java 6 2015-07-31 17:02:21 +02:00
LELEU Jérôme d46e3c6220 Merge pull request #122 from leleuj/casc-119
Deploy SNAPSHOTs to Sonatype
2015-07-31 10:37:29 +02:00
Jérôme LELEU 8ff374b949 Revert "using the old Travis infrastructure (no container)"
This reverts commit ce06a4fd91.
2015-07-30 11:23:47 +02:00
Jérôme LELEU e9b79194d7 using the old Travis infrastructure (no container) 2015-07-30 11:05:12 +02:00
LELEU Jérôme 72685767f7 Merge pull request #123 from leleuj/casc-120
Update README with 3.4 features
2015-07-29 11:13:52 +02:00
Jérôme LELEU bb11bfa7c8 Update README with 3.4 features 2015-07-28 09:29:27 +02:00
Jérôme LELEU bdecba6431 Deploy SNAPSHOTs to Sonatype 2015-07-28 08:42:33 +02:00
Scott 67b4b26819 [maven-release-plugin] prepare for next development iteration 2015-07-21 22:57:28 -04:00
Scott f3d7156482 [maven-release-plugin] prepare release cas-client-3.4.0 2015-07-21 22:57:26 -04:00
Scott 8bab6d1f4e Fixed licenses 2015-07-21 22:42:41 -04:00
Scott 76ba57a541 Added missing license headers 2015-07-21 22:19:00 -04:00
Scott ec744b2c9f Updated NOTICE generation. 2015-07-21 22:16:53 -04:00
Misagh Moayyed 4db9948c19 Moved build to the new travis environment 2015-07-10 08:34:46 -07:00
Scott 0a7ffac846 Merge pull request #66 from Unicon/CASC-210
CASC-210: Added support for having regex expressions in the proxy (chaining) list.
2015-07-07 17:10:05 -04:00
Scott c8e50905bb Merge pull request #116 from Unicon/remove-lang
removed commons-lang dependency
2015-07-03 11:27:00 -04:00
Scott eaee34b361 Merge pull request #105 from mmoayyed/removing-service-param
Added uri builder to construct query params
2015-07-03 11:13:31 -04:00
Scott 6ce10daea0 Merge pull request #117 from lathspell/master
Add filter-mapping to web.xml filter examples
2015-07-03 09:22:29 -04:00
John Gasper f98e776869 casc-210: Merge branch 'master' of https://github.com/jasig/java-cas-client into CASC-210
Resolved Conflicts:
	cas-client-core/src/main/java/org/jasig/cas/client/validation/ProxyList.java
2015-06-16 12:09:37 -07:00
Christian Brunotte df07758a89 missing "<" in example 2015-06-16 19:30:49 +02:00
Christian Brunotte 302822f361 Added <filter-mapping> to all web.xml <filter> examples. 2015-06-16 19:29:16 +02:00
Misagh Moayyed e1e12a5f3f removed since tags 2015-06-10 20:09:15 -07:00
Misagh Moayyed 8c77fc4eaf removed commons-lang dep 2015-06-10 20:04:12 -07:00
Scott 607d53a2aa Merge pull request #113 from Unicon/commons-lang3
Upgrade to commons-lang3
2015-06-08 22:56:07 -04:00
Misagh Moayyed 70b8aa8032 Merge pull request #112 from Unicon/depc-const
Deprecated unused DISABLE_XML_SCHEMA_VALIDATION
2015-06-07 20:48:35 -07:00
Misagh Moayyed 806672e525 Merge pull request #114 from Unicon/proxying-log-warn
Added additional logs to proxy validation
2015-06-07 20:48:26 -07:00
Misagh Moayyed 853450a8a6 added additional logs to proxy validation 2015-06-07 17:05:47 -07:00
Misagh Moayyed 05873137dc Update README.md 2015-06-07 13:29:05 -07:00
Misagh Moayyed 8bc89e648a Create .travis.yml 2015-06-07 13:27:32 -07:00
Misagh Moayyed f1ac21943d upgrade to commons-lang3 v3.4 2015-06-07 13:24:12 -07:00
Misagh Moayyed c6c106c375 deprecated unused const 2015-06-07 13:18:19 -07:00
Misagh Moayyed 0a6ce18150 updated param building 2015-06-05 15:17:04 -07:00
Misagh Moayyed 73e2a63a5b Merge branch 'master' into removing-service-param 2015-06-05 15:14:29 -07:00
Misagh Moayyed 77e5340c3c Update README.md 2015-05-24 18:59:20 +04:00
Misagh Moayyed 573976cda9 Update README.md 2015-05-23 23:09:30 +04:00
Misagh Moayyed dc028a6652 Update README.md 2015-05-23 23:08:50 +04:00
Misagh Moayyed 50fc28034d Update README.md 2015-05-23 22:50:52 +04:00
Misagh Moayyed 3c40922847 Update README.md 2015-05-23 22:50:09 +04:00
Misagh Moayyed d72913b53a Update README.md 2015-05-23 22:01:48 +04:00
Misagh Moayyed a31979920b Update README.md 2015-05-23 21:50:09 +04:00
Misagh Moayyed 8ec71aa2c6 Update README.md 2015-05-23 16:41:15 +04:00
Misagh Moayyed 74f0a209dd Update README.md 2015-05-23 16:40:15 +04:00
Misagh Moayyed f8f5b908d0 Create README.md 2015-05-23 02:46:17 +04:00
Misagh Moayyed d3ba9c0ae7 Delete README.txt 2015-05-23 02:45:28 +04:00
Misagh Moayyed f68281d0e4 added uri builder to construct query params 2015-05-13 03:44:13 -07:00
Marvin S. Addison 863038605f Merge pull request #101 from Jasig/no-opensaml
Remove OpenSAML and consolidate SAML components in support module
2015-05-12 09:29:02 -04:00
Marvin S. Addison f5b2275913 Issue #100 Bump minor version due to refactoring. 2015-05-11 12:09:00 -04:00
Marvin S. Addison 1edef62ecb Issue #100 Isolate JodaTime to SAML module. 2015-05-11 12:01:48 -04:00
Marvin S. Addison 7c58629958 Issue 100 Restore configuration key for backward compatibility. 2015-05-04 16:10:56 -04:00
Marvin S. Addison 70ed5fd8bb Add Marvin to SAML validator component authorship. 2015-05-04 16:07:47 -04:00
Marvin S. Addison 6e261e7251 Issue #100 Respond to code review feedback. 2015-04-20 10:34:28 -04:00
Scott 0652f4ee23 Merge pull request #93 from leleuj/CASC-217
CASC-217: Update the ticket validators to point to the new endpoint
2015-04-20 06:54:48 -04:00
Marvin S. Addison d8980535b7 Move SAML components into separate module. 2015-04-14 16:19:12 -04:00
Marvin S. Addison dd0818b84f Fix @since version. 2015-02-20 10:35:05 -05:00
Marvin S. Addison 4527671568 Sensible XPath processing optimizations. 2015-02-20 10:26:01 -05:00
Marvin S. Addison e998985732 SAML validation with XPath instead of OpenSAML. 2015-02-20 09:18:05 -05:00
Scott 6f7fe61780 Merge pull request #97 from battags/CASC-239
CASC-239 Saml11AuthenticationFilter Constructor was Private instead of Public
2015-01-25 19:11:28 -05:00
Scott db3610123f CASC-239 Saml11AuthenticationFilter Constructor was Private instead of Public. 2015-01-24 23:58:51 -05:00
Scott 380585d391 Merge pull request #96 from Jasig/conditional-opensaml-init
CASC-237 Make OpenSAML bootstrap conditional.
2015-01-20 08:34:08 -05:00
Marvin S. Addison 4aef368057 CASC-237 Make OpenSAML bootstrap conditional. 2015-01-17 11:25:03 -05:00
Scott 6de80009cf Merge pull request #94 from leleuj/casc-91
Issue-91: Introduce system properties configuration option
2015-01-07 08:48:41 -05:00
LELEU Jerome bec0e6bb2e Issue-91: Introduce system properties configuration option
First commit
2015-01-05 17:19:40 +01:00
LELEU Jerome 2a98556daa CASC-217: Update the ticket validators to point to the new endpoint
First commit
2015-01-05 15:55:33 +01:00
Scott f49c08ce93 Merge pull request #88 from battags/CASC-231
CASC-231 HttpsURLConnectonFactory is Not Serializable
2014-12-22 23:56:48 -05:00
Scott ec92d97518 Added license headers 2014-12-22 23:55:23 -05:00
Scott 34458db530 Merge branch 'master' into CASC-231 2014-12-22 23:54:46 -05:00
Scott 0b220c6f55 Merge pull request #89 from battags/CASC-200
CASC-200 Introduce Properties File Configuration Option
2014-12-22 22:10:50 -05:00
Scott 39f0f29dd9 CASC-200 Introduce Properties File Configuration Option
Problem: We can configure via JNDI, WebXML (or both) but not by properties file.
Solution: Introduce a method to use property files.
2014-12-07 14:14:08 -05:00
Scott d1da02f457 CASC-231 HttpsURLConnectonFactory is Not Serializable
Problem: THe HttpsURLConnectionFactory is not serializable, causing problems for clients that must serialize
the principal (which depends on a ProxyRetriever).

Solution: Make the HttpsURLConnectionFactory serializable.

QA Notes: added unit test to confirm serialize-deserialize
2014-12-07 13:32:14 -05:00
Scott d7ca6a098e Merge pull request #87 from battags/CASC-233
CASC-233 ErrorRedirectFilter Can throw Null Pointer Exception
2014-12-07 12:13:27 -05:00
Scott f17c4d6087 Merge pull request #86 from battags/CASC-200-rebasefail
CASC-200 Introduce Mechanism to Indicate Method of Configuration
2014-12-07 12:12:56 -05:00
Scott a780e39ab9 Merge branch 'master' into CASC-200-rebasefail
Conflicts:
	cas-client-core/src/main/java/org/jasig/cas/client/session/SingleSignOutFilter.java
2014-12-07 12:11:42 -05:00
Scott Battaglia bef2a88603 Updated try/catch loop to log when a class is not found. 2014-11-30 17:09:09 -05:00
Scott Battaglia 3af5683dc1 Addressed formatting feedback as well as reserved keywords. 2014-11-26 22:58:12 -05:00
Scott Battaglia 5109132df3 Per feedback, scoped catch block to Exception instead of Throwable 2014-11-26 22:31:01 -05:00
Scott Battaglia 51a9192792 CASC-233 ErrorRedirectFilter Can throw Null Pointer Exception
Problem: the ErrorRedirectFilter assumes there is a root cause and will null pointer if there is not.
Solution: Only use the root cause if there is one, otherwise use the original exception.

QA Notes: Added unit test to confirm non-root cause error.
2014-11-20 16:29:29 -05:00
Scott Battaglia c7e66d7df2 Unused reference to Mockito 2014-11-20 16:03:19 -05:00
Scott Battaglia d011f5e64a Removed unused mockito dependency 2014-11-20 16:01:02 -05:00
Scott Battaglia 17f887595f Added missing javadoc for Protocol enumeration 2014-11-20 15:58:52 -05:00
Scott Battaglia 324b0919b6 Added additional keys that were new from the single signout refactor. 2014-11-20 15:31:31 -05:00
Scott Battaglia 461cdcd8fc CASC-200 Create a ConfigurationStrategy to allow for pluggable configurations.
Problem: The lookup strategy for configuration is hard-coded into the filter, making it impossible to replace or expand.
Solution: Pull the strategies into their own classees and make it configurable.  Default to the previous strategy.

QA Notes: The current unit tests work.  New unit tests for the configuration will have to be added once the design is approved.
2014-11-20 15:30:38 -05:00
Marvin S. Addison 4e3f761efe [maven-release-plugin] prepare for next development iteration 2014-08-15 08:52:01 -04:00
Marvin S. Addison 0174cfbbb5 [maven-release-plugin] prepare release cas-client-3.3.3 2014-08-15 08:51:04 -04:00
Marvin S. Addison f57f0ff096 Update notice files. 2014-08-15 08:48:05 -04:00
Scott 117f32006f Merge pull request #79 from battags/CASC-229
CASC-229 Make Front Channel SSO Optional so that backwards compatibility...
2014-08-13 10:13:45 -04:00
Scott db53818de7 Merge pull request #80 from battags/CASC-230
CASC-230 Call HttpServletRequest#logout() via Reflection to Improve Back...
2014-08-13 10:13:28 -04:00
Scott ecef8dd722 Merge pull request #78 from battags/CASC-225
CASC-225 Restore Removed Constructor for Backwards Compatibility
2014-08-13 10:13:20 -04:00
Scott Battaglia b34c4e104f Updated code to abstract the reflection logic a bit more behind a strategy interface. 2014-08-11 23:04:24 -04:00
Scott Battaglia a0f8845ecf CASC-230 Call HttpServletRequest#logout() via Reflection to Improve Backwards Compatibility with Spring Security 2014-08-11 22:50:23 -04:00
Scott Battaglia b18dbfe0a9 CASC-229 Make Front Channel SSO Optional so that backwards compatibility is maintained.
Problem: Spring Security adopters will fail to be able to drop in a new version of CAS Client for Java if this feature is enabled by default/required.
Solution: Force a fail-safe optional mode if the value is not provided.
2014-08-11 22:36:27 -04:00
Scott Battaglia 42ce676ef0 CASC-225 Restore Removed Constructor for Backwards Compatibility
Problem: We removed the two string constructor which breaks Spring Security compatibility.
Solution: Add it back as deprecated so that Spring Security can upgrade.
2014-08-11 22:09:27 -04:00
Scott Battaglia aa3e07bd79 [maven-release-plugin] prepare for next development iteration 2014-08-03 00:22:49 -04:00
Scott Battaglia 112f068607 [maven-release-plugin] prepare release cas-client-3.3.2 2014-08-03 00:22:14 -04:00
Scott Battaglia d191ac8ee6 Added missing license header. 2014-08-03 00:03:25 -04:00
Scott Battaglia 61a92c0e7f CASC-224 Replace URL with String to remain compatible with Spring Security 2014-07-20 20:31:35 -04:00
Scott 266eba7c2d Merge pull request #73 from battags/CASC-228
CASC-228 URL Encode Paramaters Passed to Server via Validate
2014-06-29 15:11:58 -04:00
Scott Battaglia 9de2be91a2 CASC-228 URL Encode Paramaters Passed to Server via Validate
Problem: We currently don't pass encoded values to the server, possibly resolving in parsing/extraction errors.
Solution: URL Encode all values instead of just the service url.

QA Notes: Added unit test.
2014-06-24 18:44:45 -04:00
Scott 566c8690c8 Merge pull request #72 from battags/CASC-223
CASC-223 Backwards Compatibility for Initializing Sign Out Handler in Filter
2014-05-22 22:03:26 -04:00
Scott aeaa76ce46 Merge pull request #71 from battags/CASC-224
CASC-224 Public API Method Removed without Deprecation
2014-05-12 22:34:01 -04:00
Scott Battaglia a44b4c1229 Removed no-longer valid test. 2014-05-06 23:17:32 -04:00
Scott Battaglia a4e984e4ea Synchronize the init method in case we have multiple concurrent requests at the same time. 2014-05-06 22:53:05 -04:00
Scott Battaglia 2c9090155a CASC-223 SingleSignOutFilter requires init method to be called which changes the contract with previous versions
Problem: Some clients such as Spring Security configure the filter via Spring configuration, meaning the handler's init method
is not called vai the Filter#init method.

Solution: For now, have an atomic boolean to determine if init was called or not and call it if necessary as part of the flow.
2014-05-06 22:35:55 -04:00
Scott Battaglia b4fbf23361 CASC-224 Public API Method Removed without Deprecation
Problem: Previous versions of the CAS Client remove a public API method without sufficient deprecation time resulting in
problems for clients who want to upgrade.

Solution: Add Method back and mark it as deprecated.
2014-05-06 22:12:59 -04:00
John Gasper c61dea96bf Formatting clean-up 2014-04-15 12:56:46 -07:00
John Gasper 99763ab2b6 Using Misagh's PatternMatcherStrategy to optimize proxy chain checks 2014-04-14 08:45:21 -07:00
John Gasper 7ac4c7afb7 Merge branch 'master' of https://github.com/jasig/java-cas-client into CASC-210 2014-04-11 15:17:29 -07:00
LELEU Jérôme 4e7bf66d68 Merge pull request #68 from leleuj/CASC-220
CASC-220: Support front channel SLO logout
2014-04-09 08:10:42 +02:00
Jérôme LELEU c4c3223140 CASC-220: Support front channel SLO logout
Update after new Misagh's comments
2014-04-07 18:54:40 +02:00
LELEU Jerome 4a0e960c32 CASC-220: Support front channel SLO logout
Updates after Marvin's code review
2014-04-01 16:46:19 +02:00
Jérôme LELEU 7069a4f6fb CASC-220: Support front channel SLO logout
Update after Scott's code review
2014-03-27 21:02:30 +01:00
Jérôme LELEU 6aa2379268 CASC-220: Support front channel SLO logout
Updates after Misagh's code review
2014-03-21 14:10:33 +01:00
Scott Battaglia 80f7f3647e [maven-release-plugin] prepare for next development iteration 2014-03-19 20:55:47 -04:00
Scott Battaglia 3373d7f767 [maven-release-plugin] prepare release cas-client-3.3.1 2014-03-19 20:55:38 -04:00
Scott Battaglia 896958337a Updated to parent pom 39 2014-03-19 20:50:45 -04:00
Scott Battaglia 72766daac5 Added in missing license header. 2014-03-18 19:26:45 -04:00
unknown 9714053f07 Merge remote-tracking branch 'upstream/master' into CASC-220 2014-03-18 08:16:29 +01:00
Misagh Moayyed 286105266f Merge pull request #67 from battags/CASC-214
CASC-214 Improve Service Url Construction to Add Non-Standard Ports
2014-03-17 09:15:29 -07:00
Misagh Moayyed f018f54c4c Merge pull request #64 from mmoayyed/CAS-219
CAS-219: Provide support for certain urls to be excluded from CAS filters
2014-03-17 00:21:53 -07:00
Misagh Moayyed ed4802f943 CASC-219: added final 2014-03-17 00:18:56 -07:00
LELEU Jerome 9b33321cc2 CASC-220: Support front channel SLO logout
specific front logout parameter + Tomcat valves update
2014-03-14 10:52:42 +01:00
LELEU Jerome 47f825871e CASC-220: Support front channel SLO logout
First commit
2014-03-13 19:03:41 +01:00
Misagh Moayyed d2b93a237f CASC-219: added exact-matcher strategy 2014-03-13 08:26:22 -07:00
Misagh Moayyed 0a8fd79a44 CASC-219: changed exact to contains 2014-03-13 03:20:39 -07:00
Misagh Moayyed 00ee9e378d CASC-219: renamed matcher class to match behavior 2014-03-12 07:37:59 -07:00
Misagh Moayyed 248643cf30 CASC-219: switched warn to error, fixed typo and this refs 2014-03-11 08:46:00 -07:00
Misagh Moayyed dfb3629dc2 CASC-219: updated internal map to be a static ref instead 2014-03-11 07:11:53 -07:00
Misagh Moayyed 511bce2471 CASC-219: allowed extensions for ignoring urls 2014-03-11 05:04:59 -07:00
Misagh Moayyed 3773fc9e54 CASC-219: updated javadocs and added map to keep track of pattern matchers 2014-03-11 04:24:27 -07:00
Misagh Moayyed b97d03d126 CASC-219: Cleaned up formatting issues 2014-03-10 05:22:44 -07:00
Scott Battaglia a4df6582ee Removed debug statements used to confirm private methods worked. 2014-03-09 23:18:14 -04:00
Scott Battaglia 75584a2c33 CASC-214 Improve Service Url Construction to Add Non-Standard Ports if Missing from Configuration
Problem: sometimes the port is missing from the configuration.  This generates the wrong service url.
Solution: Add the server port if the server configuration does not have one.
QA Notes: Added unit tests to confirm behavior (and old unit tests still pass)
2014-03-09 23:13:04 -04:00
John Gasper 0ef575ae84 Refactored the match logic and cache the regex patterns. 2014-03-07 16:11:00 -08:00
Misagh Moayyed 71b366cbf3 CASC-219: Provide support for certain urls to be excluded from CAS filters. 2014-03-07 11:17:14 -07:00
Misagh Moayyed b9ac92cf25 CASC-219: Provide support for certain urls to be excluded from CAS filters. 2014-03-07 01:52:50 -07:00
John Gasper 887da3bffd no message 2014-03-05 10:54:34 -08:00
John Gasper 90ccc41db3 Minor corrections. 2014-03-05 10:45:35 -08:00
John Gasper 80ff9857f0 Added support for having regex expressions in the proxy (chaining) list. 2014-03-05 10:17:59 -08:00
Misagh Moayyed 44d1413fa7 CAS-219: Provide support for certain urls to be excluded from CAS filters. 2014-03-02 03:03:24 -07:00
Misagh Moayyed c857e4610b CAS-219: Provide support for certain urls to be excluded from CAS filters. 2014-02-27 22:02:19 -07:00
Marvin S. Addison 590a79c6a6 Merge pull request #63 from battags/CASC-203
CASC-203 Properly Parse Response to Keep Line Breaks
2014-02-20 13:49:50 -05:00
Scott Battaglia 36b8db1e86 CASC-203 Properly Parse Response to Keep Line Breaks
Problem: The CAS Client uses a buffer reader which strips out the returned line breaks.
Solution: Switch to a normal input stream reader and add appropriate test.
2014-02-17 23:09:32 -05:00
Scott Battaglia 4d7b2517a9 [maven-release-plugin] prepare for next development iteration 2014-01-07 21:15:06 -05:00
Scott Battaglia 4d12772bc4 [maven-release-plugin] prepare release v3.3.0 2014-01-07 20:37:19 -05:00
Scott Battaglia 8262bc1fff Updated notice and pom 2014-01-07 20:31:34 -05:00
Scott Battaglia a199892c73 Updated notice file 2014-01-07 20:31:24 -05:00
Scott Battaglia 00a507d51b Updated Atlassian Maven Repository location 2014-01-07 20:04:57 -05:00
Scott Battaglia 19e5e0671b Added generated notice files 2014-01-07 20:00:30 -05:00
Scott Battaglia 2a2fc56031 Fixed licensing / exclusions. 2014-01-06 23:51:09 -05:00
Scott Battaglia 89e6bfd521 Fixed license files 2014-01-05 23:04:03 -05:00
Scott Battaglia 6ba3f6f884 Added missing license headers 2014-01-05 22:53:17 -05:00
Scott Battaglia d0d7fd684d Correct license header information. 2014-01-05 22:52:15 -05:00
Scott Battaglia 57d2d66a1d Updated pom.xml to the latest jasig-parent pom (38) 2014-01-05 22:36:38 -05:00
Scott Battaglia fe9dac934a [maven-release-plugin] rollback the release of v3.3.0 2014-01-05 22:06:46 -05:00
Scott Battaglia 577dafef0e Updated to Jasig Parent POM Version 37 and set up correct release version. 2013-12-29 17:17:26 -05:00
Scott Battaglia cef064f34b Updated pom.xml file to jasig-parent-36 2013-12-17 17:35:43 -05:00
Scott b3afc92fc7 Merge pull request #58 from serac/jaas-logout-fix
Destroy cached assertions in CasLoginModule#logout() method
2013-11-12 16:34:27 -08:00
Marvin S. Addison 5b1bd87e7a Put HttpServletRequest#logout() in separate try/catch block. 2013-10-28 16:07:28 -04:00
Marvin S. Addison 82c95aaf19 Respond to code review feedback.
1. Call HttpServletRequest#logout() on SLO callback since it is available.
2. Use final for local variables where possible.
2013-10-28 15:58:40 -04:00
Marvin S. Addison 328692bb40 Remove cached assertions on logout to prevent credential replay attack. 2013-10-24 12:57:25 -04:00
Scott 46416fe741 Merge pull request #57 from h0nIg/memcachedclient
use memcached interface instead of implementation / updated client library
2013-09-02 12:28:52 -07:00
Hans-Joachim Kliemeck 6b50b18d66 changed from provided to compile 2013-09-02 19:37:46 +02:00
Marvin S. Addison 575de47020 Merge pull request #56 from serac/CASC-174
CASC-174 Provide Programmatic JAAS Login Facility for JBoss 7
2013-08-26 04:23:25 -07:00
Hans-Joachim Kliemeck 259afc7a62 updated memcached version 2013-08-17 14:19:42 +02:00
Hans-Joachim Kliemeck b697a4b0ba use interface instead of implementation 2013-08-17 13:45:34 +02:00
Marvin S. Addison 5ce3bcb3d3 CASC-174 Remove @version javadoc tag. 2013-08-15 11:05:32 -04:00
Marvin S. Addison 75406c916e CASC-174 Remove JBoss verbiage from error message. 2013-08-01 14:10:38 -04:00
Marvin S. Addison 517f94bd97 CASC-174 Provide facility for Servlet 3.0 programmatic JAAS login.
Servlet3AuthenticationFilter supersede the JBoss-specific
WebAuthenticationFilter for JBoss 7. It should also provide support for
programmatic JAAS login for any container that is Servlet 3.0/JEE6
compliant.
2013-08-01 14:05:01 -04:00
Scott 526c65fb39 Merge pull request #54 from battags/master
Updated Jasig Parent POM Version
2013-06-26 17:50:14 -07:00
Scott Battaglia adb668d9ed Latest Jasig pom file 2013-06-26 20:48:55 -04:00
Scott 15103333e5 Merge pull request #52 from battags/CASC-211
CASC-211 Better Ticket Validation Error Logic
2013-06-20 16:31:59 -07:00
Scott Battaglia 8ab75b883a Renamed arguments 2013-06-20 19:28:35 -04:00
Scott 4b87b4a9f5 Merge pull request #53 from battags/XML-Fix
Switched to SaxParserFactory directly.  Unit tests pass.  CASC-212
2013-06-20 04:08:12 -07:00
Scott Battaglia 715659ebcf Switched to SaxParserFactory directly. Unit tests pass. CASC-212 2013-06-20 00:15:53 -04:00
Scott Battaglia a9d640b1b0 Fixed formatting again. 2013-06-19 23:16:17 -04:00
Scott Battaglia b802354fdb Changed default for exceptionOnValidationFailure and message.
This seems to have some formatting changes in it also for some reason.
2013-06-19 23:11:22 -04:00
Scott fddafb753f Merge pull request #51 from battags/master
[NOJIRA] Reformat to Eclipse Standard
2013-06-19 19:55:55 -07:00
Scott Battaglia 1993718cc7 Reformat all files using shared CAS Eclipse formatter. 2013-06-19 22:50:02 -04:00
Scott 180f1f803b Merge pull request #49 from battags/CASC-206
CASC-206 Added Authentication Redirect Strategy to support original use case and new Faces support
2013-06-19 19:30:28 -07:00
Scott Battaglia 9674ad8a45 Swithed to existing Reflection utils. Added supporting unit test. 2013-06-19 22:26:09 -04:00
Scott Battaglia 8a7e32e5be Merge branch 'master' into CASC-206 2013-06-19 22:25:18 -04:00
Scott d413ee5cf8 Merge pull request #50 from battags/CASC-207
CASC-207 - Converted to static logger for serializable class
2013-06-19 07:12:31 -07:00
Scott Battaglia 077e991ae6 CASC-207
Converted logger to static for de-serialization purposes.
2013-06-18 22:38:25 -04:00
Scott Battaglia 8643e85b1e Added missing javadoc 2013-06-18 22:07:50 -04:00
Scott Battaglia 73e36bf6d2 Fixed failing test case that was missing an import statement. 2013-06-18 21:57:22 -04:00
Scott Battaglia 8df9f0272b Added redirect strategy to support Faces. 2013-06-18 21:56:58 -04:00
Scott Battaglia 091f1d5f90 Merge branch 'master' of github.com:Jasig/java-cas-client 2013-06-18 21:08:50 -04:00
Scott 4802ad8c17 Merge pull request #47 from mores/CASC-208
[CASC-208] Prevent unnecessary log errors
2013-05-07 18:06:32 -07:00
mores 2b53bdf882 getSocketFactory() should only be called on a sslContext that has been initialized. 2013-05-06 13:46:47 -04:00
Scott c36c8e952c Merge pull request #45 from mores/CASC-205
[ CASC-205 ] Saml11TicketValidator unable to process type XSString
2013-04-25 06:45:10 -07:00
mores e6e0f907b8 Fix to allow client to work with Server 3.5.2 2013-04-25 09:11:11 -04:00
Misagh Moayyed 089fca4ca4 Merge pull request #40 from mmoayyed/CASC-180
CASC-180: Fix the issue with casting to http url connections and provide...
2013-03-11 13:35:54 -07:00
Misagh Moayyed 4f79cd1014 CASC-180: Renamed factory to be HttpURLConnectionFactory. 2013-03-10 20:51:27 -07:00
Misagh Moayyed 2e6df8c5b7 CASC-180: Fixed try/catch block issue with URL creation. 2013-03-09 15:00:45 -07:00
Misagh Moayyed 3964e739c0 CASC-180: Removed the default url connection factory, allowed proxy retrieval to use the configured factory instance. 2013-03-06 09:34:39 -07:00
Misagh Moayyed c34ff785dd CASC-180: Fix the issue with casting to http url connections and provide a default instance for the http url factory. 2013-03-04 14:17:55 -07:00
Marvin S. Addison ad5525d2e5 Merge pull request #39 from serac/casc-204
CASC-204 Prevent renew misconfiguration.
2013-03-04 09:51:51 -08:00
Marvin S. Addison 6e12f43b16 CASC-204 Prevent renew misconfiguration.
Prevent renew from being configured via filter init param, which can lead
to a half-configured state where authentication filter is configured for
renew without validation filter. With this change in place, renew MUST be
configured by a global configuration facility such as context parameter or
JNDI to ensure proper configuration.
2013-03-04 10:43:55 -05:00
Misagh Moayyed 3063afc756 Merge pull request #36 from mmoayyed/CASC-180
CASC-180: Add support for Client Side Certificates
2013-03-03 09:13:14 -08:00
Scott Battaglia 974c3beb67 Merge branch 'master' of github.com:battags/java-cas-client 2013-02-17 21:31:55 -05:00
Misagh Moayyed d102c50779 CASC-180 - Add support for Client Side Certificates
Moved url connection factory interface and its https impl into the ssl package.
2013-01-24 15:47:22 -07:00
Misagh Moayyed d1ae0f5bbf Fixed javadoc for unused parameter. 2013-01-24 12:07:22 -07:00
Misagh Moayyed b54cd179e2 CASC-180 - Add support for Client Side Certificates
In order to utilize client side certificates, this commit facilitates the creation of a SSLSocketFactory on HttpsURLConnection for the client. The configuration is encapsulated inside a url factory instance that applies the adjustments where necessary.

This commit is continuation of the posted pending pull on github that is at:
https://github.com/Jasig/java-cas-client/pull/26

...and applies the suggestions and fixes that were brought to light during the code review.
2013-01-24 12:01:47 -07:00
Scott cd4dcc9fc9 Merge pull request #35 from battags/CASC-202
CASC-202 Migrate Commons Logging to SLF4J

Migrated to SLF4J, updated License header to match main CAS project, and re-ran script.
2013-01-15 19:06:54 -08:00
Scott Battaglia b4367f595e Fix formatting of pom.xml and update licensing to match CAS project. 2013-01-15 22:04:16 -05:00
Scott Battaglia 2f9d384b1e CASC-202
convert Commons Logging to SLF4J.  Add Enforcer.
2013-01-11 23:25:52 -05:00
Scott Battaglia 06ccec017d CASC-202
migration to SLF4J
2013-01-11 22:23:49 -05:00
Scott Battaglia 105bd17b61 Merge branch 'master' into CASC-202 2013-01-08 23:34:01 -05:00
Scott Battaglia f2df7a8603 CASC-202
migrated some to SLF4J
2013-01-08 23:32:35 -05:00
Scott d69e083f28 Merge pull request #34 from battags/CASC-179
CASC-179
2013-01-08 05:18:40 -08:00
Scott 7acd9adc4b Merge pull request #32 from battags/CASC-196
CASC-196
2013-01-08 05:17:09 -08:00
Scott c3ad115f5f Merge pull request #1 from katelme/patch-1
CASC-196
2013-01-08 04:40:18 -08:00
David Ordás eed831191a re-add support for multi-valued attributes
Add tests for ensure re-add support for multi-valued attributes is working
2013-01-08 13:28:35 +01:00
Scott Battaglia 67bb0a6ef8 CASC-196
re-add support for multi-valued attributes
2013-01-07 23:10:24 -05:00
Scott Battaglia e95d867792 Merge branch 'master' into CASC-196 2013-01-07 22:56:07 -05:00
Scott Battaglia 5af7c331b7 CASC-179
added parameter to determine whether to create sessions.  Also, now properly does a return.
2013-01-07 22:51:45 -05:00
Scott 27d89ccb30 Merge pull request #28 from battags/CASC-192
CASC-192
2013-01-07 06:22:28 -08:00
Scott f733760e68 Merge pull request #30 from battags/CASC-168
CASC-168
2013-01-07 05:02:05 -08:00
Scott 9294fbdffd Merge pull request #29 from battags/CASC-191
CASC-191
2013-01-07 05:01:51 -08:00
Scott c26329d21b Merge pull request #27 from battags/CASC-195
CASC-195
2013-01-06 21:02:08 -08:00
Scott d347f65bc6 Merge pull request #33 from battags/master
NOJIRA fix minor missing final tags and javadoc.
2013-01-06 20:58:03 -08:00
Scott Battaglia 82c0207c25 NOJIRA fix minor missing final tags and javadoc. 2013-01-06 23:56:24 -05:00
Scott Battaglia 980d0ff116 CASC-196
real XML parsing example if using <cas:attributes>.  Updated tests to make sure it works if there are line breaks.
2013-01-06 23:40:46 -05:00
Scott Battaglia ac8a134192 CASC-168
added ability to specify class name in order to use a sub-class.
2013-01-06 19:36:37 -05:00
Scott Battaglia 5ad57084cc CASC-191
isValid method with simple implementation
2013-01-06 18:45:05 -05:00
Scott Battaglia 41e7258af3 CASC-192
cast to XSAny in order to actually get the text content.
2013-01-06 18:24:11 -05:00
Scott Battaglia dcd9bda3df CASC-195
null check in ProxyGrantingTicketStorageImpl.
2013-01-06 18:14:42 -05:00
Scott fc1eaa1665 Merge pull request #24 from mmoayyed/CASC-199
CASC-199: Allow for an additional option to exclude empty proxy chains.
2012-12-29 13:54:01 -08:00
Misagh Moayyed 5f1a30a314 CASC-199: Allow for an additional option to exclude empty proxy chains. 2012-12-10 21:10:10 -07:00
Scott 010939de74 Merge pull request #23 from dodok1/master
properly support Confluence 3.5 - 4.3
2012-11-11 15:38:00 -08:00
Jozef Kotlar 68eb4aef23 minor change digged out of DefaultAuthenticator 2012-11-05 20:59:56 +01:00
Jozef Kotlar a754b40b30 implemented authentificator for Confluence 3.5 for newer Seraph/Crowd infrastructure
- using getUserFromSession()
- propagating event
- based on https://bitbucket.org/jaysee00/example-confluence-sso-authenticator
- based on comment from https://jira.atlassian.com/browse/CONF-26547
2012-10-30 14:28:35 +01:00
Scott a708d22469 Merge pull request #20 from ecki/topic-ignorebin
.gitignore Eclipse's .project default output bin/ directory.
2012-10-06 05:37:59 -07:00
Bernd Eckenfels caa2fccd32 .gitignore Eclipse's .project default output bin/ directory. 2012-10-04 04:53:41 +02:00
Marvin S. Addison bc6229b00e Merge pull request #18 from battags/CASC-188
CASC-188 Provide Support for Wildcard Roles
2012-09-21 06:51:16 -07:00
Scott Battaglia 008debf267 CAS-188
provide default Tomcat behavior
2012-09-20 22:20:48 -04:00
Scott afa83081a6 Merge pull request #16 from ecki/topic-redirectfix
make default value of useRedirect visible. Add some JavaDoc
2012-09-20 19:19:04 -07:00
Bernd Eckenfels 3deac9e1a9 Corrected JavaDoc (force if useSession=false force redirect=false) 2012-09-21 04:11:22 +02:00
Bernd Eckenfels 5f1e5e0ed4 make default value of useRedirect visible. Add some JavaDoc for the
options.
2012-09-21 01:32:06 +02:00
Scott bacf0c6142 Merge pull request #13 from serac/casc-166
CASC-166 Fix race condition in cached assertion cleanup.
2012-08-01 18:59:09 -07:00
Marvin S. Addison ee2b719098 CASC-166 Address code review feedback.
Use ConcurrentHashMap to avoid explicit synchronization.
Use TimeUnit to allow more user-friendly configuration of the units of the cache timeout (e.g. MINUTES, SECONDS) and rename option from cacheTimeoutUnits to cacheTimeoutUnit for consistency.
2012-07-26 10:25:06 -04:00
Marvin S. Addison ec0c7d5162 CASC-166 Fix race condition in cached assertion cleanup.
Perform assertion cleanup on same thread as JAAS module invocations to ensure that cleanup of expired assertions occurs before the cache is interrogated. A verifying test case accompanies this fix. The test case required a new module option, cacheTimeoutUnits, in order to complete on a time scale suitable for unit tests.
2012-07-25 16:58:36 -04:00
Misagh Moayyed b2f038a174 Merge pull request #12 from battags/CASC-185
CASC-185 - Merged.
2012-07-25 09:34:46 -07:00
Scott Battaglia bae8e68f55 CASC-185
add authentication time to assertion and also actually use the validity period for Assertion.
2012-07-24 23:01:35 -04:00
Scott 2b9cec59be Merge pull request #11 from battags/CASC-169
CASC-169
2012-07-24 19:40:31 -07:00
Scott Battaglia 3816e29861 CASC-169
change to hashmap to allow values to be added
2012-07-24 22:39:06 -04:00
Scott eadf300985 Merge pull request #9 from battags/CASC-184
CASC-184 - upgrade to OpenSAML2, update XML parsing to work with old and new server code.
2012-07-24 19:15:34 -07:00
Scott Battaglia 6e3f802cba CASC-184
improved SAML support.  Also execute old AND new XML in the unit tests.

cr for the first round of changes: serac
2012-07-24 22:13:25 -04:00
Scott Battaglia 616bbfa403 CASC-184
upgrade to OpenSAML2
2012-07-23 22:09:09 -04:00
Scott e10299896a Merge pull request #8 from mmoayyed/CASC-182-1
CASC-182 - reset the redirectAfterValidation parameter to false when use...
2012-07-11 10:14:33 -07:00
Misagh Moayyed 37b4058640 CASC-182: Combined logging statements into one. 2012-07-11 10:12:20 -07:00
Misagh Moayyed 09ffc2c05d CASC-182 - reset the redirectAfterValidation parameter to false when useSession is false. 2012-07-10 14:52:20 -07:00
Scott Battaglia d0ecca4274 CAS-172
don't log proxy message when there is no PGTIOU
2012-04-23 00:00:56 -04:00
Scott Battaglia eff195aaa9 CASC-171
check x-forwarded host header
2012-04-22 23:38:22 -04:00
unknown 7302ca6a99 CASC-175
ensure state can be shared
2012-04-22 23:29:38 -04:00
Scott 81e81256e0 Merge pull request #2 from lavrovdv/master
Parsing the custom attributes using xml dom parser.
2012-04-22 17:07:22 -07:00
Scott 8673f2c294 Merge pull request #5 from Gleeble/master
Change to allow for Session Fixation Prevention
2012-04-15 17:29:03 -07:00
Adam Swift 5f3700670c Changed to allow usage with systems using Session Fixation fixes following a login 2012-04-13 16:39:41 -04:00
Scott 1775ae99ec Merge pull request #4 from yzhengyu/master
CASC-164 Fix for Jasig CAS client for Java not working in 4.4 and above
2012-04-03 18:35:27 -07:00
Zhengyu Yong 0f9909406f Jira44CasAuthenticator will handle authentication for versions 4.4 and up 2012-04-02 18:07:37 +08:00
Zhengyu Yong 992a081434 added dependency to jira-core version 4.4 2012-04-02 18:05:48 +08:00
lavrovdv 88c69a7caa Merge branch 'master' of https://github.com/lavrovdv/java-cas-client
Conflicts:
	cas-client-core/src/main/java/org/jasig/cas/client/util/XmlUtils.java
	cas-client-core/src/main/java/org/jasig/cas/client/validation/Cas20ServiceTicketValidator.java
2012-03-15 11:09:09 +04:00
lavrovdv 4b454e1e2e Parsing the attributes using xml dom parser. 2012-03-15 11:04:47 +04:00
lavrovdv 78c6ac29f9 Parsing the attributes using xml dom parser. 2012-03-14 09:25:15 +04:00
lavrovdv 26e959c3d0 The result of parsing the xml document should not depend on the "\n" symbols. 2012-03-13 15:08:13 +04:00
Scott 7345e03a6f Merge pull request #1 from ZerothAngel/master
Tomcat integration: Store principal in session
2012-03-07 20:10:19 -08:00
Allan Saddi c4d63f74ca Also register the principal in the current session, if any. 2012-03-07 16:48:20 -08:00
Marvin S. Addison bbcd532924 Add gitignore file. 2012-03-07 09:49:56 -05:00
Marvin S. Addison de2ab6a3ad Update POM for GitHub and update other stale project information.
Reformat pom.xml for 2-space indentation.
2012-03-07 09:43:26 -05:00
Scott Battaglia a19c27f75b CASC-165
disable DTD reading.
2011-10-31 02:44:07 +00:00
Scott Battaglia 80693a3db9 CASC-157
added pre and post hooks
2011-09-22 02:02:03 +00:00
Scott Battaglia 477fc582f0 CASC-163
SSO filter supports ticket over POST.
2011-09-22 01:10:19 +00:00
Scott Battaglia 84aa06629f CASC-160
added a check to make sure we really wanted to gateway.
2011-09-22 00:55:15 +00:00
Scott Battaglia 5cd43c2139 CASC-101
additional protected getters
2011-09-12 04:12:37 +00:00
Scott Battaglia b1f623128c NOJIRA updated jasig parent 2011-09-11 18:24:29 +00:00
Scott Battaglia e56601db95 NOJIRA
disabled encryption test for now
2011-09-11 18:15:53 +00:00
Scott Battaglia 0d8c085d19 NOJIRA
enabled JBoss repo for now to get build working in Bamboo
2011-09-11 17:57:13 +00:00
Scott Battaglia 91046c779c NOJIRA
enabled JBoss repo for now to get build working in Bamboo
2011-09-11 17:13:56 +00:00
Scott Battaglia d754bc8d8c NOJIRA
ignore to get the CI to run.
2011-09-11 16:54:16 +00:00
Scott Battaglia fb42fefaf9 NOJIRA
fixed some bugs and updated pom to 3.3-SNAPSHOT
2011-09-11 16:46:53 +00:00
Scott Battaglia 97e6573e32 NOJIRA
accidental Java 1.6 dependency
2011-09-11 16:35:23 +00:00
Scott Battaglia e055585cf2 CASC-144
added support for multiple hosts with a space separated value
2011-09-11 16:15:30 +00:00
Scott Battaglia 3b6ccaac0a CASC-154
added method to AbstractCasFilter that can be overwritten in ticket validation and authentication to support other methods of retrieving the ticket.
2011-09-11 15:11:43 +00:00
Scott Battaglia 29165243a5 CASC-155
upgrade to Seraph 2.5 and attempt to fix class cast
2011-09-11 15:03:35 +00:00
Scott Battaglia 6a98fc61a5 CASC-156
call sendError
2011-07-31 19:01:17 +00:00
Scott Battaglia df6131ba7d CASC-151
added readme to explain the missing artifact issue.
2011-07-31 18:56:34 +00:00
Scott Battaglia 3d965426ac [maven-release-plugin] prepare for next development iteration 2011-07-10 23:44:18 +00:00
285 changed files with 20463 additions and 4124 deletions

20
.github/FUNDING.yml vendored Normal file
View File

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

11
.github/renovate.json vendored Normal file
View File

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

73
.github/stale.yml vendored Normal file
View File

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

12
.gitignore vendored Normal file
View File

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

44
.mergify.yml Normal file
View File

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

38
.travis.yml Normal file
View File

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

101
NOTICE Normal file
View File

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

1504
README.md Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,85 +1,84 @@
<!--
Licensed to Jasig under one or more contributor license
Licensed to Apereo 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,
Apereo licenses this file to you under the Apache License,
Version 2.0 (the "License"); you may not use this file
except in compliance with the License. You may obtain a
copy of the License at:
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
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
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->
<assembly>
<id>release</id>
<formats>
<format>zip</format>
<format>tar.gz</format>
</formats>
<includeBaseDirectory>true</includeBaseDirectory>
<fileSets>
<fileSet>
<lineEnding>unix</lineEnding>
<useDefaultExcludes>true</useDefaultExcludes>
<useStrictFiltering>false</useStrictFiltering>
<directory>${basedir}</directory>
<outputDirectory></outputDirectory>
<includes>
<include>*.xml</include>
<include>*.txt</include>
</includes>
</fileSet>
</fileSets>
<moduleSets>
<moduleSet>
<includes></includes>
<sources>
<fileSets>
<fileSet>
<directory>src</directory>
<outputDirectory>src</outputDirectory>
<lineEnding>unix</lineEnding>
<useDefaultExcludes>true</useDefaultExcludes>
</fileSet>
<id>release</id>
<formats>
<format>zip</format>
<format>tar.gz</format>
</formats>
<includeBaseDirectory>true</includeBaseDirectory>
<fileSets>
<fileSet>
<lineEnding>unix</lineEnding>
<useDefaultExcludes>true</useDefaultExcludes>
<useStrictFiltering>false</useStrictFiltering>
<directory>${basedir}</directory>
<outputDirectory></outputDirectory>
<includes>
<include>*.xml</include>
<include>*.txt</include>
</includes>
</fileSet>
</fileSets>
<moduleSets>
<moduleSet>
<includes></includes>
<sources>
<fileSets>
<fileSet>
<directory>src</directory>
<outputDirectory>src</outputDirectory>
<lineEnding>unix</lineEnding>
<useDefaultExcludes>true</useDefaultExcludes>
</fileSet>
<fileSet>
<lineEnding>unix</lineEnding>
<useDefaultExcludes>true</useDefaultExcludes>
<includes>
<include>*.xml</include>
</includes>
</fileSet>
<fileSet>
<lineEnding>unix</lineEnding>
<useDefaultExcludes>true</useDefaultExcludes>
<includes>
<include>*.xml</include>
</includes>
</fileSet>
<fileSet>
<lineEnding>unix</lineEnding>
<directory>target/site/apidocs/</directory>
<useDefaultExcludes>true</useDefaultExcludes>
<outputDirectory>docs</outputDirectory>
<includes>
<include>**/*</include>
</includes>
</fileSet>
</fileSets>
<fileSet>
<lineEnding>unix</lineEnding>
<directory>target/site/apidocs/</directory>
<useDefaultExcludes>true</useDefaultExcludes>
<outputDirectory>docs</outputDirectory>
<includes>
<include>**/*</include>
</includes>
</fileSet>
</fileSets>
<includeModuleDirectory>true</includeModuleDirectory>
<useDefaultExcludes>true</useDefaultExcludes>
</sources>
<binaries>
<outputDirectory>modules</outputDirectory>
<includeDependencies>true</includeDependencies>
<unpack>false</unpack>
<useDefaultExcludes>true</useDefaultExcludes>
<includes />
</binaries>
</moduleSet>
</moduleSets>
<includeModuleDirectory>true</includeModuleDirectory>
<useDefaultExcludes>true</useDefaultExcludes>
</sources>
<binaries>
<outputDirectory>modules</outputDirectory>
<includeDependencies>true</includeDependencies>
<unpack>false</unpack>
<useDefaultExcludes>true</useDefaultExcludes>
<includes/>
</binaries>
</moduleSet>
</moduleSets>
</assembly>

View File

@ -1,18 +1,18 @@
====
Licensed to Jasig under one or more contributor license
Licensed to Apereo 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,
Apereo licenses this file to you under the Apache License,
Version 2.0 (the "License"); you may not use this file
except in compliance with the License. You may obtain a
copy of the License at:
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
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
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.
====

42
cas-client-core/NOTICE Normal file
View File

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

View File

@ -1,74 +1,101 @@
<!--
Licensed to Apereo under one or more contributor license
agreements. See the NOTICE file distributed with this work
for additional information regarding copyright ownership.
Apereo licenses this file to you under the Apache License,
Version 2.0 (the "License"); you may not use this file
except in compliance with the License. You may obtain a
copy of the License at the following location:
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<parent>
<groupId>org.jasig.cas.client</groupId>
<version>3.2.1</version>
<version>3.6.2-SNAPSHOT</version>
<artifactId>cas-client</artifactId>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>org.jasig.cas.client</groupId>
<artifactId>cas-client-core</artifactId>
<packaging>jar</packaging>
<name>Jasig CAS Client for Java - Core</name>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.1.1</version>
<executions>
<execution>
<goals>
<goal>test-jar</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>xml-security</groupId>
<artifactId>xmlsec</artifactId>
<version>1.3.0</version>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.opensaml</groupId>
<artifactId>opensaml</artifactId>
<version>1.1</version>
<type>jar</type>
<scope>provided</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.4</version>
<type>jar</type>
<groupId>xml-security</groupId>
<artifactId>xmlsec</artifactId>
<version>1.3.0</version>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${spring.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${spring.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<scope>test</scope>
<version>1.2.15</version>
<version>1.2.17</version>
<exclusions>
<exclusion>
<artifactId>jmxri</artifactId>
@ -86,7 +113,4 @@
</dependency>
</dependencies>
<properties>
<spring.version>2.5.6.SEC01</spring.version>
</properties>
</project>

View File

@ -0,0 +1,51 @@
/**
* Licensed to Apereo under one or more contributor license
* agreements. See the NOTICE file distributed with this work
* for additional information regarding copyright ownership.
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at the following location:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jasig.cas.client;
/**
* Simple enumeration to hold/capture some of the standard request parameters used by the various protocols.
*
* @author Scott Battaglia
* @since 3.4.0
*/
public enum Protocol {
CAS1("ticket", "service"), CAS2(CAS1), CAS3(CAS2), SAML11("SAMLart", "TARGET");
private final String artifactParameterName;
private final String serviceParameterName;
private Protocol(final String artifactParameterName, final String serviceParameterName) {
this.artifactParameterName = artifactParameterName;
this.serviceParameterName = serviceParameterName;
}
private Protocol(final Protocol protocol) {
this(protocol.getArtifactParameterName(), protocol.getServiceParameterName());
}
public String getArtifactParameterName() {
return this.artifactParameterName;
}
public String getServiceParameterName() {
return this.serviceParameterName;
}
}

View File

@ -1,22 +1,21 @@
/**
* Licensed to Jasig under one or more contributor license
* Licensed to Apereo 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,
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at:
* 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
* 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
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jasig.cas.client.authentication;
import java.io.Serializable;
@ -48,6 +47,6 @@ public interface AttributePrincipal extends Principal, Serializable {
* The Map of key/value pairs associated with this principal.
* @return the map of key/value pairs associated with this principal.
*/
Map<String,Object> getAttributes();
Map<String, Object> getAttributes();
}

View File

@ -1,48 +1,45 @@
/**
* Licensed to Jasig under one or more contributor license
* Licensed to Apereo 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,
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at:
* 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
* 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
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jasig.cas.client.authentication;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jasig.cas.client.proxy.ProxyRetriever;
import org.jasig.cas.client.util.CommonUtils;
import java.util.Collections;
import java.util.Map;
import org.jasig.cas.client.proxy.ProxyRetriever;
import org.jasig.cas.client.util.CommonUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Concrete implementation of the AttributePrincipal interface.
*
* @author Scott Battaglia
* @version $Revision$ $Date$
* @since 3.1
*/
public class AttributePrincipalImpl extends SimplePrincipal implements AttributePrincipal {
private static final Log LOG = LogFactory.getLog(AttributePrincipalImpl.class);
private static final Logger LOGGER = LoggerFactory.getLogger(AttributePrincipalImpl.class);
/** Unique Id for Serialization */
private static final long serialVersionUID = -1443182634624927187L;
/** Map of key/value pairs about this principal. */
private final Map<String,Object> attributes;
private final Map<String, Object> attributes;
/** The CAS 2 ticket used to retrieve a proxy ticket. */
private final String proxyGrantingTicket;
@ -56,7 +53,7 @@ public class AttributePrincipalImpl extends SimplePrincipal implements Attribute
* @param name the unique identifier for the principal.
*/
public AttributePrincipalImpl(final String name) {
this(name, Collections.<String, Object>emptyMap());
this(name, Collections.<String, Object> emptyMap());
}
/**
@ -65,8 +62,8 @@ public class AttributePrincipalImpl extends SimplePrincipal implements Attribute
* @param name the unique identifier for the principal.
* @param attributes the key/value pairs for this principal.
*/
public AttributePrincipalImpl(final String name, final Map<String,Object> attributes) {
this(name, attributes, null, null);
public AttributePrincipalImpl(final String name, final Map<String, Object> attributes) {
this(name, attributes, null, null);
}
/**
@ -76,19 +73,21 @@ public class AttributePrincipalImpl extends SimplePrincipal implements Attribute
* @param proxyGrantingTicket the ticket associated with this principal.
* @param proxyRetriever the ProxyRetriever implementation to call back to the CAS server.
*/
public AttributePrincipalImpl(final String name, final String proxyGrantingTicket, final ProxyRetriever proxyRetriever) {
this(name, Collections.<String, Object>emptyMap(), proxyGrantingTicket, proxyRetriever);
public AttributePrincipalImpl(final String name, final String proxyGrantingTicket,
final ProxyRetriever proxyRetriever) {
this(name, Collections.<String, Object> emptyMap(), proxyGrantingTicket, proxyRetriever);
}
/**
* Constructs a new principal witht he supplied name, attributes, and proxying capabilities.
* Constructs a new principal with the supplied name, attributes, and proxying capabilities.
*
* @param name the unique identifier for the principal.
* @param attributes the key/value pairs for this principal.
* @param proxyGrantingTicket the ticket associated with this principal.
* @param proxyRetriever the ProxyRetriever implementation to call back to the CAS server.
*/
public AttributePrincipalImpl(final String name, final Map<String,Object> attributes, final String proxyGrantingTicket, final ProxyRetriever proxyRetriever) {
public AttributePrincipalImpl(final String name, final Map<String, Object> attributes,
final String proxyGrantingTicket, final ProxyRetriever proxyRetriever) {
super(name);
this.attributes = attributes;
this.proxyGrantingTicket = proxyGrantingTicket;
@ -97,16 +96,18 @@ public class AttributePrincipalImpl extends SimplePrincipal implements Attribute
CommonUtils.assertNotNull(this.attributes, "attributes cannot be null.");
}
public Map<String,Object> getAttributes() {
@Override
public Map<String, Object> getAttributes() {
return this.attributes;
}
public String getProxyTicketFor(String service) {
@Override
public String getProxyTicketFor(final String service) {
if (proxyGrantingTicket != null) {
return this.proxyRetriever.getProxyTicketIdFor(this.proxyGrantingTicket, service);
}
LOG.debug("No ProxyGrantingTicket was supplied, so no Proxy Ticket can be retrieved.");
LOGGER.debug("No ProxyGrantingTicket was supplied, so no Proxy Ticket can be retrieved.");
return null;
}
}

View File

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

View File

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

View File

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

View File

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

View File

@ -1,47 +1,45 @@
/**
* Licensed to Jasig under one or more contributor license
* Licensed to Apereo 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,
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at:
* 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
* 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
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jasig.cas.client.authentication;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
public final class DefaultGatewayResolverImpl implements GatewayResolver {
public static final String CONST_CAS_GATEWAY = "_const_cas_gateway_";
public boolean hasGatewayedAlready(final HttpServletRequest request,
final String serviceUrl) {
final HttpSession session = request.getSession(false);
if (session == null) {
return false;
}
final boolean result = session.getAttribute(CONST_CAS_GATEWAY) != null;
session.removeAttribute(CONST_CAS_GATEWAY);
return result;
}
@Override
public boolean hasGatewayedAlready(final HttpServletRequest request, final String serviceUrl) {
final HttpSession session = request.getSession(false);
public String storeGatewayInformation(final HttpServletRequest request,
final String serviceUrl) {
request.getSession(true).setAttribute(CONST_CAS_GATEWAY, "yes");
return serviceUrl;
}
if (session == null) {
return false;
}
final boolean result = session.getAttribute(CONST_CAS_GATEWAY) != null;
return result;
}
@Override
public String storeGatewayInformation(final HttpServletRequest request, final String serviceUrl) {
request.getSession(true).setAttribute(CONST_CAS_GATEWAY, "yes");
return serviceUrl;
}
}

View File

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

View File

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

View File

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

View File

@ -1,22 +1,21 @@
/**
* Licensed to Jasig under one or more contributor license
* Licensed to Apereo 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,
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at:
* 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
* 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
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jasig.cas.client.authentication;
import javax.servlet.http.HttpServletRequest;
@ -32,21 +31,21 @@ import javax.servlet.http.HttpServletRequest;
*/
public interface GatewayResolver {
/**
* Determines if the request has been gatewayed already. Should also do gateway clean up.
*
* @param request the Http Servlet Request
* @param serviceUrl the service url
* @return true if yes, false otherwise.
*/
boolean hasGatewayedAlready(HttpServletRequest request, String serviceUrl);
/**
* Storage the request for gatewaying and return the service url, which can be modified.
*
* @param request the HttpServletRequest.
* @param serviceUrl the service url
* @return the potentially modified service url to redirect to
*/
String storeGatewayInformation(HttpServletRequest request, String serviceUrl);
/**
* Determines if the request has been gatewayed already. Should also do gateway clean up.
*
* @param request the Http Servlet Request
* @param serviceUrl the service url
* @return true if yes, false otherwise.
*/
boolean hasGatewayedAlready(HttpServletRequest request, String serviceUrl);
/**
* Storage the request for gatewaying and return the service url, which can be modified.
*
* @param request the HttpServletRequest.
* @param serviceUrl the service url
* @return the potentially modified service url to redirect to
*/
String storeGatewayInformation(HttpServletRequest request, String serviceUrl);
}

View File

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

View File

@ -1,45 +0,0 @@
/**
* Licensed to Jasig under one or more contributor license
* agreements. See the NOTICE file distributed with this work
* for additional information regarding copyright ownership.
* Jasig licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jasig.cas.client.authentication;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
/**
* Extension to the default Authentication filter that sets the required SAML1.1 artifact parameter name and service parameter name.
* <p>
* Note, the "final" on this class helps ensure the compliance required in the initInternal method.
*
* @author Scott Battaglia
* @since 3.1.12
* @version $Revision$ $Date$
*/
public final class Saml11AuthenticationFilter extends AuthenticationFilter {
protected void initInternal(final FilterConfig filterConfig) throws ServletException {
super.initInternal(filterConfig);
log.warn("SAML1.1 compliance requires the [artifactParameterName] and [serviceParameterName] to be set to specified values.");
log.warn("This filter will overwrite any user-provided values (if any are provided)");
setArtifactParameterName("SAMLart");
setServiceParameterName("TARGET");
}
}

View File

@ -1,22 +1,21 @@
/**
* Licensed to Jasig under one or more contributor license
* Licensed to Apereo 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,
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at:
* 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
* 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
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jasig.cas.client.authentication;
import java.security.Principal;
@ -50,22 +49,26 @@ public final class SimpleGroup extends SimplePrincipal implements Group {
super(name);
}
@Override
public boolean addMember(final Principal user) {
return this.members.add(user);
}
@Override
public boolean isMember(final Principal member) {
return this.members.contains(member);
}
@Override
public Enumeration<? extends Principal> members() {
return Collections.enumeration(this.members);
}
@Override
public boolean removeMember(final Principal user) {
return this.members.remove(user);
}
public String toString() {
return super.toString() + ": " + members.toString();
}

View File

@ -1,27 +1,25 @@
/**
* Licensed to Jasig under one or more contributor license
* Licensed to Apereo 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,
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at:
* 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
* 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
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jasig.cas.client.authentication;
import java.io.Serializable;
import java.security.Principal;
import org.jasig.cas.client.util.CommonUtils;
/**
@ -49,6 +47,7 @@ public class SimplePrincipal implements Principal, Serializable {
CommonUtils.assertNotNull(this.name, "name cannot be null.");
}
@Override
public final String getName() {
return this.name;
}
@ -63,7 +62,7 @@ public class SimplePrincipal implements Principal, Serializable {
} else if (!(o instanceof SimplePrincipal)) {
return false;
} else {
return getName().equals(((SimplePrincipal)o).getName());
return getName().equals(((SimplePrincipal) o).getName());
}
}

View File

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

View File

@ -0,0 +1,121 @@
/**
* Licensed to Apereo under one or more contributor license
* agreements. See the NOTICE file distributed with this work
* for additional information regarding copyright ownership.
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at the following location:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jasig.cas.client.configuration;
import org.jasig.cas.client.util.CommonUtils;
import org.jasig.cas.client.util.ReflectUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Base class to provide most of the boiler-plate code (i.e. checking for proper values, returning defaults, etc.
*
* @author Scott Battaglia
* @since 3.4.0
*/
public abstract class BaseConfigurationStrategy implements ConfigurationStrategy {
protected final Logger logger = LoggerFactory.getLogger(getClass());
@Override
public final boolean getBoolean(final ConfigurationKey<Boolean> configurationKey) {
return getValue(configurationKey, new Parser<Boolean>() {
@Override
public Boolean parse(final String value) {
return CommonUtils.toBoolean(value);
}
});
}
@Override
public final long getLong(final ConfigurationKey<Long> configurationKey) {
return getValue(configurationKey, new Parser<Long>() {
@Override
public Long parse(final String value) {
return CommonUtils.toLong(value, configurationKey.getDefaultValue());
}
});
}
@Override
public final int getInt(final ConfigurationKey<Integer> configurationKey) {
return getValue(configurationKey, new Parser<Integer>() {
@Override
public Integer parse(final String value) {
return CommonUtils.toInt(value, configurationKey.getDefaultValue());
}
});
}
@Override
public final String getString(final ConfigurationKey<String> configurationKey) {
return getValue(configurationKey, new Parser<String>() {
@Override
public String parse(final String value) {
return value;
}
});
}
@Override
public <T> Class<? extends T> getClass(final ConfigurationKey<Class<? extends T>> configurationKey) {
return getValue(configurationKey, new Parser<Class<? extends T>>() {
@Override
public Class<? extends T> parse(final String value) {
try {
return ReflectUtils.loadClass(value);
} catch (final IllegalArgumentException e) {
return configurationKey.getDefaultValue();
}
}
});
}
private <T> T getValue(final ConfigurationKey<T> configurationKey, final Parser<T> parser) {
final String value = getWithCheck(configurationKey);
if (CommonUtils.isBlank(value)) {
logger.trace("No value found for property {}, returning default {}", configurationKey.getName(), configurationKey.getDefaultValue());
return configurationKey.getDefaultValue();
} else {
logger.trace("Loaded property {} with value {}", configurationKey.getName(), configurationKey.getDefaultValue());
}
return parser.parse(value);
}
private String getWithCheck(final ConfigurationKey configurationKey) {
CommonUtils.assertNotNull(configurationKey, "configurationKey cannot be null");
return get(configurationKey);
}
/**
* Retrieve the String value for this key. Returns null if there is no value.
*
* @param configurationKey the key to retrieve. MUST NOT BE NULL.
* @return the String if its found, null otherwise.
*/
protected abstract String get(ConfigurationKey configurationKey);
private interface Parser<T> {
T parse(String value);
}
}

View File

@ -0,0 +1,68 @@
/**
* Licensed to Apereo under one or more contributor license
* agreements. See the NOTICE file distributed with this work
* for additional information regarding copyright ownership.
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at the following location:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jasig.cas.client.configuration;
import org.jasig.cas.client.util.CommonUtils;
/**
* Holder class to represent a particular configuration key and its optional default value.
*
* @author Scott Battaglia
* @since 3.4.0
*/
public final class ConfigurationKey<E> {
private final String name;
private final E defaultValue;
public ConfigurationKey(final String name) {
this(name, null);
}
public ConfigurationKey(final String name, final E defaultValue) {
CommonUtils.assertNotNull(name, "name must not be null.");
this.name = name;
this.defaultValue = defaultValue;
}
/**
* The referencing name of the configuration key (i.e. what you would use to look it up in your configuration strategy)
*
* @return the name. MUST NOT BE NULL.
*/
public String getName() {
return this.name;
}
/**
* The (optional) default value to use when this configuration key is not set. If a value is provided it should be used. A <code>null</code> value indicates that there is no default.
*
* @return the default value or null.
*/
public E getDefaultValue() {
return this.defaultValue;
}
@Override
public String toString() {
return getName();
}
}

View File

@ -0,0 +1,86 @@
/**
* Licensed to Apereo under one or more contributor license
* agreements. See the NOTICE file distributed with this work
* for additional information regarding copyright ownership.
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at the following location:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jasig.cas.client.configuration;
import org.jasig.cas.client.Protocol;
import org.jasig.cas.client.authentication.AuthenticationRedirectStrategy;
import org.jasig.cas.client.authentication.DefaultGatewayResolverImpl;
import org.jasig.cas.client.authentication.GatewayResolver;
import org.jasig.cas.client.proxy.ProxyGrantingTicketStorage;
import org.jasig.cas.client.proxy.ProxyGrantingTicketStorageImpl;
import org.jasig.cas.client.validation.Cas20ServiceTicketValidator;
import javax.net.ssl.HostnameVerifier;
/**
* Holder interface for all known configuration keys.
*
* @author Scott Battaglia
* @since 3.4.0
*/
public interface ConfigurationKeys {
ConfigurationKey<String> ARTIFACT_PARAMETER_NAME = new ConfigurationKey<String>("artifactParameterName", Protocol.CAS2.getArtifactParameterName());
ConfigurationKey<String> SERVER_NAME = new ConfigurationKey<String>("serverName", null);
ConfigurationKey<String> SERVICE = new ConfigurationKey<String>("service");
ConfigurationKey<Boolean> RENEW = new ConfigurationKey<Boolean>("renew", Boolean.FALSE);
ConfigurationKey<String> LOGOUT_PARAMETER_NAME = new ConfigurationKey<String>("logoutParameterName", "logoutRequest");
ConfigurationKey<Boolean> ARTIFACT_PARAMETER_OVER_POST = new ConfigurationKey<Boolean>("artifactParameterOverPost", Boolean.FALSE);
ConfigurationKey<Boolean> EAGERLY_CREATE_SESSIONS = new ConfigurationKey<Boolean>("eagerlyCreateSessions", Boolean.TRUE);
ConfigurationKey<Boolean> ENCODE_SERVICE_URL = new ConfigurationKey<Boolean>("encodeServiceUrl", Boolean.TRUE);
ConfigurationKey<String> SSL_CONFIG_FILE = new ConfigurationKey<String>("sslConfigFile", null);
ConfigurationKey<String> ROLE_ATTRIBUTE = new ConfigurationKey<String>("roleAttribute", null);
ConfigurationKey<Boolean> IGNORE_CASE = new ConfigurationKey<Boolean>("ignoreCase", Boolean.FALSE);
ConfigurationKey<String> CAS_SERVER_LOGIN_URL = new ConfigurationKey<String>("casServerLoginUrl", null);
ConfigurationKey<Boolean> GATEWAY = new ConfigurationKey<Boolean>("gateway", Boolean.FALSE);
ConfigurationKey<String> METHOD = new ConfigurationKey<String>("method", null);
ConfigurationKey<Class<? extends AuthenticationRedirectStrategy>> AUTHENTICATION_REDIRECT_STRATEGY_CLASS = new ConfigurationKey<Class<? extends AuthenticationRedirectStrategy>>("authenticationRedirectStrategyClass", null);
ConfigurationKey<Class<? extends GatewayResolver>> GATEWAY_STORAGE_CLASS = new ConfigurationKey<Class<? extends GatewayResolver>>("gatewayStorageClass", DefaultGatewayResolverImpl.class);
ConfigurationKey<String> CAS_SERVER_URL_PREFIX = new ConfigurationKey<String>("casServerUrlPrefix", null);
ConfigurationKey<String> ENCODING = new ConfigurationKey<String>("encoding", null);
ConfigurationKey<Long> TOLERANCE = new ConfigurationKey<Long>("tolerance", 1000L);
ConfigurationKey<String> PRIVATE_KEY_PATH = new ConfigurationKey<String>("privateKeyPath", null);
ConfigurationKey<String> PRIVATE_KEY_ALGORITHM = new ConfigurationKey<String>("privateKeyAlgorithm", "RSA");
/**
* @deprecated As of 3.4. This constant is not used by the client and will
* be removed in future versions.
*/
@Deprecated
ConfigurationKey<Boolean> DISABLE_XML_SCHEMA_VALIDATION = new ConfigurationKey<Boolean>("disableXmlSchemaValidation", Boolean.FALSE);
ConfigurationKey<String> INTERNAL_IP = new ConfigurationKey<String>("internalIp", null);
ConfigurationKey<String> IGNORE_PATTERN = new ConfigurationKey<String>("ignorePattern", null);
ConfigurationKey<String> IGNORE_URL_PATTERN_TYPE = new ConfigurationKey<String>("ignoreUrlPatternType", "REGEX");
ConfigurationKey<Class<? extends HostnameVerifier>> HOSTNAME_VERIFIER = new ConfigurationKey<Class<? extends HostnameVerifier>>("hostnameVerifier", null);
ConfigurationKey<String> HOSTNAME_VERIFIER_CONFIG = new ConfigurationKey<String>("hostnameVerifierConfig", null);
ConfigurationKey<Boolean> EXCEPTION_ON_VALIDATION_FAILURE = new ConfigurationKey<Boolean>("exceptionOnValidationFailure", Boolean.TRUE);
ConfigurationKey<Boolean> REDIRECT_AFTER_VALIDATION = new ConfigurationKey<Boolean>("redirectAfterValidation", Boolean.TRUE);
ConfigurationKey<Boolean> USE_SESSION = new ConfigurationKey<Boolean>("useSession", Boolean.TRUE);
ConfigurationKey<String> SECRET_KEY = new ConfigurationKey<String>("secretKey", null);
ConfigurationKey<String> CIPHER_ALGORITHM = new ConfigurationKey<String>("cipherAlgorithm", "DESede");
ConfigurationKey<String> PROXY_RECEPTOR_URL = new ConfigurationKey<String>("proxyReceptorUrl", null);
ConfigurationKey<Class<? extends ProxyGrantingTicketStorage>> PROXY_GRANTING_TICKET_STORAGE_CLASS = new ConfigurationKey<Class<? extends ProxyGrantingTicketStorage>>("proxyGrantingTicketStorageClass", ProxyGrantingTicketStorageImpl.class);
ConfigurationKey<Integer> MILLIS_BETWEEN_CLEAN_UPS = new ConfigurationKey<Integer>("millisBetweenCleanUps", 60000);
ConfigurationKey<Boolean> ACCEPT_ANY_PROXY = new ConfigurationKey<Boolean>("acceptAnyProxy", Boolean.FALSE);
ConfigurationKey<String> ALLOWED_PROXY_CHAINS = new ConfigurationKey<String>("allowedProxyChains", null);
ConfigurationKey<Class<? extends Cas20ServiceTicketValidator>> TICKET_VALIDATOR_CLASS = new ConfigurationKey<Class<? extends Cas20ServiceTicketValidator>>("ticketValidatorClass", null);
ConfigurationKey<String> PROXY_CALLBACK_URL = new ConfigurationKey<String>("proxyCallbackUrl", null);
ConfigurationKey<String> RELAY_STATE_PARAMETER_NAME = new ConfigurationKey<String>("relayStateParameterName", "RelayState");
ConfigurationKey<String> LOGOUT_CALLBACK_PATH = new ConfigurationKey<String>("logoutCallbackPath", null);
}

View File

@ -0,0 +1,79 @@
/**
* Licensed to Apereo under one or more contributor license
* agreements. See the NOTICE file distributed with this work
* for additional information regarding copyright ownership.
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at the following location:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jasig.cas.client.configuration;
import javax.servlet.Filter;
import javax.servlet.FilterConfig;
/**
* Abstraction to allow for pluggable methods for retrieving filter configuration.
*
* @author Scott Battaglia
* @since 3.4.0
*/
public interface ConfigurationStrategy {
/**
* Retrieves the value for the provided {@param configurationKey}, falling back to the {@param configurationKey}'s {@link ConfigurationKey#getDefaultValue()} if nothing can be found.
*
* @param configurationKey the configuration key. MUST NOT BE NULL.
* @return the configured value, or the default value.
*/
boolean getBoolean(ConfigurationKey<Boolean> configurationKey);
/**
* Retrieves the value for the provided {@param configurationKey}, falling back to the {@param configurationKey}'s {@link ConfigurationKey#getDefaultValue()} if nothing can be found.
*
* @param configurationKey the configuration key. MUST NOT BE NULL.
* @return the configured value, or the default value.
*/
String getString(ConfigurationKey<String> configurationKey);
/**
* Retrieves the value for the provided {@param configurationKey}, falling back to the {@param configurationKey}'s {@link ConfigurationKey#getDefaultValue()} if nothing can be found.
*
* @param configurationKey the configuration key. MUST NOT BE NULL.
* @return the configured value, or the default value.
*/
long getLong(ConfigurationKey<Long> configurationKey);
/**
* Retrieves the value for the provided {@param configurationKey}, falling back to the {@param configurationKey}'s {@link ConfigurationKey#getDefaultValue()} if nothing can be found.
*
* @param configurationKey the configuration key. MUST NOT BE NULL.
* @return the configured value, or the default value.
*/
int getInt(ConfigurationKey<Integer> configurationKey);
/**
* Retrieves the value for the provided {@param configurationKey}, falling back to the {@param configurationKey}'s {@link ConfigurationKey#getDefaultValue()} if nothing can be found.
*
* @param configurationKey the configuration key. MUST NOT BE NULL.
* @return the configured value, or the default value.
*/
<T> Class<? extends T> getClass(ConfigurationKey<Class<? extends T>> configurationKey);
/**
* Initializes the strategy. This must be called before calling any of the "get" methods.
*
* @param filterConfig the filter configuration object.
* @param filterClazz the filter
*/
void init(FilterConfig filterConfig, Class<? extends Filter> filterClazz);
}

View File

@ -0,0 +1,74 @@
/**
* Licensed to Apereo under one or more contributor license
* agreements. See the NOTICE file distributed with this work
* for additional information regarding copyright ownership.
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at the following location:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jasig.cas.client.configuration;
import org.jasig.cas.client.util.CommonUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Enumeration to map simple names to the underlying classes so that deployers can reference the simple name in the
* <code>web.xml</code> instead of the fully qualified class name.
*
* @author Scott Battaglia
* @since 3.4.0
*/
public enum ConfigurationStrategyName {
DEFAULT(LegacyConfigurationStrategyImpl.class), JNDI(JndiConfigurationStrategyImpl.class), WEB_XML(WebXmlConfigurationStrategyImpl.class),
PROPERTY_FILE(PropertiesConfigurationStrategyImpl.class), SYSTEM_PROPERTIES(SystemPropertiesConfigurationStrategyImpl.class);
private static final Logger LOGGER = LoggerFactory.getLogger(ConfigurationStrategyName.class);
private final Class<? extends ConfigurationStrategy> configurationStrategyClass;
private ConfigurationStrategyName(final Class<? extends ConfigurationStrategy> configurationStrategyClass) {
this.configurationStrategyClass = configurationStrategyClass;
}
/**
* Static helper method that will resolve a simple string to either an enum value or a {@link org.jasig.cas.client.configuration.ConfigurationStrategy} class.
*
* @param value the value to attempt to resolve.
* @return the underlying class that this maps to (either via simple name or fully qualified class name).
*/
public static Class<? extends ConfigurationStrategy> resolveToConfigurationStrategy(final String value) {
if (CommonUtils.isBlank(value)) {
return DEFAULT.configurationStrategyClass;
}
for (final ConfigurationStrategyName csn : values()) {
if (csn.name().equalsIgnoreCase(value)) {
return csn.configurationStrategyClass;
}
}
try {
final Class<?> clazz = Class.forName(value);
if (ConfigurationStrategy.class.isAssignableFrom(clazz)) {
return (Class<? extends ConfigurationStrategy>) clazz;
}
} catch (final ClassNotFoundException e) {
LOGGER.error("Unable to locate strategy {} by name or class name. Using default strategy instead.", value, e);
}
return DEFAULT.configurationStrategyClass;
}
}

View File

@ -0,0 +1,94 @@
/**
* Licensed to Apereo under one or more contributor license
* agreements. See the NOTICE file distributed with this work
* for additional information regarding copyright ownership.
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at the following location:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jasig.cas.client.configuration;
import org.jasig.cas.client.util.CommonUtils;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.servlet.Filter;
import javax.servlet.FilterConfig;
/**
* Loads configuration information from JNDI, using the <code>defaultValue</code> if it can't.
*
* @author Scott Battaglia
* @since 3.4.0
*/
public class JndiConfigurationStrategyImpl extends BaseConfigurationStrategy {
private static final String ENVIRONMENT_PREFIX = "java:comp/env/cas/";
private final String environmentPrefix;
private InitialContext context;
private String simpleFilterName;
public JndiConfigurationStrategyImpl() {
this(ENVIRONMENT_PREFIX);
}
public JndiConfigurationStrategyImpl(final String environmentPrefix) {
this.environmentPrefix = environmentPrefix;
}
@Override
protected final String get(final ConfigurationKey configurationKey) {
if (context == null) {
return null;
}
final String propertyName = configurationKey.getName();
final String filterValue = loadFromContext(context, this.environmentPrefix + this.simpleFilterName + "/" + propertyName);
if (CommonUtils.isNotBlank(filterValue)) {
logger.info("Property [{}] loaded from JNDI Filter Specific Property with value [{}]", propertyName, filterValue);
return filterValue;
}
final String rootValue = loadFromContext(context, this.environmentPrefix + propertyName);
if (CommonUtils.isNotBlank(rootValue)) {
logger.info("Property [{}] loaded from JNDI with value [{}]", propertyName, rootValue);
return rootValue;
}
return null;
}
private String loadFromContext(final InitialContext context, final String path) {
try {
return (String) context.lookup(path);
} catch (final NamingException e) {
return null;
}
}
@Override
public final void init(final FilterConfig filterConfig, final Class<? extends Filter> clazz) {
this.simpleFilterName = clazz.getSimpleName();
try {
this.context = new InitialContext();
} catch (final NamingException e) {
logger.error("Unable to create InitialContext. No properties can be loaded via JNDI.", e);
}
}
}

View File

@ -0,0 +1,55 @@
/**
* Licensed to Apereo under one or more contributor license
* agreements. See the NOTICE file distributed with this work
* for additional information regarding copyright ownership.
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at the following location:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jasig.cas.client.configuration;
import org.jasig.cas.client.util.CommonUtils;
import javax.servlet.Filter;
import javax.servlet.FilterConfig;
/**
* Replicates the original behavior by checking the {@link org.jasig.cas.client.configuration.WebXmlConfigurationStrategyImpl} first, and then
* the {@link org.jasig.cas.client.configuration.JndiConfigurationStrategyImpl} before using the <code>defaultValue</code>.
*
* @author Scott Battaglia
* @since 3.4.0
*/
public final class LegacyConfigurationStrategyImpl extends BaseConfigurationStrategy {
private final WebXmlConfigurationStrategyImpl webXmlConfigurationStrategy = new WebXmlConfigurationStrategyImpl();
private final JndiConfigurationStrategyImpl jndiConfigurationStrategy = new JndiConfigurationStrategyImpl();
@Override
public void init(final FilterConfig filterConfig, final Class<? extends Filter> filterClazz) {
this.webXmlConfigurationStrategy.init(filterConfig, filterClazz);
this.jndiConfigurationStrategy.init(filterConfig, filterClazz);
}
@Override
protected String get(final ConfigurationKey key) {
final String value1 = this.webXmlConfigurationStrategy.get(key);
if (CommonUtils.isNotBlank(value1)) {
return value1;
}
return this.jndiConfigurationStrategy.get(key);
}
}

View File

@ -0,0 +1,101 @@
/**
* Licensed to Apereo under one or more contributor license
* agreements. See the NOTICE file distributed with this work
* for additional information regarding copyright ownership.
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at the following location:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jasig.cas.client.configuration;
import org.jasig.cas.client.util.CommonUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.servlet.Filter;
import javax.servlet.FilterConfig;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Properties;
/**
* @author Scott Battaglia
* @since 3.4.0
*/
public final class PropertiesConfigurationStrategyImpl extends BaseConfigurationStrategy {
/**
* Property name we'll use in the {@link javax.servlet.FilterConfig} and {@link javax.servlet.ServletConfig} to try and find where
* you stored the configuration file.
*/
private static final String CONFIGURATION_FILE_LOCATION = "configFileLocation";
/**
* Default location of the configuration file. Mostly for testing/demo. You will most likely want to configure an alternative location.
*/
private static final String DEFAULT_CONFIGURATION_FILE_LOCATION = "/etc/java-cas-client.properties";
private static final Logger LOGGER = LoggerFactory.getLogger(PropertiesConfigurationStrategyImpl.class);
private String simpleFilterName;
private final Properties properties = new Properties();
@Override
protected String get(final ConfigurationKey configurationKey) {
final String property = configurationKey.getName();
final String filterSpecificProperty = this.simpleFilterName + "." + property;
final String filterSpecificValue = this.properties.getProperty(filterSpecificProperty);
if (CommonUtils.isNotEmpty(filterSpecificValue)) {
return filterSpecificValue;
}
return this.properties.getProperty(property);
}
@Override
public void init(final FilterConfig filterConfig, final Class<? extends Filter> filterClazz) {
this.simpleFilterName = filterClazz.getSimpleName();
final String fileLocationFromFilterConfig = filterConfig.getInitParameter(CONFIGURATION_FILE_LOCATION);
final boolean filterConfigFileLoad = loadPropertiesFromFile(fileLocationFromFilterConfig);
if (!filterConfigFileLoad) {
final String fileLocationFromServletConfig = filterConfig.getServletContext().getInitParameter(CONFIGURATION_FILE_LOCATION);
final boolean servletContextFileLoad = loadPropertiesFromFile(fileLocationFromServletConfig);
if (!servletContextFileLoad) {
final boolean defaultConfigFileLoaded = loadPropertiesFromFile(DEFAULT_CONFIGURATION_FILE_LOCATION);
CommonUtils.assertTrue(defaultConfigFileLoaded, "unable to load properties to configure CAS client");
}
}
}
private boolean loadPropertiesFromFile(final String file) {
if (CommonUtils.isEmpty(file)) {
return false;
}
FileInputStream fis = null;
try {
fis = new FileInputStream(file);
this.properties.load(fis);
return true;
} catch (final IOException e) {
LOGGER.warn("Unable to load properties for file {}", file, e);
return false;
} finally {
CommonUtils.closeQuietly(fis);
}
}
}

View File

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

View File

@ -0,0 +1,62 @@
/**
* Licensed to Apereo under one or more contributor license
* agreements. See the NOTICE file distributed with this work
* for additional information regarding copyright ownership.
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at the following location:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jasig.cas.client.configuration;
import org.jasig.cas.client.util.CommonUtils;
import javax.servlet.Filter;
import javax.servlet.FilterConfig;
/**
* Implementation of the {@link org.jasig.cas.client.configuration.ConfigurationStrategy} that first checks the {@link javax.servlet.FilterConfig} and
* then checks the {@link javax.servlet.ServletContext}, ultimately falling back to the <code>defaultValue</code>.
*
* @author Scott Battaglia
* @since 3.4.0
*/
public final class WebXmlConfigurationStrategyImpl extends BaseConfigurationStrategy {
private FilterConfig filterConfig;
@Override
protected String get(final ConfigurationKey configurationKey) {
final String value = this.filterConfig.getInitParameter(configurationKey.getName());
if (CommonUtils.isNotBlank(value)) {
CommonUtils.assertFalse(ConfigurationKeys.RENEW.equals(configurationKey), "Renew MUST be specified via context parameter or JNDI environment to avoid misconfiguration.");
logger.info("Property [{}] loaded from FilterConfig.getInitParameter with value [{}]", configurationKey, value);
return value;
}
final String value2 = filterConfig.getServletContext().getInitParameter(configurationKey.getName());
if (CommonUtils.isNotBlank(value2)) {
logger.info("Property [{}] loaded from ServletContext.getInitParameter with value [{}]", configurationKey,
value2);
return value2;
}
return null;
}
@Override
public void init(final FilterConfig filterConfig, final Class<? extends Filter> clazz) {
this.filterConfig = filterConfig;
}
}

View File

@ -1,26 +1,24 @@
/**
* Licensed to Jasig under one or more contributor license
* Licensed to Apereo 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,
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at:
* 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
* 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
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jasig.cas.client.jaas;
import java.io.Serializable;
import org.jasig.cas.client.authentication.SimplePrincipal;
import org.jasig.cas.client.validation.Assertion;
@ -33,12 +31,12 @@ import org.jasig.cas.client.validation.Assertion;
*
*/
public class AssertionPrincipal extends SimplePrincipal implements Serializable {
/** AssertionPrincipal.java */
private static final long serialVersionUID = 2288520214366461693L;
/** CAS assertion describing authenticated state */
private Assertion assertion;
private final Assertion assertion;
/**
* Creates a new principal containing the CAS assertion.

View File

@ -1,22 +1,21 @@
/**
* Licensed to Jasig under one or more contributor license
* Licensed to Apereo 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,
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at:
* 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
* 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
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jasig.cas.client.jaas;
import java.beans.BeanInfo;
@ -27,26 +26,19 @@ import java.io.IOException;
import java.security.Principal;
import java.security.acl.Group;
import java.util.*;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import javax.security.auth.Subject;
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.callback.*;
import javax.security.auth.login.LoginException;
import javax.security.auth.spi.LoginModule;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jasig.cas.client.authentication.SimpleGroup;
import org.jasig.cas.client.authentication.SimplePrincipal;
import org.jasig.cas.client.util.CommonUtils;
import org.jasig.cas.client.util.ReflectUtils;
import org.jasig.cas.client.validation.Assertion;
import org.jasig.cas.client.validation.TicketValidator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* JAAS login module that delegates to a CAS {@link TicketValidator} component
@ -79,6 +71,8 @@ import org.jasig.cas.client.validation.TicketValidator;
* for JAAS providers that attempt to periodically reauthenticate to renew principal.
* Since CAS tickets are one-time-use, a cached assertion must be provided on reauthentication.</li>
* <li>cacheTimeout (optional) - Assertion cache timeout in minutes.</li>
* <li>cacheTimeoutUnit (optional) - Assertion cache timeout unit. Must be one of {@link TimeUnit} enumeration
* names, e.g. DAYS, HOURS, MINUTES, SECONDS, MILLISECONDS. Default unit is MINUTES.</li>
* </ul>
*
* <p>
@ -109,14 +103,14 @@ import org.jasig.cas.client.validation.TicketValidator;
public class CasLoginModule implements LoginModule {
/** Constant for login name stored in shared state. */
public static final String LOGIN_NAME = "javax.security.auth.login.name";
/**
* Default group name for storing caller principal.
* The default value supports JBoss, but is configurable to hopefully
* support other JEE containers.
*/
public static final String DEFAULT_PRINCIPAL_GROUP_NAME = "CallerPrincipal";
/**
* Default group name for storing role membership data.
* The default value supports JBoss, but is configurable to hopefully
@ -129,50 +123,50 @@ public class CasLoginModule implements LoginModule {
*/
public static final int DEFAULT_CACHE_TIMEOUT = 480;
/** Default assertion cache timeout unit is minutes. */
public static final TimeUnit DEFAULT_CACHE_TIMEOUT_UNIT = TimeUnit.MINUTES;
/**
* Stores mapping of ticket to assertion to support JAAS providers that
* attempt to periodically re-authenticate to renew principal. Since
* CAS tickets are one-time-use, a cached assertion must be provided on
* re-authentication.
*/
protected static final Map<TicketCredential,Assertion> ASSERTION_CACHE = new HashMap<TicketCredential,Assertion>();
protected static final Map<TicketCredential, Assertion> ASSERTION_CACHE = new HashMap<TicketCredential, Assertion>();
/** Executor responsible for assertion cache cleanup */
protected static Executor cacheCleanerExecutor = Executors.newSingleThreadExecutor();
/** Logger instance */
protected final Log log = LogFactory.getLog(getClass());
protected final Logger logger = LoggerFactory.getLogger(getClass());
/** JAAS authentication subject */
protected Subject subject;
/** JAAS callback handler */
protected CallbackHandler callbackHandler;
/** CAS ticket validator */
protected TicketValidator ticketValidator;
/** CAS service parameter used if no service is provided via TextCallback on login */
protected String service;
/** CAS assertion */
protected Assertion assertion;
/** CAS ticket credential */
protected TicketCredential ticket;
/** Login module shared state */
protected Map<String,Object> sharedState;
protected Map<String, Object> sharedState;
/** Roles to be added to all authenticated principals by default */
protected String[] defaultRoles;
/** Names of attributes in the CAS assertion that should be used for role data */
protected Set<String> roleAttributeNames = new HashSet<String>();
protected final Set<String> roleAttributeNames = new HashSet<String>();
/** Name of JAAS Group containing caller principal */
protected String principalGroupName = DEFAULT_PRINCIPAL_GROUP_NAME;
/** Name of JAAS Group containing role data */
protected String roleGroupName = DEFAULT_ROLE_GROUP_NAME;
@ -182,8 +176,12 @@ public class CasLoginModule implements LoginModule {
/** Assertion cache timeout in minutes */
protected int cacheTimeout = DEFAULT_CACHE_TIMEOUT;
/** Units of cache timeout. */
protected TimeUnit cacheTimeoutUnit = DEFAULT_CACHE_TIMEOUT_UNIT;
/**
* Initializes the CAS login module.
*
* @param subject Authentication subject.
* @param handler Callback handler.
* @param state Shared state map.
@ -201,113 +199,152 @@ public class CasLoginModule implements LoginModule {
* which by default are single use, reauthentication fails. Assertion caching addresses this
* behavior.</li>
* <li>cacheTimeout (optional) - assertion cache timeout in minutes.</li>
* <li>cacheTimeoutUnit (optional) - Assertion cache timeout unit. Must be one of {@link TimeUnit} enumeration
* names, e.g. DAYS, HOURS, MINUTES, SECONDS, MILLISECONDS. Default unit is MINUTES.</li>
* </ul>
*/
@Override
public final void initialize(final Subject subject, final CallbackHandler handler, final Map<String, ?> state,
final Map<String, ?> options) {
public void initialize(final Subject subject, final CallbackHandler handler, final Map<String,?> state, final Map<String, ?> options) {
this.assertion = null;
this.callbackHandler = handler;
this.subject = subject;
this.sharedState = (Map<String, Object>) state;
this.sharedState = new HashMap<String, Object>(state);
String ticketValidatorClass = null;
for (final String key : options.keySet()) {
log.trace("Processing option " + key);
logger.trace("Processing option {}", key);
if ("service".equals(key)) {
this.service = (String) options.get(key);
log.debug("Set service=" + this.service);
logger.debug("Set service={}", this.service);
} else if ("ticketValidatorClass".equals(key)) {
ticketValidatorClass = (String) options.get(key);
log.debug("Set ticketValidatorClass=" + ticketValidatorClass);
logger.debug("Set ticketValidatorClass={}", ticketValidatorClass);
} else if ("defaultRoles".equals(key)) {
final String roles = (String) options.get(key);
log.trace("Got defaultRoles value " + roles);
logger.trace("Got defaultRoles value {}", roles);
this.defaultRoles = roles.split(",\\s*");
log.debug("Set defaultRoles=" + Arrays.asList(this.defaultRoles));
logger.debug("Set defaultRoles={}", Arrays.asList(this.defaultRoles));
} else if ("roleAttributeNames".equals(key)) {
final String attrNames = (String) options.get(key);
log.trace("Got roleAttributeNames value " + attrNames);
logger.trace("Got roleAttributeNames value {}", attrNames);
final String[] attributes = attrNames.split(",\\s*");
this.roleAttributeNames.addAll(Arrays.asList(attributes));
log.debug("Set roleAttributeNames=" + this.roleAttributeNames);
logger.debug("Set roleAttributeNames={}", this.roleAttributeNames);
} else if ("principalGroupName".equals(key)) {
this.principalGroupName = (String) options.get(key);
log.debug("Set principalGroupName=" + this.principalGroupName);
logger.debug("Set principalGroupName={}", this.principalGroupName);
} else if ("roleGroupName".equals(key)) {
this.roleGroupName = (String) options.get(key);
log.debug("Set roleGroupName=" + this.roleGroupName);
logger.debug("Set roleGroupName={}", this.roleGroupName);
} else if ("cacheAssertions".equals(key)) {
this.cacheAssertions = Boolean.parseBoolean((String) options.get(key));
log.debug("Set cacheAssertions=" + this.cacheAssertions);
logger.debug("Set cacheAssertions={}", this.cacheAssertions);
} else if ("cacheTimeout".equals(key)) {
this.cacheTimeout = Integer.parseInt((String) options.get(key));
log.debug("Set cacheTimeout=" + this.cacheTimeout);
logger.debug("Set cacheTimeout={}", this.cacheTimeout);
} else if ("cacheTimeoutUnit".equals(key)) {
this.cacheTimeoutUnit = Enum.valueOf(TimeUnit.class, (String) options.get(key));
logger.debug("Set cacheTimeoutUnit={}", this.cacheTimeoutUnit);
}
}
if (this.cacheAssertions) {
cacheCleanerExecutor.execute(new CacheCleaner());
cleanCache();
}
CommonUtils.assertNotNull(ticketValidatorClass, "ticketValidatorClass is required.");
this.ticketValidator = createTicketValidator(ticketValidatorClass, options);
}
public boolean login() throws LoginException {
log.debug("Performing login.");
final NameCallback serviceCallback = new NameCallback("service");
final PasswordCallback ticketCallback = new PasswordCallback("ticket", false);
try {
this.callbackHandler.handle(new Callback[] { ticketCallback, serviceCallback });
} catch (final IOException e) {
log.info("Login failed due to IO exception in callback handler: " + e);
throw (LoginException) new LoginException("IO exception in callback handler: " + e).initCause(e);
} catch (final UnsupportedCallbackException e) {
log.info("Login failed due to unsupported callback: " + e);
throw (LoginException) new LoginException("Callback handler does not support PasswordCallback and TextInputCallback.").initCause(e);
}
if (ticketCallback.getPassword() != null) {
this.ticket = new TicketCredential(new String(ticketCallback.getPassword()));
final String service = CommonUtils.isNotBlank(serviceCallback.getName()) ? serviceCallback.getName() : this.service;
if (this.cacheAssertions) {
synchronized(ASSERTION_CACHE) {
if (ASSERTION_CACHE.get(ticket) != null) {
log.debug("Assertion found in cache.");
this.assertion = ASSERTION_CACHE.get(ticket);
}
}
}
if (this.assertion == null) {
log.debug("CAS assertion is null; ticket validation required.");
if (CommonUtils.isBlank(service)) {
log.info("Login failed because required CAS service parameter not provided.");
throw new LoginException("Neither login module nor callback handler provided required service parameter.");
}
try {
if (log.isDebugEnabled()) {
log.debug("Attempting ticket validation with service=" + service + " and ticket=" + ticket);
}
this.assertion = this.ticketValidator.validate(this.ticket.getName(), service);
} catch (final Exception e) {
log.info("Login failed due to CAS ticket validation failure: " + e);
throw (LoginException) new LoginException("CAS ticket validation failed: " + e).initCause(e);
}
}
log.info("Login succeeded.");
} else {
log.info("Login failed because callback handler did not provide CAS ticket.");
throw new LoginException("Callback handler did not provide CAS ticket.");
}
/**
* Operations to perform before doing login.
*
* @return true if you'd like login to continue, false otherwise.
*/
protected boolean preLogin() {
return true;
}
public boolean abort() throws LoginException {
/**
* This occurs after logout is processed.
*
* @param result the result from the login attempt.
*/
protected void postLogin(final boolean result) {
// template method
}
@Override
public final boolean login() throws LoginException {
logger.debug("Performing login.");
if (!preLogin()) {
logger.debug("preLogin failed.");
return false;
}
final NameCallback serviceCallback = new NameCallback("service");
final PasswordCallback ticketCallback = new PasswordCallback("ticket", false);
boolean result = false;
try {
try {
this.callbackHandler.handle(new Callback[] { ticketCallback, serviceCallback });
} catch (final IOException e) {
logger.info("Login failed due to IO exception in callback handler", e);
throw (LoginException) new LoginException("IO exception in callback handler: " + e).initCause(e);
} catch (final UnsupportedCallbackException e) {
logger.info("Login failed due to unsupported callback", e);
throw (LoginException) new LoginException(
"Callback handler does not support PasswordCallback and TextInputCallback.").initCause(e);
}
if (ticketCallback.getPassword() != null) {
this.ticket = new TicketCredential(new String(ticketCallback.getPassword()));
final String service = CommonUtils.isNotBlank(serviceCallback.getName()) ? serviceCallback.getName()
: this.service;
if (this.cacheAssertions) {
this.assertion = ASSERTION_CACHE.get(ticket);
if (this.assertion != null) {
logger.debug("Assertion found in cache.");
}
}
if (this.assertion == null) {
logger.debug("CAS assertion is null; ticket validation required.");
if (CommonUtils.isBlank(service)) {
logger.info("Login failed because required CAS service parameter not provided.");
throw new LoginException(
"Neither login module nor callback handler provided required service parameter.");
}
try {
logger.debug("Attempting ticket validation with service={} and ticket={}", service,
this.ticket);
this.assertion = this.ticketValidator.validate(this.ticket.getName(), service);
} catch (final Exception e) {
logger.info("Login failed due to CAS ticket validation failure", e);
throw (LoginException) new LoginException("CAS ticket validation failed: " + e).initCause(e);
}
}
logger.info("Login succeeded.");
} else {
logger.info("Login failed because callback handler did not provide CAS ticket.");
throw new LoginException("Callback handler did not provide CAS ticket.");
}
result = true;
} finally {
postLogin(result);
}
return result;
}
@Override
public final boolean abort() throws LoginException {
if (this.ticket != null) {
this.ticket = null;
}
@ -317,86 +354,140 @@ public class CasLoginModule implements LoginModule {
return true;
}
public boolean commit() throws LoginException {
if (this.assertion != null) {
if (this.ticket != null) {
this.subject.getPrivateCredentials().add(this.ticket);
} else {
throw new LoginException("Ticket credential not found.");
}
final AssertionPrincipal casPrincipal = new AssertionPrincipal(this.assertion.getPrincipal().getName(), this.assertion);
this.subject.getPrincipals().add(casPrincipal);
// Add group containing principal as sole member
// Supports JBoss JAAS use case
final Group principalGroup = new SimpleGroup(this.principalGroupName);
principalGroup.addMember(casPrincipal);
this.subject.getPrincipals().add(principalGroup);
// Add group principal containing role data
final Group roleGroup = new SimpleGroup(this.roleGroupName);
for (final String defaultRole : defaultRoles) {
roleGroup.addMember(new SimplePrincipal(defaultRole));
}
final Map<String,Object> attributes = this.assertion.getPrincipal().getAttributes();
for (final String key : attributes.keySet()) {
if (this.roleAttributeNames.contains(key)) {
// Attribute value is Object if singular or Collection if plural
final Object value = attributes.get(key);
if (value instanceof Collection<?>) {
for (final Object o : (Collection<?>) value) {
roleGroup.addMember(new SimplePrincipal(o.toString()));
}
} else {
roleGroup.addMember(new SimplePrincipal(value.toString()));
}
}
}
this.subject.getPrincipals().add(roleGroup);
// Place principal name in shared state for downstream JAAS modules (module chaining use case)
this.sharedState.put(LOGIN_NAME, new Object()); // casPrincipal.getName());
if (log.isDebugEnabled()) {
if (log.isDebugEnabled()) {
log.debug("Created JAAS subject with principals: " + subject.getPrincipals());
}
}
if (this.cacheAssertions) {
if (log.isDebugEnabled()) {
log.debug("Caching assertion for principal " + this.assertion.getPrincipal());
}
ASSERTION_CACHE.put(this.ticket, this.assertion);
}
} else {
// Login must have failed if there is no assertion defined
// Need to clean up state
if (this.ticket != null) {
this.ticket = null;
}
}
/**
* Operations to perform before doing commit.
*
* @return true if you'd like commit to continue, false otherwise.
*/
protected boolean preCommit() {
return true;
}
public boolean logout() throws LoginException {
log.debug("Performing logout.");
/**
* This occurs after commit is processed.
*
* @param result the result from the login attempt.
*/
protected void postCommit(final boolean result) {
// template method
}
@Override
public final boolean commit() throws LoginException {
if (!preCommit()) {
return false;
}
boolean result = false;
try {
if (this.assertion != null) {
if (this.ticket != null) {
this.subject.getPrivateCredentials().add(this.ticket);
} else {
throw new LoginException("Ticket credential not found.");
}
final AssertionPrincipal casPrincipal = new AssertionPrincipal(this.assertion.getPrincipal().getName(),
this.assertion);
this.subject.getPrincipals().add(casPrincipal);
// Add group containing principal as sole member
// Supports JBoss JAAS use case
final Group principalGroup = new SimpleGroup(this.principalGroupName);
principalGroup.addMember(casPrincipal);
this.subject.getPrincipals().add(principalGroup);
// Add group principal containing role data
final Group roleGroup = new SimpleGroup(this.roleGroupName);
for (final String defaultRole : defaultRoles) {
roleGroup.addMember(new SimplePrincipal(defaultRole));
}
final Map<String, Object> attributes = this.assertion.getPrincipal().getAttributes();
for (final String key : attributes.keySet()) {
if (this.roleAttributeNames.contains(key)) {
// Attribute value is Object if singular or Collection if plural
final Object value = attributes.get(key);
if (value instanceof Collection<?>) {
for (final Object o : (Collection<?>) value) {
roleGroup.addMember(new SimplePrincipal(o.toString()));
}
} else {
roleGroup.addMember(new SimplePrincipal(value.toString()));
}
}
}
this.subject.getPrincipals().add(roleGroup);
// Place principal name in shared state for downstream JAAS modules (module chaining use case)
this.sharedState.put(LOGIN_NAME, assertion.getPrincipal().getName());
logger.debug("Created JAAS subject with principals: {}", subject.getPrincipals());
if (this.cacheAssertions) {
logger.debug("Caching assertion for principal {}", this.assertion.getPrincipal());
ASSERTION_CACHE.put(this.ticket, this.assertion);
}
} else {
// Login must have failed if there is no assertion defined
// Need to clean up state
if (this.ticket != null) {
this.ticket = null;
}
}
result = true;
} finally {
postCommit(result);
}
return result;
}
@Override
public final boolean logout() throws LoginException {
logger.debug("Performing logout.");
if (!preLogout()) {
return false;
}
// Remove cache entry if assertion caching is enabled
if (this.cacheAssertions) {
for (final TicketCredential ticket : this.subject.getPrivateCredentials(TicketCredential.class)) {
logger.debug("Removing cached assertion for {}", ticket);
ASSERTION_CACHE.remove(ticket);
}
}
// Remove all CAS principals
removePrincipalsOfType(AssertionPrincipal.class);
removePrincipalsOfType(SimplePrincipal.class);
removePrincipalsOfType(SimpleGroup.class);
// Remove all CAS credentials
removeCredentialsOfType(TicketCredential.class);
log.info("Logout succeeded.");
logger.info("Logout succeeded.");
postLogout();
return true;
}
/**
* Happens before logout occurs.
*
* @return true if we should continue, false otherwise.
*/
protected boolean preLogout() {
return true;
}
/**
* Happens after logout.
*/
protected void postLogout() {
// template method
}
/**
* Creates a {@link TicketValidator} instance from a class name and map of property name/value pairs.
@ -404,32 +495,34 @@ public class CasLoginModule implements LoginModule {
* @param propertyMap Map of property name/value pairs to set on validator instance.
* @return Ticket validator with properties set.
*/
private TicketValidator createTicketValidator(final String className, final Map<String,?> propertyMap) {
CommonUtils.assertTrue(propertyMap.containsKey("casServerUrlPrefix"), "Required property casServerUrlPrefix not found.");
private TicketValidator createTicketValidator(final String className, final Map<String, ?> propertyMap) {
CommonUtils.assertTrue(propertyMap.containsKey("casServerUrlPrefix"),
"Required property casServerUrlPrefix not found.");
final Class<TicketValidator> validatorClass = ReflectUtils.loadClass(className);
final TicketValidator validator = ReflectUtils.newInstance(validatorClass, propertyMap.get("casServerUrlPrefix"));
final TicketValidator validator = ReflectUtils.newInstance(validatorClass,
propertyMap.get("casServerUrlPrefix"));
try {
final BeanInfo info = Introspector.getBeanInfo(validatorClass);
for (final String property : propertyMap.keySet()) {
if (!"casServerUrlPrefix".equals(property)) {
log.debug("Attempting to set TicketValidator property " + property);
logger.debug("Attempting to set TicketValidator property {}", property);
final String value = (String) propertyMap.get(property);
final PropertyDescriptor pd = ReflectUtils.getPropertyDescriptor(info, property);
if (pd != null) {
ReflectUtils.setProperty(property, convertIfNecessary(pd, value), validator, info);
log.debug("Set " + property + "=" + value);
ReflectUtils.setProperty(property, convertIfNecessary(pd, value), validator, info);
logger.debug("Set {} = {}", property, value);
} else {
log.warn("Cannot find property " + property + " on " + className);
logger.warn("Cannot find property {} on {}", property, className);
}
}
}
} catch (final IntrospectionException e) {
throw new RuntimeException("Error getting bean info for " + validatorClass, e);
}
return validator;
}
@ -453,7 +546,8 @@ public class CasLoginModule implements LoginModule {
} else if (long.class.equals(pd.getPropertyType())) {
return new Long(value);
} else {
throw new IllegalArgumentException("No conversion strategy exists for property " + pd.getName() + " of type " + pd.getPropertyType());
throw new IllegalArgumentException("No conversion strategy exists for property " + pd.getName()
+ " of type " + pd.getPropertyType());
}
}
@ -473,26 +567,21 @@ public class CasLoginModule implements LoginModule {
this.subject.getPrivateCredentials().removeAll(this.subject.getPrivateCredentials(clazz));
}
/** Removes expired entries from the assertion cache. */
private class CacheCleaner implements Runnable {
public void run() {
if (log.isDebugEnabled()) {
log.debug("Cleaning assertion cache of size " + CasLoginModule.ASSERTION_CACHE.size());
}
final Iterator<Map.Entry<TicketCredential,Assertion>> iter =
CasLoginModule.ASSERTION_CACHE.entrySet().iterator();
final Calendar cutoff = Calendar.getInstance();
cutoff.add(Calendar.MINUTE, -CasLoginModule.this.cacheTimeout);
while (iter.hasNext()) {
final Assertion assertion = iter.next().getValue();
final Calendar created = Calendar.getInstance();
created.setTime(assertion.getValidFromDate());
if (created.before(cutoff)) {
if (log.isDebugEnabled()) {
log.debug("Removing expired assertion for principal " + assertion.getPrincipal());
}
iter.remove();
}
/**
* Removes expired entries from the assertion cache.
*/
private void cleanCache() {
logger.debug("Cleaning assertion cache of size {}", ASSERTION_CACHE.size());
final Iterator<Map.Entry<TicketCredential, Assertion>> iter = ASSERTION_CACHE.entrySet().iterator();
final Calendar cutoff = Calendar.getInstance();
cutoff.setTimeInMillis(System.currentTimeMillis() - this.cacheTimeoutUnit.toMillis(this.cacheTimeout));
while (iter.hasNext()) {
final Assertion assertion = iter.next().getValue();
final Calendar created = Calendar.getInstance();
created.setTime(assertion.getValidFromDate());
if (created.before(cutoff)) {
logger.debug("Removing expired assertion for principal {}", assertion.getPrincipal());
iter.remove();
}
}
}

View File

@ -1,31 +1,25 @@
/**
* Licensed to Jasig under one or more contributor license
* Licensed to Apereo 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,
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at:
* 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
* 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
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jasig.cas.client.jaas;
import java.io.IOException;
import javax.security.auth.callback.Callback;
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.callback.*;
/**
* Callback handler that provides the CAS service and ticket to a
@ -41,10 +35,10 @@ public class ServiceAndTicketCallbackHandler implements CallbackHandler {
/** CAS service URL */
private final String service;
/** CAS service ticket */
private final String ticket;
/**
* Creates a new instance with the given service and ticket.
*
@ -56,6 +50,7 @@ public class ServiceAndTicketCallbackHandler implements CallbackHandler {
this.ticket = ticket;
}
@Override
public void handle(final Callback[] callbacks) throws IOException, UnsupportedCallbackException {
for (final Callback callback : callbacks) {
if (callback instanceof NameCallback) {

View File

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

View File

@ -1,22 +1,21 @@
/**
* Licensed to Jasig under one or more contributor license
* Licensed to Apereo 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,
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at:
* 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
* 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
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jasig.cas.client.jaas;
import java.security.Principal;
@ -33,9 +32,9 @@ public final class TicketCredential implements Principal {
/** Hash code seed value */
private static final int HASHCODE_SEED = 17;
/** Ticket ID string */
private String ticket;
private final String ticket;
/**
* Creates a new instance that wraps the given ticket.
@ -45,6 +44,7 @@ public final class TicketCredential implements Principal {
this.ticket = ticket;
}
@Override
public String getName() {
return this.ticket;
}
@ -53,13 +53,16 @@ public final class TicketCredential implements Principal {
return this.ticket;
}
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
public boolean equals(final Object o) {
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
final TicketCredential that = (TicketCredential) o;
if (ticket != null ? !ticket.equals(that.ticket) : that.ticket != null) return false;
if (ticket != null ? !ticket.equals(that.ticket) : that.ticket != null)
return false;
return true;
}

View File

@ -1,13 +1,32 @@
/**
* Licensed to Apereo under one or more contributor license
* agreements. See the NOTICE file distributed with this work
* for additional information regarding copyright ownership.
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at the following location:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jasig.cas.client.proxy;
import javax.crypto.Cipher;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import javax.crypto.spec.DESedeKeySpec;
import org.jasig.cas.client.configuration.ConfigurationKeys;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
import javax.crypto.Cipher;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESedeKeySpec;
/**
* Provides encryption capabilities. Not entirely safe to configure since we have no way of controlling the
@ -19,13 +38,12 @@ import java.security.spec.InvalidKeySpecException;
*/
public abstract class AbstractEncryptedProxyGrantingTicketStorageImpl implements ProxyGrantingTicketStorage {
public static final String DEFAULT_ENCRYPTION_ALGORITHM = "DESede";
private Key key;
private String cipherAlgorithm = DEFAULT_ENCRYPTION_ALGORITHM;
private String cipherAlgorithm = ConfigurationKeys.CIPHER_ALGORITHM.getDefaultValue();
public final void setSecretKey(final String key) throws NoSuchAlgorithmException, InvalidKeyException, InvalidKeySpecException {
public final void setSecretKey(final String key) throws NoSuchAlgorithmException, InvalidKeyException,
InvalidKeySpecException {
this.key = SecretKeyFactory.getInstance(this.cipherAlgorithm).generateSecret(new DESedeKeySpec(key.getBytes()));
}
@ -42,10 +60,12 @@ public abstract class AbstractEncryptedProxyGrantingTicketStorageImpl implements
this.cipherAlgorithm = cipherAlgorithm;
}
@Override
public final void save(final String proxyGrantingTicketIou, final String proxyGrantingTicket) {
saveInternal(proxyGrantingTicketIou, encrypt(proxyGrantingTicket));
}
@Override
public final String retrieve(final String proxyGrantingTicketIou) {
return decrypt(retrieveInternal(proxyGrantingTicketIou));
}

View File

@ -1,54 +1,49 @@
/**
* Licensed to Jasig under one or more contributor license
* Licensed to Apereo 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,
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at:
* 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
* 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
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jasig.cas.client.proxy;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import java.net.URL;
import java.net.URLEncoder;
import org.jasig.cas.client.ssl.HttpURLConnectionFactory;
import org.jasig.cas.client.util.CommonUtils;
import org.jasig.cas.client.util.XmlUtils;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Implementation of a ProxyRetriever that follows the CAS 2.0 specification.
* For more information on the CAS 2.0 specification, please see the <a
* href="http://www.ja-sig.org/products/cas/overview/protocol/index.html">specification
* href="http://www.jasig.org/cas/protocol">specification
* document</a>.
* <p/>
* In general, this class will make a call to the CAS server with some specified
* parameters and receive an XML response to parse.
*
* @author Scott Battaglia
* @version $Revision: 11729 $ $Date: 2007-09-26 14:22:30 -0400 (Tue, 26 Sep 2007) $
* @since 3.0
*/
public final class Cas20ProxyRetriever implements ProxyRetriever {
/** Unique Id for serialization. */
private static final long serialVersionUID = 560409469568911791L;
private static final long serialVersionUID = 560409469568911792L;
/**
* Instance of Commons Logging.
*/
private final Log log = LogFactory.getLog(this.getClass());
private static final Logger logger = LoggerFactory.getLogger(Cas20ProxyRetriever.class);
/**
* Url to CAS server.
@ -57,39 +52,59 @@ public final class Cas20ProxyRetriever implements ProxyRetriever {
private final String encoding;
/** Url connection factory to use when communicating with the server **/
private final HttpURLConnectionFactory urlConnectionFactory;
@Deprecated
public Cas20ProxyRetriever(final String casServerUrl, final String encoding) {
this(casServerUrl, encoding, null);
}
/**
* Main Constructor.
*
* @param casServerUrl the URL to the CAS server (i.e. http://localhost/cas/)
* @param encoding the encoding to use.
* @param urlFactory url connection factory use when retrieving proxy responses from the server
*/
public Cas20ProxyRetriever(final String casServerUrl, final String encoding) {
public Cas20ProxyRetriever(final String casServerUrl, final String encoding,
final HttpURLConnectionFactory urlFactory) {
CommonUtils.assertNotNull(casServerUrl, "casServerUrl cannot be null.");
this.casServerUrl = casServerUrl;
this.encoding = encoding;
this.urlConnectionFactory = urlFactory;
}
public String getProxyTicketIdFor(final String proxyGrantingTicketId,
final String targetService) {
@Override
public String getProxyTicketIdFor(final String proxyGrantingTicketId, final String targetService) {
CommonUtils.assertNotNull(proxyGrantingTicketId, "proxyGrantingTicketId cannot be null.");
CommonUtils.assertNotNull(targetService, "targetService cannot be null.");
final String url = constructUrl(proxyGrantingTicketId, targetService);
final String response = CommonUtils.getResponseFromServer(url, this.encoding);
final URL url = constructUrl(proxyGrantingTicketId, targetService);
final String response;
if (this.urlConnectionFactory != null) {
response = CommonUtils.getResponseFromServer(url, this.urlConnectionFactory, this.encoding);
} else {
response = CommonUtils.getResponseFromServer(url, this.encoding);
}
final String error = XmlUtils.getTextForElement(response, "proxyFailure");
if (CommonUtils.isNotEmpty(error)) {
log.debug(error);
logger.debug(error);
return null;
}
return XmlUtils.getTextForElement(response, "proxyTicket");
final String ticket = XmlUtils.getTextForElement(response, "proxyTicket");
logger.debug("Got proxy ticket {}", ticket);
return ticket;
}
private String constructUrl(final String proxyGrantingTicketId, final String targetService) {
private URL constructUrl(final String proxyGrantingTicketId, final String targetService) {
try {
return this.casServerUrl + (this.casServerUrl.endsWith("/") ? "" : "/") + "proxy" + "?pgt="
+ proxyGrantingTicketId + "&targetService="
+ URLEncoder.encode(targetService, "UTF-8");
} catch (final UnsupportedEncodingException e) {
return new URL(this.casServerUrl + (this.casServerUrl.endsWith("/") ? "" : "/") + "proxy" + "?pgt="
+ proxyGrantingTicketId + "&targetService=" + URLEncoder.encode(targetService, "UTF-8"));
} catch (final Exception e) {
throw new RuntimeException(e);
}
}

View File

@ -1,22 +1,21 @@
/**
* Licensed to Jasig under one or more contributor license
* Licensed to Apereo 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,
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at:
* 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
* 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
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jasig.cas.client.proxy;
import java.util.TimerTask;
@ -39,6 +38,8 @@ public final class CleanUpTimerTask extends TimerTask {
public CleanUpTimerTask(final ProxyGrantingTicketStorage proxyGrantingTicketStorage) {
this.proxyGrantingTicketStorage = proxyGrantingTicketStorage;
}
@Override
public void run() {
this.proxyGrantingTicketStorage.cleanUp();
}

View File

@ -1,22 +1,21 @@
/**
* Licensed to Jasig under one or more contributor license
* Licensed to Apereo 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,
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at:
* 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
* 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
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jasig.cas.client.proxy;
/**
@ -24,7 +23,6 @@ package org.jasig.cas.client.proxy;
* them to a specific ProxyGrantingTicketIou.
*
* @author Scott Battaglia
* @version $Revision: 11729 $ $Date: 2007-09-26 14:22:30 -0400 (Tue, 26 Sep 2007) $
* @since 3.0
*/
public interface ProxyGrantingTicketStorage {
@ -47,7 +45,7 @@ public interface ProxyGrantingTicketStorage {
* @return the ProxyGrantingTicket Id or null if it can't be found
*/
public String retrieve(String proxyGrantingTicketIou);
/**
* Called on a regular basis by an external timer,
* giving implementations a chance to remove stale data.

View File

@ -1,30 +1,29 @@
/**
* Licensed to Jasig under one or more contributor license
* Licensed to Apereo 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,
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at:
* 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
* 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
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jasig.cas.client.proxy;
import java.util.*;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jasig.cas.client.util.CommonUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Implementation of {@link ProxyGrantingTicketStorage} that is backed by a
@ -35,12 +34,11 @@ import org.apache.commons.logging.LogFactory;
*
* @author Scott Battaglia
* @author Brad Cupit (brad [at] lsu {dot} edu)
* @version $Revision: 11729 $ $Date: 2007-09-26 14:22:30 -0400 (Tue, 26 Sep 2007) $
* @since 3.0
*/
public final class ProxyGrantingTicketStorageImpl implements ProxyGrantingTicketStorage {
private final Log log = LogFactory.getLog(getClass());
private final Logger logger = LoggerFactory.getLogger(getClass());
/**
* Default timeout in milliseconds.
@ -50,7 +48,7 @@ public final class ProxyGrantingTicketStorageImpl implements ProxyGrantingTicket
/**
* Map that stores the PGTIOU to PGT mappings.
*/
private final ConcurrentMap<String,ProxyGrantingTicketHolder> cache = new ConcurrentHashMap<String,ProxyGrantingTicketHolder>();
private final ConcurrentMap<String, ProxyGrantingTicketHolder> cache = new ConcurrentHashMap<String, ProxyGrantingTicketHolder>();
/**
* time, in milliseconds, before a {@link ProxyGrantingTicketHolder}
@ -58,7 +56,7 @@ public final class ProxyGrantingTicketStorageImpl implements ProxyGrantingTicket
*
* @see ProxyGrantingTicketStorageImpl#DEFAULT_TIMEOUT
*/
private long timeout;
private final long timeout;
/**
* Constructor set the timeout to the default value.
@ -74,35 +72,38 @@ public final class ProxyGrantingTicketStorageImpl implements ProxyGrantingTicket
* @param timeout the time to hold on to the ProxyGrantingTicket
*/
public ProxyGrantingTicketStorageImpl(final long timeout) {
this.timeout = timeout;
this.timeout = timeout;
}
/**
* NOTE: you can only retrieve a ProxyGrantingTicket once with this method.
* Its removed after retrieval.
*/
@Override
public String retrieve(final String proxyGrantingTicketIou) {
if (CommonUtils.isBlank(proxyGrantingTicketIou)) {
return null;
}
final ProxyGrantingTicketHolder holder = this.cache.get(proxyGrantingTicketIou);
if (holder == null) {
log.info("No Proxy Ticket found for [" + proxyGrantingTicketIou + "].");
logger.info("No Proxy Ticket found for [{}].", proxyGrantingTicketIou);
return null;
}
this.cache.remove(proxyGrantingTicketIou);
if (log.isDebugEnabled()) {
log.debug("Returned ProxyGrantingTicket of [" + holder.getProxyGrantingTicket() + "]");
}
logger.debug("Returned ProxyGrantingTicket of [{}]", holder.getProxyGrantingTicket());
return holder.getProxyGrantingTicket();
}
@Override
public void save(final String proxyGrantingTicketIou, final String proxyGrantingTicket) {
final ProxyGrantingTicketHolder holder = new ProxyGrantingTicketHolder(proxyGrantingTicket);
if (log.isDebugEnabled()) {
log.debug("Saving ProxyGrantingTicketIOU and ProxyGrantingTicket combo: [" + proxyGrantingTicketIou + ", " + proxyGrantingTicket + "]");
}
logger.debug("Saving ProxyGrantingTicketIOU and ProxyGrantingTicket combo: [{}, {}]", proxyGrantingTicketIou,
proxyGrantingTicket);
this.cache.put(proxyGrantingTicketIou, holder);
}
@ -110,14 +111,15 @@ public final class ProxyGrantingTicketStorageImpl implements ProxyGrantingTicket
* Cleans up old, expired proxy tickets. This method must be
* called regularly via an external thread or timer.
*/
@Override
public void cleanUp() {
for (final Map.Entry<String,ProxyGrantingTicketHolder> holder : this.cache.entrySet()) {
for (final Map.Entry<String, ProxyGrantingTicketHolder> holder : this.cache.entrySet()) {
if (holder.getValue().isExpired(this.timeout)) {
this.cache.remove(holder.getKey());
}
}
}
private static final class ProxyGrantingTicketHolder {
private final String proxyGrantingTicket;

View File

@ -1,22 +1,21 @@
/**
* Licensed to Jasig under one or more contributor license
* Licensed to Apereo 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,
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at:
* 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
* 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
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jasig.cas.client.proxy;
import java.io.Serializable;
@ -26,7 +25,6 @@ import java.io.Serializable;
* implementation a black box to the client.
*
* @author Scott Battaglia
* @version $Revision: 11729 $ $Date: 2007-09-26 14:22:30 -0400 (Tue, 26 Sep 2007) $
* @since 3.0
*/
public interface ProxyRetriever extends Serializable {
@ -38,6 +36,5 @@ public interface ProxyRetriever extends Serializable {
* @param targetService the service we want to proxy.
* @return the ProxyTicket Id if Granted, null otherwise.
*/
String getProxyTicketIdFor(String proxyGrantingTicketId,
String targetService);
String getProxyTicketIdFor(String proxyGrantingTicketId, String targetService);
}

View File

@ -1,24 +1,23 @@
<!--
Licensed to Jasig under one or more contributor license
Licensed to Apereo 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,
Apereo licenses this file to you under the Apache License,
Version 2.0 (the "License"); you may not use this file
except in compliance with the License. You may obtain a
copy of the License at:
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
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
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->
<html>
<body>
<p>The proxy package includes a servlet to act as a proxy receptor,

View File

@ -1,31 +1,28 @@
/**
* Licensed to Jasig under one or more contributor license
* Licensed to Apereo 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,
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at:
* 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
* 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
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jasig.cas.client.session;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.http.HttpSession;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* HashMap backed implementation of SessionMappingStorage.
@ -36,50 +33,51 @@ import javax.servlet.http.HttpSession;
*
*/
public final class HashMapBackedSessionMappingStorage implements SessionMappingStorage {
/**
* Maps the ID from the CAS server to the Session.
*/
private final Map<String,HttpSession> MANAGED_SESSIONS = new HashMap<String,HttpSession>();
private final Map<String, HttpSession> MANAGED_SESSIONS = new HashMap<String, HttpSession>();
/**
* Maps the Session ID to the key from the CAS Server.
*/
private final Map<String,String> ID_TO_SESSION_KEY_MAPPING = new HashMap<String,String>();
private final Map<String, String> ID_TO_SESSION_KEY_MAPPING = new HashMap<String, String>();
private final Log log = LogFactory.getLog(getClass());
private final Logger logger = LoggerFactory.getLogger(getClass());
public synchronized void addSessionById(String mappingId, HttpSession session) {
@Override
public synchronized void addSessionById(final String mappingId, final HttpSession session) {
ID_TO_SESSION_KEY_MAPPING.put(session.getId(), mappingId);
MANAGED_SESSIONS.put(mappingId, session);
}
}
public synchronized void removeBySessionById(String sessionId) {
if (log.isDebugEnabled()) {
log.debug("Attempting to remove Session=[" + sessionId + "]");
}
@Override
public synchronized void removeBySessionById(final String sessionId) {
logger.debug("Attempting to remove Session=[{}]", sessionId);
final String key = ID_TO_SESSION_KEY_MAPPING.get(sessionId);
if (log.isDebugEnabled()) {
if (logger.isDebugEnabled()) {
if (key != null) {
log.debug("Found mapping for session. Session Removed.");
logger.debug("Found mapping for session. Session Removed.");
} else {
log.debug("No mapping for session found. Ignoring.");
logger.debug("No mapping for session found. Ignoring.");
}
}
MANAGED_SESSIONS.remove(key);
ID_TO_SESSION_KEY_MAPPING.remove(sessionId);
}
}
public synchronized HttpSession removeSessionByMappingId(String mappingId) {
final HttpSession session = MANAGED_SESSIONS.get(mappingId);
@Override
public synchronized HttpSession removeSessionByMappingId(final String mappingId) {
final HttpSession session = MANAGED_SESSIONS.get(mappingId);
if (session != null) {
removeBySessionById(session.getId());
removeBySessionById(session.getId());
}
return session;
}
}
}

View File

@ -1,22 +1,21 @@
/**
* Licensed to Jasig under one or more contributor license
* Licensed to Apereo 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,
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at:
* 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
* 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
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jasig.cas.client.session;
import javax.servlet.http.HttpSession;
@ -30,26 +29,26 @@ import javax.servlet.http.HttpSession;
*
*/
public interface SessionMappingStorage {
/**
* Remove the HttpSession based on the mappingId.
*
* @param mappingId the id the session is keyed under.
* @return the HttpSession if it exists.
*/
HttpSession removeSessionByMappingId(String mappingId);
/**
* Remove a session by its Id.
* @param sessionId the id of the session.
*/
void removeBySessionById(String sessionId);
/**
* Add a session by its mapping Id.
* @param mappingId the id to map the session to.
* @param session the HttpSession.
*/
void addSessionById(String mappingId, HttpSession session);
/**
* Remove the HttpSession based on the mappingId.
*
* @param mappingId the id the session is keyed under.
* @return the HttpSession if it exists.
*/
HttpSession removeSessionByMappingId(String mappingId);
/**
* Remove a session by its Id.
* @param sessionId the id of the session.
*/
void removeBySessionById(String sessionId);
/**
* Add a session by its mapping Id.
* @param mappingId the id to map the session to.
* @param session the HttpSession.
*/
void addSessionById(String mappingId, HttpSession session);
}

View File

@ -1,33 +1,32 @@
/**
* Licensed to Jasig under one or more contributor license
* Licensed to Apereo 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,
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at:
* 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
* 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
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jasig.cas.client.session;
import org.jasig.cas.client.util.AbstractConfigurationFilter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.concurrent.atomic.AtomicBoolean;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.jasig.cas.client.configuration.ConfigurationKeys;
import org.jasig.cas.client.util.AbstractConfigurationFilter;
/**
* Implements the Single Sign Out protocol. It handles registering the session and destroying the session.
@ -38,49 +37,70 @@ import java.io.IOException;
*/
public final class SingleSignOutFilter extends AbstractConfigurationFilter {
private static final SingleSignOutHandler handler = new SingleSignOutHandler();
private static final SingleSignOutHandler HANDLER = new SingleSignOutHandler();
private final AtomicBoolean handlerInitialized = new AtomicBoolean(false);
@Override
public void init(final FilterConfig filterConfig) throws ServletException {
super.init(filterConfig);
if (!isIgnoreInitConfiguration()) {
handler.setArtifactParameterName(getPropertyFromInitParams(filterConfig, "artifactParameterName", "ticket"));
handler.setLogoutParameterName(getPropertyFromInitParams(filterConfig, "logoutParameterName", "logoutRequest"));
setArtifactParameterName(getString(ConfigurationKeys.ARTIFACT_PARAMETER_NAME));
setLogoutParameterName(getString(ConfigurationKeys.LOGOUT_PARAMETER_NAME));
setRelayStateParameterName(getString(ConfigurationKeys.RELAY_STATE_PARAMETER_NAME));
setLogoutCallbackPath(getString(ConfigurationKeys.LOGOUT_CALLBACK_PATH));
HANDLER.setArtifactParameterOverPost(getBoolean(ConfigurationKeys.ARTIFACT_PARAMETER_OVER_POST));
HANDLER.setEagerlyCreateSessions(getBoolean(ConfigurationKeys.EAGERLY_CREATE_SESSIONS));
}
handler.init();
HANDLER.init();
handlerInitialized.set(true);
}
public void setArtifactParameterName(final String name) {
handler.setArtifactParameterName(name);
HANDLER.setArtifactParameterName(name);
}
public void setLogoutParameterName(final String name) {
HANDLER.setLogoutParameterName(name);
}
public void setLogoutParameterName(final String name) {
handler.setLogoutParameterName(name);
public void setRelayStateParameterName(final String name) {
HANDLER.setRelayStateParameterName(name);
}
public void setLogoutCallbackPath(final String logoutCallbackPath) {
HANDLER.setLogoutCallbackPath(logoutCallbackPath);
}
public void setSessionMappingStorage(final SessionMappingStorage storage) {
handler.setSessionMappingStorage(storage);
HANDLER.setSessionMappingStorage(storage);
}
public void doFilter(final ServletRequest servletRequest, final ServletResponse servletResponse, final FilterChain filterChain) throws IOException, ServletException {
final HttpServletRequest request = (HttpServletRequest) servletRequest;
if (handler.isTokenRequest(request)) {
handler.recordSession(request);
} else if (handler.isLogoutRequest(request)) {
handler.destroySession(request);
// Do not continue up filter chain
return;
} else {
log.trace("Ignoring URI " + request.getRequestURI());
@Override
public void doFilter(final ServletRequest servletRequest, final ServletResponse servletResponse,
final FilterChain filterChain) throws IOException, ServletException {
final HttpServletRequest request = (HttpServletRequest) servletRequest;
final HttpServletResponse response = (HttpServletResponse) servletResponse;
/**
* <p>Workaround for now for the fact that Spring Security will fail since it doesn't call {@link #init(javax.servlet.FilterConfig)}.</p>
* <p>Ultimately we need to allow deployers to actually inject their fully-initialized {@link org.jasig.cas.client.session.SingleSignOutHandler}.</p>
*/
if (!this.handlerInitialized.getAndSet(true)) {
HANDLER.init();
}
filterChain.doFilter(servletRequest, servletResponse);
if (HANDLER.process(request, response)) {
filterChain.doFilter(servletRequest, servletResponse);
}
}
@Override
public void destroy() {
// nothing to do
}
protected static SingleSignOutHandler getSingleSignOutHandler() {
return handler;
return HANDLER;
}
}

View File

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

View File

@ -1,22 +1,21 @@
/**
* Licensed to Jasig under one or more contributor license
* Licensed to Apereo 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,
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at:
* 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
* 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
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jasig.cas.client.session;
import javax.servlet.http.HttpSession;
@ -35,16 +34,18 @@ import javax.servlet.http.HttpSessionListener;
*/
public final class SingleSignOutHttpSessionListener implements HttpSessionListener {
private SessionMappingStorage sessionMappingStorage;
private SessionMappingStorage sessionMappingStorage;
@Override
public void sessionCreated(final HttpSessionEvent event) {
// nothing to do at the moment
}
@Override
public void sessionDestroyed(final HttpSessionEvent event) {
if (sessionMappingStorage == null) {
sessionMappingStorage = getSessionMappingStorage();
}
if (sessionMappingStorage == null) {
sessionMappingStorage = getSessionMappingStorage();
}
final HttpSession session = event.getSession();
sessionMappingStorage.removeBySessionById(session.getId());
}
@ -56,6 +57,6 @@ public final class SingleSignOutHttpSessionListener implements HttpSessionListen
* @return the SessionMappingStorage
*/
protected static SessionMappingStorage getSessionMappingStorage() {
return SingleSignOutFilter.getSingleSignOutHandler().getSessionMappingStorage();
return SingleSignOutFilter.getSingleSignOutHandler().getSessionMappingStorage();
}
}

View File

@ -1,22 +1,21 @@
/**
* Licensed to Jasig under one or more contributor license
* Licensed to Apereo 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,
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at:
* 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
* 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
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jasig.cas.client.ssl;
import javax.net.ssl.HostnameVerifier;
@ -33,6 +32,7 @@ import javax.net.ssl.SSLSession;
public final class AnyHostnameVerifier implements HostnameVerifier {
/** {@inheritDoc} */
@Override
public boolean verify(final String hostname, final SSLSession session) {
return true;
}

View File

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

View File

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

View File

@ -1,25 +1,25 @@
/**
* Licensed to Jasig under one or more contributor license
* Licensed to Apereo 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,
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at:
* 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
* 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
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jasig.cas.client.ssl;
import java.io.Serializable;
import java.util.regex.Pattern;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLSession;
@ -32,12 +32,13 @@ import javax.net.ssl.SSLSession;
* @since 3.1.10
*
*/
public final class RegexHostnameVerifier implements HostnameVerifier {
public final class RegexHostnameVerifier implements HostnameVerifier, Serializable {
private static final long serialVersionUID = 1L;
/** Allowed hostname pattern */
private Pattern pattern;
private final Pattern pattern;
/**
* Creates a new instance using the given regular expression.
*
@ -47,8 +48,8 @@ public final class RegexHostnameVerifier implements HostnameVerifier {
this.pattern = Pattern.compile(regex);
}
/** {@inheritDoc} */
@Override
public boolean verify(final String hostname, final SSLSession session) {
return pattern.matcher(hostname).matches();
}

View File

@ -1,26 +1,26 @@
/**
* Licensed to Jasig under one or more contributor license
* Licensed to Apereo 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,
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at:
* 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
* 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
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jasig.cas.client.ssl;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLSession;
import java.io.Serializable;
/**
* Verifies a SSL peer host name based on an explicit whitelist of allowed hosts.
@ -30,11 +30,12 @@ import javax.net.ssl.SSLSession;
* @since 3.1.10
*
*/
public final class WhitelistHostnameVerifier implements HostnameVerifier {
public final class WhitelistHostnameVerifier implements HostnameVerifier, Serializable {
private static final long serialVersionUID = 1L;
/** Allowed hosts */
private String[] allowedHosts;
private final String[] allowedHosts;
/**
* Creates a new instance using the given array of allowed hosts.
@ -45,7 +46,6 @@ public final class WhitelistHostnameVerifier implements HostnameVerifier {
this.allowedHosts = allowed;
}
/**
* Creates a new instance using the given list of allowed hosts.
*
@ -56,6 +56,7 @@ public final class WhitelistHostnameVerifier implements HostnameVerifier {
}
/** {@inheritDoc} */
@Override
public boolean verify(final String hostname, final SSLSession session) {
for (final String allowedHost : this.allowedHosts) {

View File

@ -1,31 +1,31 @@
/**
* Licensed to Jasig under one or more contributor license
* Licensed to Apereo 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,
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at:
* 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
* 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
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jasig.cas.client.util;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jasig.cas.client.Protocol;
import org.jasig.cas.client.configuration.ConfigurationKeys;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Arrays;
/**
* Abstract filter that contains code that is common to all CAS filters.
@ -38,23 +38,16 @@ import javax.servlet.http.HttpServletResponse;
* <p>Please note that one of the two above parameters must be set.</p>
*
* @author Scott Battaglia
* @version $Revision$ $Date$
* @author Misagh Moayyed
* @since 3.1
*/
public abstract class AbstractCasFilter extends AbstractConfigurationFilter {
/** Represents the constant for where the assertion will be located in memory. */
public static final String CONST_CAS_ASSERTION = "_const_cas_assertion_";
/** Instance of commons logging for logging purposes. */
protected final Log log = LogFactory.getLog(getClass());
private final Protocol protocol;
/** Defines the parameter to look for for the artifact. */
private String artifactParameterName = "ticket";
/** Defines the parameter to look for for the service. */
private String serviceParameterName = "service";
/** Sets where response.encodeUrl should be called on service urls when constructed. */
private boolean encodeServiceUrl = true;
@ -66,24 +59,24 @@ public abstract class AbstractCasFilter extends AbstractConfigurationFilter {
/** The exact url of the service. */
private String service;
public final void init(final FilterConfig filterConfig) throws ServletException {
if (!isIgnoreInitConfiguration()) {
setServerName(getPropertyFromInitParams(filterConfig, "serverName", null));
log.trace("Loading serverName property: " + this.serverName);
setService(getPropertyFromInitParams(filterConfig, "service", null));
log.trace("Loading service property: " + this.service);
setArtifactParameterName(getPropertyFromInitParams(filterConfig, "artifactParameterName", "ticket"));
log.trace("Loading artifact parameter name property: " + this.artifactParameterName);
setServiceParameterName(getPropertyFromInitParams(filterConfig, "serviceParameterName", "service"));
log.trace("Loading serviceParameterName property: " + this.serviceParameterName);
setEncodeServiceUrl(parseBoolean(getPropertyFromInitParams(filterConfig, "encodeServiceUrl", "true")));
log.trace("Loading encodeServiceUrl property: " + this.encodeServiceUrl);
protected AbstractCasFilter(final Protocol protocol) {
this.protocol = protocol;
}
@Override
public final void init(final FilterConfig filterConfig) throws ServletException {
super.init(filterConfig);
if (!isIgnoreInitConfiguration()) {
setServerName(getString(ConfigurationKeys.SERVER_NAME));
setService(getString(ConfigurationKeys.SERVICE));
setEncodeServiceUrl(getBoolean(ConfigurationKeys.ENCODE_SERVICE_URL));
initInternal(filterConfig);
}
init();
}
/** Controls the ordering of filter initialization and checking by defining a method that runs before the init.
* @param filterConfig the original filter configuration.
* @throws ServletException if there is a problem.
@ -98,19 +91,22 @@ public abstract class AbstractCasFilter extends AbstractConfigurationFilter {
* afterPropertiesSet();
*/
public void init() {
CommonUtils.assertNotNull(this.artifactParameterName, "artifactParameterName cannot be null.");
CommonUtils.assertNotNull(this.serviceParameterName, "serviceParameterName cannot be null.");
CommonUtils.assertTrue(CommonUtils.isNotEmpty(this.serverName) || CommonUtils.isNotEmpty(this.service), "serverName or service must be set.");
CommonUtils.assertTrue(CommonUtils.isBlank(this.serverName) || CommonUtils.isBlank(this.service), "serverName and service cannot both be set. You MUST ONLY set one.");
CommonUtils.assertTrue(CommonUtils.isNotEmpty(this.serverName) || CommonUtils.isNotEmpty(this.service),
"serverName or service must be set.");
CommonUtils.assertTrue(CommonUtils.isBlank(this.serverName) || CommonUtils.isBlank(this.service),
"serverName and service cannot both be set. You MUST ONLY set one.");
}
// empty implementation as most filters won't need this.
@Override
public void destroy() {
// nothing to do
}
protected final String constructServiceUrl(final HttpServletRequest request, final HttpServletResponse response) {
return CommonUtils.constructServiceUrl(request, response, this.service, this.serverName, this.artifactParameterName, this.encodeServiceUrl);
return CommonUtils.constructServiceUrl(request, response, this.service, this.serverName,
this.protocol.getServiceParameterName(),
this.protocol.getArtifactParameterName(), this.encodeServiceUrl);
}
/**
@ -121,8 +117,8 @@ public abstract class AbstractCasFilter extends AbstractConfigurationFilter {
*/
public final void setServerName(final String serverName) {
if (serverName != null && serverName.endsWith("/")) {
this.serverName = serverName.substring(0, serverName.length()-1);
log.info(String.format("Eliminated extra slash from serverName [%s]. It is now [%s]", serverName, this.serverName));
this.serverName = serverName.substring(0, serverName.length() - 1);
logger.info("Eliminated extra slash from serverName [{}]. It is now [{}]", serverName, this.serverName);
} else {
this.serverName = serverName;
}
@ -132,23 +128,22 @@ public abstract class AbstractCasFilter extends AbstractConfigurationFilter {
this.service = service;
}
public final void setArtifactParameterName(final String artifactParameterName) {
this.artifactParameterName = artifactParameterName;
}
public final void setServiceParameterName(final String serviceParameterName) {
this.serviceParameterName = serviceParameterName;
}
public final void setEncodeServiceUrl(final boolean encodeServiceUrl) {
this.encodeServiceUrl = encodeServiceUrl;
this.encodeServiceUrl = encodeServiceUrl;
}
public final String getArtifactParameterName() {
return this.artifactParameterName;
protected Protocol getProtocol() {
return this.protocol;
}
public final String getServiceParameterName() {
return this.serviceParameterName;
/**
* Template method to allow you to change how you retrieve the ticket.
*
* @param request the HTTP ServletRequest. CANNOT be NULL.
* @return the ticket if its found, null otherwise.
*/
protected String retrieveTicketFromRequest(final HttpServletRequest request) {
return CommonUtils.safeGetParameter(request, this.protocol.getArtifactParameterName(),
Arrays.asList(this.protocol.getArtifactParameterName()));
}
}

View File

@ -1,31 +1,32 @@
/**
* Licensed to Jasig under one or more contributor license
* Licensed to Apereo 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,
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at:
* 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
* 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
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jasig.cas.client.util;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.servlet.Filter;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jasig.cas.client.configuration.ConfigurationKey;
import org.jasig.cas.client.configuration.ConfigurationStrategy;
import org.jasig.cas.client.configuration.ConfigurationStrategyName;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Abstracts out the ability to configure the filters from the initial properties provided.
@ -35,90 +36,43 @@ import org.apache.commons.logging.LogFactory;
* @since 3.1
*/
public abstract class AbstractConfigurationFilter implements Filter {
protected final Log log = LogFactory.getLog(getClass());
private static final String CONFIGURATION_STRATEGY_KEY = "configurationStrategy";
protected final Logger logger = LoggerFactory.getLogger(getClass());
private boolean ignoreInitConfiguration = false;
/**
* Retrieves the property from the FilterConfig. First it checks the FilterConfig's initParameters to see if it
* has a value.
* If it does, it returns that, otherwise it retrieves the ServletContext's initParameters and returns that value if any.
* <p>
* Finally, it will check JNDI if all other methods fail. All the JNDI properties should be stored under either java:comp/env/cas/SHORTFILTERNAME/{propertyName}
* or java:comp/env/cas/{propertyName}
* <p>
* Essentially the documented order is:
* <ol>
* <li>FilterConfig.getInitParameter</li>
* <li>ServletContext.getInitParameter</li>
* <li>java:comp/env/cas/SHORTFILTERNAME/{propertyName}</li>
* <li>java:comp/env/cas/{propertyName}</li>
* <li>Default Value</li>
* </ol>
*
*
* @param filterConfig the Filter Configuration.
* @param propertyName the property to retrieve.
* @param defaultValue the default value if the property is not found.
* @return the property value, following the above conventions. It will always return the more specific value (i.e.
* filter vs. context).
*/
protected final String getPropertyFromInitParams(final FilterConfig filterConfig, final String propertyName, final String defaultValue) {
final String value = filterConfig.getInitParameter(propertyName);
private ConfigurationStrategy configurationStrategy;
if (CommonUtils.isNotBlank(value)) {
log.info("Property [" + propertyName + "] loaded from FilterConfig.getInitParameter with value [" + value + "]");
return value;
}
final String value2 = filterConfig.getServletContext().getInitParameter(propertyName);
if (CommonUtils.isNotBlank(value2)) {
log.info("Property [" + propertyName + "] loaded from ServletContext.getInitParameter with value [" + value2 + "]");
return value2;
}
InitialContext context;
try {
context = new InitialContext();
} catch (final NamingException e) {
log.warn(e,e);
return defaultValue;
}
final String shortName = this.getClass().getName().substring(this.getClass().getName().lastIndexOf(".")+1);
final String value3 = loadFromContext(context, "java:comp/env/cas/" + shortName + "/" + propertyName);
if (CommonUtils.isNotBlank(value3)) {
log.info("Property [" + propertyName + "] loaded from JNDI Filter Specific Property with value [" + value3 + "]");
return value3;
}
final String value4 = loadFromContext(context, "java:comp/env/cas/" + propertyName);
if (CommonUtils.isNotBlank(value4)) {
log.info("Property [" + propertyName + "] loaded from JNDI with value [" + value4 + "]");
return value4;
}
log.info("Property [" + propertyName + "] not found. Using default value [" + defaultValue + "]");
return defaultValue;
}
protected final boolean parseBoolean(final String value) {
return ((value != null) && value.equalsIgnoreCase("true"));
}
protected final String loadFromContext(final InitialContext context, final String path) {
try {
return (String) context.lookup(path);
} catch (final NamingException e) {
return null;
}
@Override
public void init(final FilterConfig filterConfig) throws ServletException {
final String configurationStrategyName = filterConfig.getServletContext().getInitParameter(CONFIGURATION_STRATEGY_KEY);
this.configurationStrategy = ReflectUtils.newInstance(ConfigurationStrategyName.resolveToConfigurationStrategy(configurationStrategyName));
this.configurationStrategy.init(filterConfig, getClass());
}
public final void setIgnoreInitConfiguration(boolean ignoreInitConfiguration) {
protected final boolean getBoolean(final ConfigurationKey<Boolean> configurationKey) {
return this.configurationStrategy.getBoolean(configurationKey);
}
protected final String getString(final ConfigurationKey<String> configurationKey) {
return this.configurationStrategy.getString(configurationKey);
}
protected final long getLong(final ConfigurationKey<Long> configurationKey) {
return this.configurationStrategy.getLong(configurationKey);
}
protected final int getInt(final ConfigurationKey<Integer> configurationKey) {
return this.configurationStrategy.getInt(configurationKey);
}
protected final <T> Class<? extends T> getClass(final ConfigurationKey<Class<? extends T>> configurationKey) {
return this.configurationStrategy.getClass(configurationKey);
}
public final void setIgnoreInitConfiguration(final boolean ignoreInitConfiguration) {
this.ignoreInitConfiguration = ignoreInitConfiguration;
}

View File

@ -1,22 +1,21 @@
/**
* Licensed to Jasig under one or more contributor license
* Licensed to Apereo 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,
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at:
* 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
* 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
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jasig.cas.client.util;
import org.jasig.cas.client.validation.Assertion;
@ -25,7 +24,6 @@ import org.jasig.cas.client.validation.Assertion;
* Static holder that places Assertion in a ThreadLocal.
*
* @author Scott Battaglia
* @version $Revision: 11728 $ $Date: 2007-09-26 14:20:43 -0400 (Tue, 26 Sep 2007) $
* @since 3.0
*/
public class AssertionHolder {
@ -35,7 +33,6 @@ public class AssertionHolder {
*/
private static final ThreadLocal<Assertion> threadLocal = new ThreadLocal<Assertion>();
/**
* Retrieve the assertion from the ThreadLocal.
*

View File

@ -1,53 +1,50 @@
/**
* Licensed to Jasig under one or more contributor license
* Licensed to Apereo 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,
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at:
* 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
* 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
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jasig.cas.client.util;
import org.jasig.cas.client.validation.Assertion;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import java.io.IOException;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import org.jasig.cas.client.validation.Assertion;
/**
* Places the assertion in a ThreadLocal such that other resources can access it that do not have access to the web tier session.
*
* @author Scott Battaglia
* @version $Revision: 11728 $ $Date: 2007-09-26 14:20:43 -0400 (Tue, 26 Sep 2007) $
* @since 3.0
*/
public final class AssertionThreadLocalFilter implements Filter {
@Override
public void init(final FilterConfig filterConfig) throws ServletException {
// nothing to do here
}
public void doFilter(final ServletRequest servletRequest, final ServletResponse servletResponse, final FilterChain filterChain) throws IOException, ServletException {
@Override
public void doFilter(final ServletRequest servletRequest, final ServletResponse servletResponse,
final FilterChain filterChain) throws IOException, ServletException {
final HttpServletRequest request = (HttpServletRequest) servletRequest;
final HttpSession session = request.getSession(false);
final Assertion assertion = (Assertion) (session == null ? request.getAttribute(AbstractCasFilter.CONST_CAS_ASSERTION) : session.getAttribute(AbstractCasFilter.CONST_CAS_ASSERTION));
final Assertion assertion = (Assertion) (session == null ? request
.getAttribute(AbstractCasFilter.CONST_CAS_ASSERTION) : session
.getAttribute(AbstractCasFilter.CONST_CAS_ASSERTION));
try {
AssertionHolder.setAssertion(assertion);
@ -57,6 +54,7 @@ public final class AssertionThreadLocalFilter implements Filter {
}
}
@Override
public void destroy() {
// nothing to do
}

View File

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

View File

@ -1,36 +1,29 @@
/**
* Licensed to Jasig under one or more contributor license
* Licensed to Apereo 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,
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at:
* 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
* 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
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jasig.cas.client.util;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.Map;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* A Delegating Filter looks up a parameter in the request object and matches
@ -38,7 +31,6 @@ import java.util.Map;
* the associated filter is executed. Otherwise, the normal chain is executed.
*
* @author Scott Battaglia
* @version $Revision: 11729 $ $Date: 2006-09-26 14:22:30 -0400 (Tue, 26 Sep 2006) $
* @since 3.0
*/
public final class DelegatingFilter implements Filter {
@ -46,7 +38,7 @@ public final class DelegatingFilter implements Filter {
/**
* Instance of Commons Logging.
*/
private final Log log = LogFactory.getLog(this.getClass());
private final Logger logger = LoggerFactory.getLogger(this.getClass());
/**
* The request parameter to look for in the Request object.
@ -56,7 +48,7 @@ public final class DelegatingFilter implements Filter {
/**
* The map of filters to delegate to and the criteria (as key).
*/
private final Map<String,Filter> delegators;
private final Map<String, Filter> delegators;
/**
* The default filter to use if there is no match.
@ -69,11 +61,13 @@ public final class DelegatingFilter implements Filter {
*/
private final boolean exactMatch;
public DelegatingFilter(final String requestParameterName, final Map<String,Filter> delegators, final boolean exactMatch) {
public DelegatingFilter(final String requestParameterName, final Map<String, Filter> delegators,
final boolean exactMatch) {
this(requestParameterName, delegators, exactMatch, null);
}
public DelegatingFilter(final String requestParameterName, final Map<String,Filter> delegators, final boolean exactMatch, final Filter defaultFilter) {
public DelegatingFilter(final String requestParameterName, final Map<String, Filter> delegators,
final boolean exactMatch, final Filter defaultFilter) {
CommonUtils.assertNotNull(requestParameterName, "requestParameterName cannot be null.");
CommonUtils.assertTrue(!delegators.isEmpty(), "delegators cannot be empty.");
@ -83,11 +77,14 @@ public final class DelegatingFilter implements Filter {
this.exactMatch = exactMatch;
}
@Override
public void destroy() {
// nothing to do here
}
public void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain filterChain) throws IOException, ServletException {
@Override
public void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain filterChain)
throws IOException, ServletException {
final String parameter = CommonUtils.safeGetParameter((HttpServletRequest) request, this.requestParameterName);
@ -95,19 +92,15 @@ public final class DelegatingFilter implements Filter {
for (final String key : this.delegators.keySet()) {
if ((parameter.equals(key) && this.exactMatch) || (parameter.matches(key) && !this.exactMatch)) {
final Filter filter = this.delegators.get(key);
if (log.isDebugEnabled()) {
log.debug("Match found for parameter ["
+ this.requestParameterName + "] with value ["
+ parameter + "]. Delegating to filter ["
+ filter.getClass().getName() + "]");
}
logger.debug("Match found for parameter [{}] with value [{}]. Delegating to filter [{}]",
this.requestParameterName, parameter, filter.getClass().getName());
filter.doFilter(request, response, filterChain);
return;
}
}
}
log.debug("No match found for parameter [" + this.requestParameterName + "] with value [" + parameter + "]");
logger.debug("No match found for parameter [{}] with value [{}]", this.requestParameterName, parameter);
if (this.defaultFilter != null) {
this.defaultFilter.doFilter(request, response, filterChain);
@ -116,6 +109,7 @@ public final class DelegatingFilter implements Filter {
}
}
@Override
public void init(final FilterConfig filterConfig) throws ServletException {
// nothing to do here.
}

View File

@ -1,128 +1,139 @@
/**
* Licensed to Jasig under one or more contributor license
* Licensed to Apereo 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,
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at:
* 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
* 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
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jasig.cas.client.util;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.*;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Filters that redirects to the supplied url based on an exception. Exceptions and the urls are configured via
* init filter name/param values.
* <p>
* <p/>
* If there is an exact match the filter uses that value. If there's a non-exact match (i.e. inheritance), then the filter
* uses the last value that matched.
* <p>
* <p/>
* If there is no match it will redirect to a default error page. The default exception is configured via the "defaultErrorRedirectPage" property.
*
*
* @author Scott Battaglia
* @version $Revision$ $Date$
* @since 3.1.4
*
*/
public final class ErrorRedirectFilter implements Filter {
private final Log log = LogFactory.getLog(getClass());
private final List<ErrorHolder> errors = new ArrayList<ErrorHolder>();
private String defaultErrorRedirectPage;
public void destroy() {
// nothing to do here
}
private final Logger logger = LoggerFactory.getLogger(getClass());
public void doFilter(final ServletRequest request, final ServletResponse response,
final FilterChain filterChain) throws IOException, ServletException {
final HttpServletResponse httpResponse = (HttpServletResponse) response;
try {
filterChain.doFilter(request, response);
} catch (final ServletException e) {
final Throwable t = e.getCause();
ErrorHolder currentMatch = null;
private final List<ErrorHolder> errors = new ArrayList<ErrorHolder>();
private String defaultErrorRedirectPage;
@Override
public void destroy() {
// nothing to do here
}
@Override
public void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain filterChain)
throws IOException, ServletException {
final HttpServletResponse httpResponse = (HttpServletResponse) response;
try {
filterChain.doFilter(request, response);
} catch (final Exception e) {
final Throwable t = extractErrorToCompare(e);
ErrorHolder currentMatch = null;
for (final ErrorHolder errorHolder : this.errors) {
if (errorHolder.exactMatch(t)) {
currentMatch = errorHolder;
break;
} else if (errorHolder.inheritanceMatch(t)) {
currentMatch = errorHolder;
}
}
if (currentMatch != null) {
httpResponse.sendRedirect(currentMatch.getUrl());
} else {
httpResponse.sendRedirect(defaultErrorRedirectPage);
}
}
}
if (errorHolder.exactMatch(t)) {
currentMatch = errorHolder;
break;
} else if (errorHolder.inheritanceMatch(t)) {
currentMatch = errorHolder;
}
}
public void init(final FilterConfig filterConfig) throws ServletException {
this.defaultErrorRedirectPage = filterConfig.getInitParameter("defaultErrorRedirectPage");
final Enumeration<?> enumeration = filterConfig.getInitParameterNames();
while (enumeration.hasMoreElements()) {
final String className = (String) enumeration.nextElement();
try {
if (!className.equals("defaultErrorRedirectPage")) {
this.errors.add(new ErrorHolder(className, filterConfig.getInitParameter(className)));
}
} catch (final ClassNotFoundException e) {
log.warn("Class [" + className + "] cannot be found in ClassLoader. Ignoring.");
}
}
}
protected final class ErrorHolder {
private Class<?> className;
private String url;
protected ErrorHolder(final String className, final String url) throws ClassNotFoundException {
this.className = Class.forName(className);
this.url = url;
}
public boolean exactMatch(final Throwable e) {
return this.className.equals(e.getClass());
}
public boolean inheritanceMatch(final Throwable e) {
return className.isAssignableFrom(e.getClass());
}
public String getUrl() {
return this.url;
}
}
if (currentMatch != null) {
httpResponse.sendRedirect(currentMatch.getUrl());
} else {
httpResponse.sendRedirect(defaultErrorRedirectPage);
}
}
}
/**
* Determine which error to use for comparison. If there is an {@link Throwable#getCause()} then that will be used. Otherwise, the original throwable is used.
*
* @param throwable the throwable to look for a root cause.
* @return the throwable to use for comparison. MUST NOT BE NULL.
*/
private Throwable extractErrorToCompare(final Throwable throwable) {
final Throwable cause = throwable.getCause();
if (cause != null) {
return cause;
}
return throwable;
}
@Override
public void init(final FilterConfig filterConfig) throws ServletException {
this.defaultErrorRedirectPage = filterConfig.getInitParameter("defaultErrorRedirectPage");
final Enumeration<?> enumeration = filterConfig.getInitParameterNames();
while (enumeration.hasMoreElements()) {
final String className = (String) enumeration.nextElement();
try {
if (!className.equals("defaultErrorRedirectPage")) {
this.errors.add(new ErrorHolder(className, filterConfig.getInitParameter(className)));
}
} catch (final ClassNotFoundException e) {
logger.warn("Class [{}] cannot be found in ClassLoader. Ignoring.", className);
}
}
}
protected final class ErrorHolder {
private Class<?> className;
private String url;
protected ErrorHolder(final String className, final String url) throws ClassNotFoundException {
this.className = Class.forName(className);
this.url = url;
}
public boolean exactMatch(final Throwable e) {
return this.className.equals(e.getClass());
}
public boolean inheritanceMatch(final Throwable e) {
return className.isAssignableFrom(e.getClass());
}
public String getUrl() {
return this.url;
}
}
}

View File

@ -1,38 +1,33 @@
/**
* Licensed to Jasig under one or more contributor license
* Licensed to Apereo 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,
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at:
* 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
* 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
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jasig.cas.client.util;
import org.jasig.cas.client.authentication.AttributePrincipal;
import org.jasig.cas.client.validation.Assertion;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.security.Principal;
import java.util.Collection;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpSession;
import org.jasig.cas.client.authentication.AttributePrincipal;
import org.jasig.cas.client.configuration.ConfigurationKeys;
import org.jasig.cas.client.validation.Assertion;
/**
* Implementation of a filter that wraps the normal HttpServletRequest with a
@ -49,17 +44,17 @@ import java.util.Collection;
*
* @author Scott Battaglia
* @author Marvin S. Addison
* @version $Revision: 11729 $ $Date: 2007-09-26 14:22:30 -0400 (Tue, 26 Sep 2007) $
* @since 3.0
*/
public final class HttpServletRequestWrapperFilter extends AbstractConfigurationFilter {
/** Name of the attribute used to answer role membership queries */
private String roleAttribute;
/** Whether or not to ignore case in role membership queries */
private boolean ignoreCase;
@Override
public void destroy() {
// nothing to do
}
@ -69,23 +64,30 @@ public final class HttpServletRequestWrapperFilter extends AbstractConfiguration
* <code>request.getRemoteUser</code> to the underlying Assertion object
* stored in the user session.
*/
public void doFilter(final ServletRequest servletRequest, final ServletResponse servletResponse, final FilterChain filterChain) throws IOException, ServletException {
@Override
public void doFilter(final ServletRequest servletRequest, final ServletResponse servletResponse,
final FilterChain filterChain) throws IOException, ServletException {
final AttributePrincipal principal = retrievePrincipalFromSessionOrRequest(servletRequest);
filterChain.doFilter(new CasHttpServletRequestWrapper((HttpServletRequest) servletRequest, principal), servletResponse);
filterChain.doFilter(new CasHttpServletRequestWrapper((HttpServletRequest) servletRequest, principal),
servletResponse);
}
protected AttributePrincipal retrievePrincipalFromSessionOrRequest(final ServletRequest servletRequest) {
final HttpServletRequest request = (HttpServletRequest) servletRequest;
final HttpSession session = request.getSession(false);
final Assertion assertion = (Assertion) (session == null ? request.getAttribute(AbstractCasFilter.CONST_CAS_ASSERTION) : session.getAttribute(AbstractCasFilter.CONST_CAS_ASSERTION));
final Assertion assertion = (Assertion) (session == null ? request
.getAttribute(AbstractCasFilter.CONST_CAS_ASSERTION) : session
.getAttribute(AbstractCasFilter.CONST_CAS_ASSERTION));
return assertion == null ? null : assertion.getPrincipal();
}
@Override
public void init(final FilterConfig filterConfig) throws ServletException {
this.roleAttribute = getPropertyFromInitParams(filterConfig, "roleAttribute", null);
this.ignoreCase = Boolean.parseBoolean(getPropertyFromInitParams(filterConfig, "ignoreCase", "false"));
super.init(filterConfig);
this.roleAttribute = getString(ConfigurationKeys.ROLE_ATTRIBUTE);
this.ignoreCase = getBoolean(ConfigurationKeys.IGNORE_CASE);
}
final class CasHttpServletRequestWrapper extends HttpServletRequestWrapper {
@ -97,46 +99,49 @@ public final class HttpServletRequestWrapperFilter extends AbstractConfiguration
this.principal = principal;
}
@Override
public Principal getUserPrincipal() {
return this.principal;
}
@Override
public String getRemoteUser() {
return principal != null ? this.principal.getName() : null;
}
@Override
public boolean isUserInRole(final String role) {
if (CommonUtils.isBlank(role)) {
log.debug("No valid role provided. Returning false.");
logger.debug("No valid role provided. Returning false.");
return false;
}
if (this.principal == null) {
log.debug("No Principal in Request. Returning false.");
logger.debug("No Principal in Request. Returning false.");
return false;
}
if (CommonUtils.isBlank(roleAttribute)) {
log.debug("No Role Attribute Configured. Returning false.");
logger.debug("No Role Attribute Configured. Returning false.");
return false;
}
final Object value = this.principal.getAttributes().get(roleAttribute);
if (value instanceof Collection<?>) {
for (final Object o : (Collection<?>) value) {
if (rolesEqual(role, o)) {
log.debug("User [" + getRemoteUser() + "] is in role [" + role + "]: " + true);
logger.debug("User [{}] is in role [{}]: true", getRemoteUser(), role);
return true;
}
}
}
final boolean isMember = rolesEqual(role, value);
log.debug("User [" + getRemoteUser() + "] is in role [" + role + "]: " + isMember);
logger.debug("User [{}] is in role [{}]: {}", getRemoteUser(), role, isMember);
return isMember;
}
/**
* Determines whether the given role is equal to the candidate
* role attribute taking into account case sensitivity.

View File

@ -0,0 +1,92 @@
/**
* Licensed to Apereo under one or more contributor license
* agreements. See the NOTICE file distributed with this work
* for additional information regarding copyright ownership.
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at the following location:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jasig.cas.client.util;
import java.io.*;
import java.nio.CharBuffer;
import java.nio.charset.Charset;
/**
* IO utility class.
*
* @author Marvin S. Addison
* @since 3.4
*/
public final class IOUtils {
/** UTF-8 character set. */
public static final Charset UTF8 = Charset.forName("UTF-8");
private IOUtils() { /** Utility class pattern. */ }
/**
* Reads all data from the given stream as UTF-8 character data and closes it on completion or errors.
*
* @param in Input stream containing character data.
*
* @return String of all data in stream.
*
* @throws IOException On IO errors.
*/
public static String readString(final InputStream in) throws IOException {
return readString(in, UTF8);
}
/**
* Reads all data from the given stream as character data in the given character set and closes it on completion
* or errors.
*
* @param in Input stream containing character data.
* @param charset Character set of data in stream.
*
* @return String of all data in stream.
*
* @throws IOException On IO errors.
*/
public static String readString(final InputStream in, final Charset charset) throws IOException {
final Reader reader = new InputStreamReader(in, charset);
final StringBuilder builder = new StringBuilder();
final CharBuffer buffer = CharBuffer.allocate(2048);
try {
while (reader.read(buffer) > -1) {
buffer.flip();
builder.append(buffer);
}
} finally {
closeQuietly(reader);
}
return builder.toString();
}
/**
* Unconditionally close a {@link Closeable} resource. Errors on close are ignored.
*
* @param resource Resource to close.
*/
public static void closeQuietly(final Closeable resource) {
try {
if (resource != null) {
resource.close();
}
} catch (final IOException e) {
//ignore
}
}
}

View File

@ -0,0 +1,83 @@
/**
* Licensed to Apereo under one or more contributor license
* agreements. See the NOTICE file distributed with this work
* for additional information regarding copyright ownership.
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at the following location:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jasig.cas.client.util;
import javax.xml.namespace.NamespaceContext;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
/**
* Namespace context implementation backed by a map of XML prefixes to namespace URIs.
*
* @author Marvin S. Addison
* @since 3.4
*/
public class MapNamespaceContext implements NamespaceContext {
private final Map<String, String> namespaceMap;
/**
* Creates a new instance from an array of namespace delcarations.
*
* @param namespaceDeclarations An array of namespace declarations of the form prefix->uri.
*/
public MapNamespaceContext(final String ... namespaceDeclarations) {
namespaceMap = new HashMap<String, String>();
int index;
String key;
String value;
for (final String decl : namespaceDeclarations) {
index = decl.indexOf('-');
key = decl.substring(0, index);
value = decl.substring(index + 2);
namespaceMap.put(key, value);
}
}
/**
* Creates a new instance from a map.
*
* @param namespaceMap Map of XML namespace prefixes (keys) to URIs (values).
*/
public MapNamespaceContext(final Map<String, String> namespaceMap) {
this.namespaceMap = namespaceMap;
}
@Override
public String getNamespaceURI(final String prefix) {
return namespaceMap.get(prefix);
}
@Override
public String getPrefix(final String namespaceURI) {
for (final Map.Entry<String, String> entry : namespaceMap.entrySet()) {
if (entry.getValue().equalsIgnoreCase(namespaceURI)) {
return entry.getKey();
}
}
return null;
}
@Override
public Iterator getPrefixes(final String namespaceURI) {
return Collections.singleton(getPrefix(namespaceURI)).iterator();
}
}

View File

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

View File

@ -1,28 +1,28 @@
/**
* Licensed to Jasig under one or more contributor license
* Licensed to Apereo 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,
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at:
* 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
* 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
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jasig.cas.client.util;
import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
/**
@ -54,7 +54,6 @@ public final class ReflectUtils {
}
}
/**
* Creates a new instance of the given class by passing the given arguments
* to the constructor.
@ -62,10 +61,10 @@ public final class ReflectUtils {
* @param args Constructor arguments.
* @return New instance of given class.
*/
public static <T> T newInstance(final String className, final Object ... args) {
return newInstance(ReflectUtils.<T>loadClass(className), args);
public static <T> T newInstance(final String className, final Object... args) {
return newInstance(ReflectUtils.<T> loadClass(className), args);
}
/**
* Creates a new instance of the given class by passing the given arguments
* to the constructor.
@ -73,7 +72,7 @@ public final class ReflectUtils {
* @param args Constructor arguments.
* @return New instance of given class.
*/
public static <T> T newInstance(final Class<T> clazz, final Object ... args) {
public static <T> T newInstance(final Class<T> clazz, final Object... args) {
final Class<?>[] argClasses = new Class[args.length];
for (int i = 0; i < args.length; i++) {
argClasses[i] = args[i].getClass();
@ -139,7 +138,8 @@ public final class ReflectUtils {
* @param target Target JavaBean on which to set property.
* @param info BeanInfo describing the target JavaBean.
*/
public static void setProperty(final String propertyName, final Object value, final Object target, final BeanInfo info) {
public static void setProperty(final String propertyName, final Object value, final Object target,
final BeanInfo info) {
try {
final PropertyDescriptor pd = getPropertyDescriptor(info, propertyName);
pd.getWriteMethod().invoke(target, value);
@ -149,4 +149,35 @@ public final class ReflectUtils {
throw new RuntimeException("Error setting property " + propertyName, e);
}
}
/**
* Gets the value of the given declared field on the target object or any of its superclasses.
*
* @param fieldName Name of field to get.
* @param target Target object that possesses field.
*
* @return Field value.
*/
public static Object getField(final String fieldName, final Object target) {
Class<?> clazz = target.getClass();
Field field = null;
do {
try {
field = clazz.getDeclaredField(fieldName);
} catch (final NoSuchFieldException e) {
clazz = clazz.getSuperclass();
}
} while (field == null && clazz != null);
if (field == null) {
throw new IllegalArgumentException(fieldName + " does not exist on " + target);
}
try {
if (!field.isAccessible()) {
field.setAccessible(true);
}
return field.get(target);
} catch (final Exception e) {
throw new IllegalArgumentException("Error getting field " + fieldName, e);
}
}
}

View File

@ -0,0 +1,109 @@
/**
* Licensed to Apereo under one or more contributor license
* agreements. See the NOTICE file distributed with this work
* for additional information regarding copyright ownership.
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at the following location:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jasig.cas.client.util;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import javax.xml.namespace.NamespaceContext;
import javax.xml.namespace.QName;
import javax.xml.xpath.*;
/**
* Thread local XPath expression.
*
* @author Marvin S. Addison
* @since 3.4
*/
public class ThreadLocalXPathExpression extends ThreadLocal<XPathExpression> implements XPathExpression {
/** XPath expression */
private final String expression;
/** Namespace context. */
private final NamespaceContext context;
/**
* Creates a new instance from an XPath expression and namespace context.
*
* @param xPath XPath expression.
* @param context Namespace context for handling namespace prefix to URI mappings.
*/
public ThreadLocalXPathExpression(final String xPath, final NamespaceContext context) {
this.expression = xPath;
this.context = context;
}
@Override
public Object evaluate(final Object o, final QName qName) throws XPathExpressionException {
return get().evaluate(o, qName);
}
@Override
public String evaluate(final Object o) throws XPathExpressionException {
return get().evaluate(o);
}
@Override
public Object evaluate(final InputSource inputSource, final QName qName) throws XPathExpressionException {
return get().evaluate(inputSource, qName);
}
@Override
public String evaluate(final InputSource inputSource) throws XPathExpressionException {
return get().evaluate(inputSource);
}
/**
* Evaluates the XPath expression and returns the result coerced to a string.
*
* @param o Object on which to evaluate the expression; typically a DOM node.
*
* @return Evaluation result as a string.
*
* @throws XPathExpressionException On XPath evaluation errors.
*/
public String evaluateAsString(final Object o) throws XPathExpressionException {
return (String) evaluate(o, XPathConstants.STRING);
}
/**
* Evaluates the XPath expression and returns the result coerced to a node list.
*
* @param o Object on which to evaluate the expression; typically a DOM node.
*
* @return Evaluation result as a node list.
*
* @throws XPathExpressionException On XPath evaluation errors.
*/
public NodeList evaluateAsNodeList(final Object o) throws XPathExpressionException {
return (NodeList) evaluate(o, XPathConstants.NODESET);
}
@Override
protected XPathExpression initialValue() {
try {
final XPath xPath = XPathFactory.newInstance().newXPath();
xPath.setNamespaceContext(context);
return xPath.compile(expression);
} catch (final XPathExpressionException e) {
throw new IllegalArgumentException("Invalid XPath expression");
}
}
}

View File

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

View File

@ -1,42 +1,44 @@
/**
* Licensed to Jasig under one or more contributor license
* Licensed to Apereo 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,
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at:
* 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
* 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
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jasig.cas.client.util;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import java.io.StringReader;
import java.util.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;
import org.xml.sax.helpers.XMLReaderFactory;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.List;
import javax.xml.XMLConstants;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParserFactory;
/**
* Common utilities for easily parsing XML without duplicating logic.
*
* @author Scott Battaglia
* @version $Revision: 11729 $ $Date: 2007-09-26 14:22:30 -0400 (Tue, 26 Sep 2007) $
* @since 3.0
*/
public final class XmlUtils {
@ -44,7 +46,37 @@ public final class XmlUtils {
/**
* Static instance of Commons Logging.
*/
private final static Log LOG = LogFactory.getLog(XmlUtils.class);
private final static Logger LOGGER = LoggerFactory.getLogger(XmlUtils.class);
/**
* Creates a new namespace-aware DOM document object by parsing the given XML.
*
* @param xml XML content.
*
* @return DOM document.
*/
public static Document newDocument(final String xml) {
final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
final Map<String, Boolean> features = new HashMap<String, Boolean>();
features.put(XMLConstants.FEATURE_SECURE_PROCESSING, true);
features.put("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
features.put("http://apache.org/xml/features/disallow-doctype-decl", true);
for (final Map.Entry<String, Boolean> entry : features.entrySet()) {
try {
factory.setFeature(entry.getKey(), entry.getValue());
} catch (final ParserConfigurationException e) {
LOGGER.warn("Failed setting XML feature {}: {}", entry.getKey(), e);
}
}
factory.setExpandEntityReferences(false);
factory.setNamespaceAware(true);
try {
return factory.newDocumentBuilder().parse(new InputSource(new StringReader(xml)));
} catch (final Exception e) {
throw new RuntimeException("XML parsing error: " + e);
}
}
/**
* Get an instance of an XML reader from the XMLReaderFactory.
@ -53,12 +85,20 @@ public final class XmlUtils {
*/
public static XMLReader getXmlReader() {
try {
return XMLReaderFactory.createXMLReader();
} catch (final SAXException e) {
final SAXParserFactory factory = SAXParserFactory.newInstance();
factory.setNamespaceAware(true);
factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
factory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
factory.setFeature("http://xml.org/sax/features/external-general-entities", false);
factory.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
return factory.newSAXParser().getXMLReader();
} catch (final Exception e) {
throw new RuntimeException("Unable to create XMLReader", e);
}
}
/**
* Retrieve the text for a group of elements. Each text element is an entry
* in a list.
@ -68,8 +108,7 @@ public final class XmlUtils {
* @param element the element to look for
* @return the list of text from the elements.
*/
public static List<String> getTextForElements(final String xmlAsString,
final String element) {
public static List<String> getTextForElements(final String xmlAsString, final String element) {
final List<String> elements = new ArrayList<String>(2);
final XMLReader reader = getXmlReader();
@ -79,16 +118,16 @@ public final class XmlUtils {
private StringBuilder buffer = new StringBuilder();
public void startElement(final String uri, final String localName,
final String qName, final Attributes attributes)
throws SAXException {
@Override
public void startElement(final String uri, final String localName, final String qName,
final Attributes attributes) throws SAXException {
if (localName.equals(element)) {
this.foundElement = true;
}
}
public void endElement(final String uri, final String localName,
final String qName) throws SAXException {
@Override
public void endElement(final String uri, final String localName, final String qName) throws SAXException {
if (localName.equals(element)) {
this.foundElement = false;
elements.add(this.buffer.toString());
@ -96,8 +135,8 @@ public final class XmlUtils {
}
}
public void characters(char[] ch, int start, int length)
throws SAXException {
@Override
public void characters(final char[] ch, final int start, final int length) throws SAXException {
if (this.foundElement) {
this.buffer.append(ch, start, length);
}
@ -110,7 +149,7 @@ public final class XmlUtils {
try {
reader.parse(new InputSource(new StringReader(xmlAsString)));
} catch (final Exception e) {
LOG.error(e, e);
LOGGER.error(e.getMessage(), e);
return null;
}
@ -125,8 +164,7 @@ public final class XmlUtils {
* @param element the element to look for
* @return the text value of the element.
*/
public static String getTextForElement(final String xmlAsString,
final String element) {
public static String getTextForElement(final String xmlAsString, final String element) {
final XMLReader reader = getXmlReader();
final StringBuilder builder = new StringBuilder();
@ -134,23 +172,23 @@ public final class XmlUtils {
private boolean foundElement = false;
public void startElement(final String uri, final String localName,
final String qName, final Attributes attributes)
throws SAXException {
@Override
public void startElement(final String uri, final String localName, final String qName,
final Attributes attributes) throws SAXException {
if (localName.equals(element)) {
this.foundElement = true;
}
}
public void endElement(final String uri, final String localName,
final String qName) throws SAXException {
@Override
public void endElement(final String uri, final String localName, final String qName) throws SAXException {
if (localName.equals(element)) {
this.foundElement = false;
}
}
public void characters(char[] ch, int start, int length)
throws SAXException {
@Override
public void characters(final char[] ch, final int start, final int length) throws SAXException {
if (this.foundElement) {
builder.append(ch, start, length);
}
@ -163,7 +201,7 @@ public final class XmlUtils {
try {
reader.parse(new InputSource(new StringReader(xmlAsString)));
} catch (final Exception e) {
LOG.error(e, e);
LOGGER.error(e.getMessage(), e);
return null;
}

View File

@ -1,24 +1,23 @@
<!--
Licensed to Jasig under one or more contributor license
Licensed to Apereo 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,
Apereo licenses this file to you under the Apache License,
Version 2.0 (the "License"); you may not use this file
except in compliance with the License. You may obtain a
copy of the License at:
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
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
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->
<html>
<body>
<p>The validation package includes interfaces for validating Tickets, as well as the common implementations.</p>

View File

@ -1,27 +1,25 @@
/**
* Licensed to Jasig under one or more contributor license
* Licensed to Apereo 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,
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at:
* 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
* 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
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jasig.cas.client.validation;
import org.jasig.cas.client.util.CommonUtils;
import java.net.URL;
import org.jasig.cas.client.util.CommonUtils;
/**
* Abstract class that knows the protocol for validating a CAS ticket.
@ -36,18 +34,11 @@ public abstract class AbstractCasProtocolUrlBasedTicketValidator extends Abstrac
super(casServerUrlPrefix);
}
protected final void setDisableXmlSchemaValidation(final boolean disable) {
// nothing to do
}
/**
* Retrieves the response from the server by opening a connection and merely reading the response.
*/
@Override
protected final String retrieveResponseFromServer(final URL validationUrl, final String ticket) {
if (this.hostnameVerifier != null) {
return CommonUtils.getResponseFromServer(validationUrl, this.hostnameVerifier, getEncoding());
} else {
return CommonUtils.getResponseFromServer(validationUrl, getEncoding());
}
return CommonUtils.getResponseFromServer(validationUrl, getURLConnectionFactory(), getEncoding());
}
}

View File

@ -1,47 +1,49 @@
/**
* Licensed to Jasig under one or more contributor license
* Licensed to Apereo 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,
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at:
* 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
* 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
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jasig.cas.client.validation;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Properties;
import javax.net.ssl.HostnameVerifier;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.jasig.cas.client.Protocol;
import org.jasig.cas.client.configuration.ConfigurationKeys;
import org.jasig.cas.client.util.AbstractCasFilter;
import org.jasig.cas.client.util.CommonUtils;
import org.jasig.cas.client.util.ReflectUtils;
import javax.net.ssl.HostnameVerifier;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* The filter that handles all the work of validating ticket requests.
* <p>
* This filter can be configured with the following values:
* <ul>
* <li><code>redirectAfterValidation</code> - redirect the CAS client to the same URL without the ticket.</li>
* <li><code>redirectAfterValidation</code> - redirect the CAS client to the same URL without the ticket.
* (default: true, Will be forced to false when {@link #useSession} is false.)</li>
* <li><code>exceptionOnValidationFailure</code> - throw an exception if the validation fails. Otherwise, continue
* processing.</li>
* <li><code>useSession</code> - store any of the useful information in a session attribute.</li>
* processing. (default: true)</li>
* <li><code>useSession</code> - store any of the useful information in a session attribute. (default: true)</li>
* <li><code>hostnameVerifier</code> - name of class implementing a {@link HostnameVerifier}.</li>
* <li><code>hostnameVerifierConfig</code> - name of configuration class (constructor argument of verifier).</li>
* </ul>
*
* @author Scott Battaglia
@ -58,13 +60,21 @@ public abstract class AbstractTicketValidationFilter extends AbstractCasFilter {
* successful validation to remove the ticket parameter from the query
* string.
*/
private boolean redirectAfterValidation = false;
private boolean redirectAfterValidation = true;
/** Determines whether an exception is thrown when there is a ticket validation failure. */
private boolean exceptionOnValidationFailure = true;
private boolean exceptionOnValidationFailure = false;
/**
* Specify whether the Assertion should be stored in a session
* attribute {@link AbstractCasFilter#CONST_CAS_ASSERTION}.
*/
private boolean useSession = true;
protected AbstractTicketValidationFilter(final Protocol protocol) {
super(protocol);
}
/**
* Template method to return the appropriate validator.
*
@ -74,18 +84,39 @@ public abstract class AbstractTicketValidationFilter extends AbstractCasFilter {
protected TicketValidator getTicketValidator(final FilterConfig filterConfig) {
return this.ticketValidator;
}
/**
* Gets the ssl config to use for HTTPS connections
* if one is configured for this filter.
* @return Properties that can contains key/trust info for Client Side Certificates
*/
protected Properties getSSLConfig() {
final Properties properties = new Properties();
final String fileName = getString(ConfigurationKeys.SSL_CONFIG_FILE);
if (fileName != null) {
FileInputStream fis = null;
try {
fis = new FileInputStream(fileName);
properties.load(fis);
logger.trace("Loaded {} entries from {}", properties.size(), fileName);
} catch (final IOException ioe) {
logger.error(ioe.getMessage(), ioe);
} finally {
CommonUtils.closeQuietly(fis);
}
}
return properties;
}
/**
* Gets the configured {@link HostnameVerifier} to use for HTTPS connections
* if one is configured for this filter.
* @param filterConfig Servlet filter configuration.
* @return Instance of specified host name verifier or null if none specified.
*/
protected HostnameVerifier getHostnameVerifier(final FilterConfig filterConfig) {
final String className = getPropertyFromInitParams(filterConfig, "hostnameVerifier", null);
log.trace("Using hostnameVerifier parameter: " + className);
final String config = getPropertyFromInitParams(filterConfig, "hostnameVerifierConfig", null);
log.trace("Using hostnameVerifierConfig parameter: " + config);
protected HostnameVerifier getHostnameVerifier() {
final Class<? extends HostnameVerifier> className = getClass(ConfigurationKeys.HOSTNAME_VERIFIER);
final String config = getString(ConfigurationKeys.HOSTNAME_VERIFIER_CONFIG);
if (className != null) {
if (config != null) {
return ReflectUtils.newInstance(className, config);
@ -96,17 +127,22 @@ public abstract class AbstractTicketValidationFilter extends AbstractCasFilter {
return null;
}
@Override
protected void initInternal(final FilterConfig filterConfig) throws ServletException {
setExceptionOnValidationFailure(parseBoolean(getPropertyFromInitParams(filterConfig, "exceptionOnValidationFailure", "true")));
log.trace("Setting exceptionOnValidationFailure parameter: " + this.exceptionOnValidationFailure);
setRedirectAfterValidation(parseBoolean(getPropertyFromInitParams(filterConfig, "redirectAfterValidation", "true")));
log.trace("Setting redirectAfterValidation parameter: " + this.redirectAfterValidation);
setUseSession(parseBoolean(getPropertyFromInitParams(filterConfig, "useSession", "true")));
log.trace("Setting useSession parameter: " + this.useSession);
setExceptionOnValidationFailure(getBoolean(ConfigurationKeys.EXCEPTION_ON_VALIDATION_FAILURE));
setRedirectAfterValidation(getBoolean(ConfigurationKeys.REDIRECT_AFTER_VALIDATION));
setUseSession(getBoolean(ConfigurationKeys.USE_SESSION));
if (!this.useSession && this.redirectAfterValidation) {
logger.warn("redirectAfterValidation parameter may not be true when useSession parameter is false. Resetting it to false in order to prevent infinite redirects.");
setRedirectAfterValidation(false);
}
setTicketValidator(getTicketValidator(filterConfig));
super.initInternal(filterConfig);
}
@Override
public void init() {
super.init();
CommonUtils.assertNotNull(this.ticketValidator, "ticketValidator cannot be null.");
@ -122,7 +158,8 @@ public abstract class AbstractTicketValidationFilter extends AbstractCasFilter {
* @throws IOException if there is an I/O problem
* @throws ServletException if there is a servlet problem.
*/
protected boolean preFilter(final ServletRequest servletRequest, final ServletResponse servletResponse, final FilterChain filterChain) throws IOException, ServletException {
protected boolean preFilter(final ServletRequest servletRequest, final ServletResponse servletResponse,
final FilterChain filterChain) throws IOException, ServletException {
return true;
}
@ -135,8 +172,9 @@ public abstract class AbstractTicketValidationFilter extends AbstractCasFilter {
* @param response the HttpServletResponse.
* @param assertion the successful Assertion from the server.
*/
protected void onSuccessfulValidation(final HttpServletRequest request, final HttpServletResponse response, final Assertion assertion) {
// nothing to do here.
protected void onSuccessfulValidation(final HttpServletRequest request, final HttpServletResponse response,
final Assertion assertion) {
// nothing to do here.
}
/**
@ -150,7 +188,9 @@ public abstract class AbstractTicketValidationFilter extends AbstractCasFilter {
// nothing to do here.
}
public final void doFilter(final ServletRequest servletRequest, final ServletResponse servletResponse, final FilterChain filterChain) throws IOException, ServletException {
@Override
public final void doFilter(final ServletRequest servletRequest, final ServletResponse servletResponse,
final FilterChain filterChain) throws IOException, ServletException {
if (!preFilter(servletRequest, servletResponse, filterChain)) {
return;
@ -158,19 +198,16 @@ public abstract class AbstractTicketValidationFilter extends AbstractCasFilter {
final HttpServletRequest request = (HttpServletRequest) servletRequest;
final HttpServletResponse response = (HttpServletResponse) servletResponse;
final String ticket = CommonUtils.safeGetParameter(request, getArtifactParameterName());
final String ticket = retrieveTicketFromRequest(request);
if (CommonUtils.isNotBlank(ticket)) {
if (log.isDebugEnabled()) {
log.debug("Attempting to validate ticket: " + ticket);
}
logger.debug("Attempting to validate ticket: {}", ticket);
try {
final Assertion assertion = this.ticketValidator.validate(ticket, constructServiceUrl(request, response));
final Assertion assertion = this.ticketValidator.validate(ticket,
constructServiceUrl(request, response));
if (log.isDebugEnabled()) {
log.debug("Successfully authenticated user: " + assertion.getPrincipal().getName());
}
logger.debug("Successfully authenticated user: {}", assertion.getPrincipal().getName());
request.setAttribute(CONST_CAS_ASSERTION, assertion);
@ -180,13 +217,12 @@ public abstract class AbstractTicketValidationFilter extends AbstractCasFilter {
onSuccessfulValidation(request, response, assertion);
if (this.redirectAfterValidation) {
log. debug("Redirecting after successful ticket validation.");
logger.debug("Redirecting after successful ticket validation.");
response.sendRedirect(constructServiceUrl(request, response));
return;
}
} catch (final TicketValidationException e) {
response.setStatus(HttpServletResponse.SC_FORBIDDEN);
log.warn(e, e);
logger.debug(e.getMessage(), e);
onFailedValidation(request, response);
@ -194,6 +230,8 @@ public abstract class AbstractTicketValidationFilter extends AbstractCasFilter {
throw new ServletException(e);
}
response.sendError(HttpServletResponse.SC_FORBIDDEN, e.getMessage());
return;
}
}
@ -203,8 +241,8 @@ public abstract class AbstractTicketValidationFilter extends AbstractCasFilter {
}
public final void setTicketValidator(final TicketValidator ticketValidator) {
this.ticketValidator = ticketValidator;
}
this.ticketValidator = ticketValidator;
}
public final void setRedirectAfterValidation(final boolean redirectAfterValidation) {
this.redirectAfterValidation = redirectAfterValidation;
@ -217,8 +255,4 @@ public abstract class AbstractTicketValidationFilter extends AbstractCasFilter {
public final void setUseSession(final boolean useSession) {
this.useSession = useSession;
}
}

View File

@ -1,55 +1,50 @@
/**
* Licensed to Jasig under one or more contributor license
* Licensed to Apereo 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,
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at:
* 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
* 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
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jasig.cas.client.validation;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jasig.cas.client.util.CommonUtils;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Map;
import javax.net.ssl.HostnameVerifier;
import org.jasig.cas.client.ssl.HttpURLConnectionFactory;
import org.jasig.cas.client.ssl.HttpsURLConnectionFactory;
import org.jasig.cas.client.util.CommonUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Abstract validator implementation for tickets that must be validated against a server.
*
* @author Scott Battaglia
* @version $Revision$ $Date$
* @since 3.1
*/
public abstract class AbstractUrlBasedTicketValidator implements TicketValidator {
protected final Logger logger = LoggerFactory.getLogger(getClass());
/**
* Commons Logging instance.
* URLConnection factory instance to use when making validation requests to the CAS server.
* Defaults to {@link HttpsURLConnectionFactory}
*/
protected final Log log = LogFactory.getLog(getClass());
/**
* Hostname verifier used when making an SSL request to the CAS server.
*/
protected HostnameVerifier hostnameVerifier;
private HttpURLConnectionFactory urlConnectionFactory = new HttpsURLConnectionFactory();
/**
* Prefix for the CAS server. Should be everything up to the url endpoint, including the /.
@ -66,7 +61,7 @@ public abstract class AbstractUrlBasedTicketValidator implements TicketValidator
/**
* A map containing custom parameters to pass to the validation url.
*/
private Map<String,String> customParameters;
private Map<String, String> customParameters;
private String encoding;
@ -76,8 +71,8 @@ public abstract class AbstractUrlBasedTicketValidator implements TicketValidator
* @param casServerUrlPrefix the location of the CAS server.
*/
protected AbstractUrlBasedTicketValidator(final String casServerUrlPrefix) {
this.casServerUrlPrefix = casServerUrlPrefix;
CommonUtils.assertNotNull(this.casServerUrlPrefix, "casServerUrlPrefix cannot be null.");
CommonUtils.assertNotNull(casServerUrlPrefix, "casServerUrlPrefix cannot be null.");
this.casServerUrlPrefix = CommonUtils.addTrailingSlash(casServerUrlPrefix);
}
/**
@ -85,7 +80,7 @@ public abstract class AbstractUrlBasedTicketValidator implements TicketValidator
*
* @param urlParameters the map containing the parameters.
*/
protected void populateUrlAttributeMap(final Map<String,String> urlParameters) {
protected void populateUrlAttributeMap(final Map<String, String> urlParameters) {
// nothing to do
}
@ -95,13 +90,6 @@ public abstract class AbstractUrlBasedTicketValidator implements TicketValidator
*/
protected abstract String getUrlSuffix();
/**
* Disable XML Schema validation. Note, setting this to true may not be reversable. Defaults to false. Setting it to false
* after setting it to true may not have any affect.
*
* @param disabled whether to disable or not.
*/
protected abstract void setDisableXmlSchemaValidation(boolean disabled);
/**
* Constructs the URL to send the validation request to.
@ -111,36 +99,34 @@ public abstract class AbstractUrlBasedTicketValidator implements TicketValidator
* @return the fully constructed URL.
*/
protected final String constructValidationUrl(final String ticket, final String serviceUrl) {
final Map<String,String> urlParameters = new HashMap<String,String>();
final Map<String, String> urlParameters = new HashMap<String, String>();
log.debug("Placing URL parameters in map.");
logger.debug("Placing URL parameters in map.");
urlParameters.put("ticket", ticket);
urlParameters.put("service", encodeUrl(serviceUrl));
urlParameters.put("service", serviceUrl);
if (this.renew) {
urlParameters.put("renew", "true");
}
log.debug("Calling template URL attribute map.");
logger.debug("Calling template URL attribute map.");
populateUrlAttributeMap(urlParameters);
log.debug("Loading custom parameters from configuration.");
logger.debug("Loading custom parameters from configuration.");
if (this.customParameters != null) {
urlParameters.putAll(this.customParameters);
}
final String suffix = getUrlSuffix();
final StringBuilder buffer = new StringBuilder(urlParameters.size()*10 + this.casServerUrlPrefix.length() + suffix.length() +1);
final StringBuilder buffer = new StringBuilder(urlParameters.size() * 10 + this.casServerUrlPrefix.length()
+ suffix.length() + 1);
int i = 0;
buffer.append(this.casServerUrlPrefix);
if (!this.casServerUrlPrefix.endsWith("/")) {
buffer.append("/");
}
buffer.append(suffix);
for (Map.Entry<String,String> entry : urlParameters.entrySet()) {
for (final Map.Entry<String, String> entry : urlParameters.entrySet()) {
final String key = entry.getKey();
final String value = entry.getValue();
@ -148,7 +134,8 @@ public abstract class AbstractUrlBasedTicketValidator implements TicketValidator
buffer.append(i++ == 0 ? "?" : "&");
buffer.append(key);
buffer.append("=");
buffer.append(value);
final String encodedValue = encodeUrl(value);
buffer.append(encodedValue);
}
}
@ -163,10 +150,10 @@ public abstract class AbstractUrlBasedTicketValidator implements TicketValidator
* @return the encoded url, or the original url if "UTF-8" character encoding could not be found.
*/
protected final String encodeUrl(final String url) {
if (url == null) {
return null;
}
if (url == null) {
return null;
}
try {
return URLEncoder.encode(url, "UTF-8");
} catch (final UnsupportedEncodingException e) {
@ -194,25 +181,20 @@ public abstract class AbstractUrlBasedTicketValidator implements TicketValidator
protected abstract String retrieveResponseFromServer(URL validationUrl, String ticket);
public Assertion validate(final String ticket, final String service) throws TicketValidationException {
@Override
public final Assertion validate(final String ticket, final String service) throws TicketValidationException {
final String validationUrl = constructValidationUrl(ticket, service);
if (log.isDebugEnabled()) {
log.debug("Constructing validation url: " + validationUrl);
}
logger.debug("Constructing validation url: {}", validationUrl);
try {
log.debug("Retrieving response from server.");
logger.debug("Retrieving response from server.");
final String serverResponse = retrieveResponseFromServer(new URL(validationUrl), ticket);
if (serverResponse == null) {
throw new TicketValidationException("The CAS server returned no response.");
}
if (log.isDebugEnabled()) {
log.debug("Server response: " + serverResponse);
}
logger.debug("Server response: {}", serverResponse);
return parseResponseFromServer(serverResponse);
} catch (final MalformedURLException e) {
@ -224,13 +206,9 @@ public abstract class AbstractUrlBasedTicketValidator implements TicketValidator
this.renew = renew;
}
public final void setCustomParameters(final Map<String,String> customParameters) {
public final void setCustomParameters(final Map<String, String> customParameters) {
this.customParameters = customParameters;
}
public final void setHostnameVerifier(final HostnameVerifier verifier) {
this.hostnameVerifier = verifier;
}
public final void setEncoding(final String encoding) {
this.encoding = encoding;
@ -239,4 +217,24 @@ public abstract class AbstractUrlBasedTicketValidator implements TicketValidator
protected final String getEncoding() {
return this.encoding;
}
}
protected final boolean isRenew() {
return this.renew;
}
protected final String getCasServerUrlPrefix() {
return this.casServerUrlPrefix;
}
protected final Map<String, String> getCustomParameters() {
return this.customParameters;
}
protected HttpURLConnectionFactory getURLConnectionFactory() {
return this.urlConnectionFactory;
}
public void setURLConnectionFactory(final HttpURLConnectionFactory urlConnectionFactory) {
this.urlConnectionFactory = urlConnectionFactory;
}
}

View File

@ -1,29 +1,27 @@
/**
* Licensed to Jasig under one or more contributor license
* Licensed to Apereo 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,
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at:
* 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
* 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
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jasig.cas.client.validation;
import org.jasig.cas.client.authentication.AttributePrincipal;
import java.io.Serializable;
import java.util.Date;
import java.util.Map;
import org.jasig.cas.client.authentication.AttributePrincipal;
/**
* Represents a response to a validation request.
@ -48,12 +46,20 @@ public interface Assertion extends Serializable {
*/
Date getValidUntilDate();
/**
* The date the authentication actually occurred on. If its unable to be determined, it should be set to the current
* time.
*
* @return the authentication date, or the current time if it can't be determined.
*/
Date getAuthenticationDate();
/**
* The key/value pairs associated with this assertion.
*
* @return the map of attributes.
*/
Map<String,Object> getAttributes();
Map<String, Object> getAttributes();
/**
* The principal for which this assertion is valid.
@ -61,4 +67,12 @@ public interface Assertion extends Serializable {
* @return the principal.
*/
AttributePrincipal getPrincipal();
/**
* Determines whether an Assertion is considered usable or not. A naive implementation may just check the date validity.
*
* @return true if its valid, false otherwise.
* @since 3.3.0 (though in 3.3.0, no one actually calls this)
*/
boolean isValid();
}

View File

@ -1,31 +1,29 @@
/**
* Licensed to Jasig under one or more contributor license
* Licensed to Apereo 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,
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at:
* 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
* 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
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jasig.cas.client.validation;
import org.jasig.cas.client.authentication.AttributePrincipal;
import org.jasig.cas.client.authentication.AttributePrincipalImpl;
import org.jasig.cas.client.util.CommonUtils;
import java.util.Collections;
import java.util.Date;
import java.util.Map;
import org.jasig.cas.client.authentication.AttributePrincipal;
import org.jasig.cas.client.authentication.AttributePrincipalImpl;
import org.jasig.cas.client.util.CommonUtils;
/**
* Concrete Implementation of the {@link Assertion}.
@ -38,16 +36,18 @@ import java.util.Map;
public final class AssertionImpl implements Assertion {
/** Unique Id for serialization. */
private static final long serialVersionUID = -7767943925833639221L;
private static final long serialVersionUID = -7767943925833639221L;
/** The date from which the assertion is valid. */
/** The date from which the assertion is valid. */
private final Date validFromDate;
/** The date the assertion is valid until. */
private final Date validUntilDate;
private final Date authenticationDate;
/** Map of key/value pairs associated with this assertion. I.e. authentication type. */
private final Map<String,Object> attributes;
private final Map<String, Object> attributes;
/** The principal for which this assertion is valid for. */
private final AttributePrincipal principal;
@ -58,7 +58,7 @@ public final class AssertionImpl implements Assertion {
* @param name the name of the principal for which this assertion is valid.
*/
public AssertionImpl(final String name) {
this(new AttributePrincipalImpl(name));
this(new AttributePrincipalImpl(name));
}
/**
@ -67,7 +67,7 @@ public final class AssertionImpl implements Assertion {
* @param principal the Principal to associate with the Assertion.
*/
public AssertionImpl(final AttributePrincipal principal) {
this(principal, Collections.<String, Object>emptyMap());
this(principal, Collections.<String, Object> emptyMap());
}
/**
@ -76,8 +76,8 @@ public final class AssertionImpl implements Assertion {
* @param principal the Principal to associate with the Assertion.
* @param attributes the key/value pairs for this attribute.
*/
public AssertionImpl(final AttributePrincipal principal, final Map<String,Object> attributes) {
this(principal, new Date(), null, attributes);
public AssertionImpl(final AttributePrincipal principal, final Map<String, Object> attributes) {
this(principal, new Date(), null, new Date(), attributes);
}
/**
@ -88,29 +88,52 @@ public final class AssertionImpl implements Assertion {
* @param validUntilDate when the assertion is valid to.
* @param attributes the key/value pairs for this attribute.
*/
public AssertionImpl(final AttributePrincipal principal, final Date validFromDate, final Date validUntilDate, final Map<String,Object> attributes) {
public AssertionImpl(final AttributePrincipal principal, final Date validFromDate, final Date validUntilDate,
final Date authenticationDate, final Map<String, Object> attributes) {
this.principal = principal;
this.validFromDate = validFromDate;
this.validUntilDate = validUntilDate;
this.attributes = attributes;
this.authenticationDate = authenticationDate;
CommonUtils.assertNotNull(this.principal, "principal cannot be null.");
CommonUtils.assertNotNull(this.validFromDate, "validFromDate cannot be null.");
CommonUtils.assertNotNull(this.attributes, "attributes cannot be null.");
}
@Override
public Date getAuthenticationDate() {
return this.authenticationDate;
}
@Override
public Date getValidFromDate() {
return this.validFromDate;
}
@Override
public Date getValidUntilDate() {
return this.validUntilDate;
}
public Map<String,Object> getAttributes() {
@Override
public Map<String, Object> getAttributes() {
return this.attributes;
}
@Override
public AttributePrincipal getPrincipal() {
return this.principal;
}
@Override
public boolean isValid() {
if (this.validFromDate == null) {
return true;
}
final Date now = new Date();
return (this.validFromDate.before(now) || this.validFromDate.equals(now))
&& (this.validUntilDate == null || this.validUntilDate.after(now) || this.validUntilDate.equals(now));
}
}

View File

@ -1,43 +1,55 @@
/**
* Licensed to Jasig under one or more contributor license
* Licensed to Apereo 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,
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at:
* 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
* 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
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jasig.cas.client.validation;
import javax.servlet.FilterConfig;
import org.jasig.cas.client.Protocol;
import org.jasig.cas.client.configuration.ConfigurationKeys;
import org.jasig.cas.client.ssl.HttpURLConnectionFactory;
import org.jasig.cas.client.ssl.HttpsURLConnectionFactory;
/**
* Implementation of AbstractTicketValidatorFilter that instanciates a Cas10TicketValidator.
* Implementation of AbstractTicketValidatorFilter that creates a Cas10TicketValidator.
* <p>Deployers can provide the "casServerPrefix" and the "renew" attributes via the standard context or filter init
* parameters.
*
*
* @author Scott Battaglia
* @version $Revision$ $Date$
* @since 3.1
*/
public class Cas10TicketValidationFilter extends AbstractTicketValidationFilter {
public Cas10TicketValidationFilter() {
super(Protocol.CAS1);
}
@Override
protected final TicketValidator getTicketValidator(final FilterConfig filterConfig) {
final String casServerUrlPrefix = getPropertyFromInitParams(filterConfig, "casServerUrlPrefix", null);
final String casServerUrlPrefix = getString(ConfigurationKeys.CAS_SERVER_URL_PREFIX);
final Cas10TicketValidator validator = new Cas10TicketValidator(casServerUrlPrefix);
validator.setRenew(parseBoolean(getPropertyFromInitParams(filterConfig, "renew", "false")));
validator.setHostnameVerifier(getHostnameVerifier(filterConfig));
validator.setEncoding(getPropertyFromInitParams(filterConfig, "encoding", null));
validator.setRenew(getBoolean(ConfigurationKeys.RENEW));
final HttpURLConnectionFactory factory = new HttpsURLConnectionFactory(getHostnameVerifier(),
getSSLConfig());
validator.setURLConnectionFactory(factory);
validator.setEncoding(getString(ConfigurationKeys.ENCODING));
return validator;
}

View File

@ -1,22 +1,21 @@
/**
* Licensed to Jasig under one or more contributor license
* Licensed to Apereo 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,
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at:
* 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
* 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
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jasig.cas.client.validation;
import java.io.BufferedReader;
@ -36,10 +35,12 @@ public final class Cas10TicketValidator extends AbstractCasProtocolUrlBasedTicke
super(casServerUrlPrefix);
}
@Override
protected String getUrlSuffix() {
return "validate";
}
@Override
protected Assertion parseResponseFromServer(final String response) throws TicketValidationException {
if (!response.startsWith("yes")) {
throw new TicketValidationException("CAS Server could not validate ticket.");

View File

@ -1,43 +1,45 @@
/**
* Licensed to Jasig under one or more contributor license
* Licensed to Apereo 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,
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at:
* 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
* 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
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jasig.cas.client.validation;
import java.io.IOException;
import java.security.PrivateKey;
import java.util.*;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.jasig.cas.client.Protocol;
import org.jasig.cas.client.configuration.ConfigurationKeys;
import org.jasig.cas.client.proxy.*;
import org.jasig.cas.client.ssl.HttpURLConnectionFactory;
import org.jasig.cas.client.ssl.HttpsURLConnectionFactory;
import org.jasig.cas.client.util.CommonUtils;
import org.jasig.cas.client.util.PrivateKeyUtils;
import org.jasig.cas.client.util.ReflectUtils;
import static org.jasig.cas.client.configuration.ConfigurationKeys.*;
/**
* Creates either a CAS20ProxyTicketValidator or a CAS20ServiceTicketValidator depending on whether any of the
* proxy parameters are set.
* <p>
* <p/>
* This filter can also pass additional parameters to the ticket validator. Any init parameter not included in the
* reserved list {@link org.jasig.cas.client.validation.Cas20ProxyReceivingTicketValidationFilter#RESERVED_INIT_PARAMS}.
*
@ -45,16 +47,20 @@ import org.jasig.cas.client.util.ReflectUtils;
* @author Brad Cupit (brad [at] lsu {dot} edu)
* @version $Revision$ $Date$
* @since 3.1
*
*/
public class Cas20ProxyReceivingTicketValidationFilter extends AbstractTicketValidationFilter {
private static final String[] RESERVED_INIT_PARAMS = new String[] {"proxyGrantingTicketStorageClass", "proxyReceptorUrl", "acceptAnyProxy", "allowedProxyChains", "casServerUrlPrefix", "proxyCallbackUrl", "renew", "exceptionOnValidationFailure", "redirectAfterValidation", "useSession", "serverName", "service", "artifactParameterName", "serviceParameterName", "encodeServiceUrl", "millisBetweenCleanUps", "hostnameVerifier", "encoding", "config"};
private static final int DEFAULT_MILLIS_BETWEEN_CLEANUPS = 60 * 1000;
private static final String[] RESERVED_INIT_PARAMS = new String[]{ARTIFACT_PARAMETER_NAME.getName(), SERVER_NAME.getName(), SERVICE.getName(), RENEW.getName(), LOGOUT_PARAMETER_NAME.getName(),
ARTIFACT_PARAMETER_OVER_POST.getName(), EAGERLY_CREATE_SESSIONS.getName(), ENCODE_SERVICE_URL.getName(), SSL_CONFIG_FILE.getName(), ROLE_ATTRIBUTE.getName(), IGNORE_CASE.getName(),
CAS_SERVER_LOGIN_URL.getName(), GATEWAY.getName(), AUTHENTICATION_REDIRECT_STRATEGY_CLASS.getName(), GATEWAY_STORAGE_CLASS.getName(), CAS_SERVER_URL_PREFIX.getName(), ENCODING.getName(),
TOLERANCE.getName(), IGNORE_PATTERN.getName(), IGNORE_URL_PATTERN_TYPE.getName(), HOSTNAME_VERIFIER.getName(), HOSTNAME_VERIFIER_CONFIG.getName(),
EXCEPTION_ON_VALIDATION_FAILURE.getName(), REDIRECT_AFTER_VALIDATION.getName(), USE_SESSION.getName(), SECRET_KEY.getName(), CIPHER_ALGORITHM.getName(), PROXY_RECEPTOR_URL.getName(),
PROXY_GRANTING_TICKET_STORAGE_CLASS.getName(), MILLIS_BETWEEN_CLEAN_UPS.getName(), ACCEPT_ANY_PROXY.getName(), ALLOWED_PROXY_CHAINS.getName(), TICKET_VALIDATOR_CLASS.getName(),
PROXY_CALLBACK_URL.getName(), RELAY_STATE_PARAMETER_NAME.getName(), METHOD.getName(), PRIVATE_KEY_PATH.getName(), PRIVATE_KEY_ALGORITHM.getName()
};
/**
* The URL to send to the CAS server as the URL that will process proxying requests on the CAS client.
* The URL to send to the CAS server as the URL that will process proxying requests on the CAS client.
*/
private String proxyReceptorUrl;
@ -63,24 +69,41 @@ public class Cas20ProxyReceivingTicketValidationFilter extends AbstractTicketVal
private TimerTask timerTask;
private int millisBetweenCleanUps;
protected Class<? extends Cas20ServiceTicketValidator> defaultServiceTicketValidatorClass;
protected Class<? extends Cas20ProxyTicketValidator> defaultProxyTicketValidatorClass;
private PrivateKey privateKey;
/**
* Storage location of ProxyGrantingTickets and Proxy Ticket IOUs.
*/
private ProxyGrantingTicketStorage proxyGrantingTicketStorage = new ProxyGrantingTicketStorageImpl();
protected void initInternal(final FilterConfig filterConfig) throws ServletException {
setProxyReceptorUrl(getPropertyFromInitParams(filterConfig, "proxyReceptorUrl", null));
public Cas20ProxyReceivingTicketValidationFilter() {
this(Protocol.CAS2);
this.defaultServiceTicketValidatorClass = Cas20ServiceTicketValidator.class;
this.defaultProxyTicketValidatorClass = Cas20ProxyTicketValidator.class;
}
final String proxyGrantingTicketStorageClass = getPropertyFromInitParams(filterConfig, "proxyGrantingTicketStorageClass", null);
protected Cas20ProxyReceivingTicketValidationFilter(final Protocol protocol) {
super(protocol);
}
@Override
protected void initInternal(final FilterConfig filterConfig) throws ServletException {
setProxyReceptorUrl(getString(ConfigurationKeys.PROXY_RECEPTOR_URL));
final Class<? extends ProxyGrantingTicketStorage> proxyGrantingTicketStorageClass = getClass(ConfigurationKeys.PROXY_GRANTING_TICKET_STORAGE_CLASS);
if (proxyGrantingTicketStorageClass != null) {
this.proxyGrantingTicketStorage = ReflectUtils.newInstance(proxyGrantingTicketStorageClass);
if (this.proxyGrantingTicketStorage instanceof AbstractEncryptedProxyGrantingTicketStorageImpl) {
final AbstractEncryptedProxyGrantingTicketStorageImpl p = (AbstractEncryptedProxyGrantingTicketStorageImpl) this.proxyGrantingTicketStorage;
final String cipherAlgorithm = getPropertyFromInitParams(filterConfig, "cipherAlgorithm", AbstractEncryptedProxyGrantingTicketStorageImpl.DEFAULT_ENCRYPTION_ALGORITHM);
final String secretKey = getPropertyFromInitParams(filterConfig, "secretKey", null);
final String cipherAlgorithm = getString(ConfigurationKeys.CIPHER_ALGORITHM);
final String secretKey = getString(ConfigurationKeys.SECRET_KEY);
p.setCipherAlgorithm(cipherAlgorithm);
@ -94,11 +117,13 @@ public class Cas20ProxyReceivingTicketValidationFilter extends AbstractTicketVal
}
}
log.trace("Setting proxyReceptorUrl parameter: " + this.proxyReceptorUrl);
this.millisBetweenCleanUps = Integer.parseInt(getPropertyFromInitParams(filterConfig, "millisBetweenCleanUps", Integer.toString(DEFAULT_MILLIS_BETWEEN_CLEANUPS)));
this.millisBetweenCleanUps = getInt(ConfigurationKeys.MILLIS_BETWEEN_CLEAN_UPS);
this.privateKey = buildPrivateKey(getString(PRIVATE_KEY_PATH), getString(PRIVATE_KEY_ALGORITHM));
super.initInternal(filterConfig);
}
@Override
public void init() {
super.init();
CommonUtils.assertNotNull(this.proxyGrantingTicketStorage, "proxyGrantingTicketStorage cannot be null.");
@ -113,36 +138,61 @@ public class Cas20ProxyReceivingTicketValidationFilter extends AbstractTicketVal
this.timer.schedule(this.timerTask, this.millisBetweenCleanUps, this.millisBetweenCleanUps);
}
private <T> T createNewTicketValidator(final Class<? extends Cas20ServiceTicketValidator> ticketValidatorClass, final String casServerUrlPrefix,
final Class<T> clazz) {
if (ticketValidatorClass == null) {
return ReflectUtils.newInstance(clazz, casServerUrlPrefix);
}
return (T) ReflectUtils.newInstance(ticketValidatorClass, casServerUrlPrefix);
}
public static PrivateKey buildPrivateKey(final String keyPath, final String keyAlgorithm) {
if (keyPath != null) {
return PrivateKeyUtils.createKey(keyPath, keyAlgorithm);
}
return null;
}
/**
* Constructs a Cas20ServiceTicketValidator or a Cas20ProxyTicketValidator based on supplied parameters.
*
* @param filterConfig the Filter Configuration object.
* @return a fully constructed TicketValidator.
*/
@Override
protected final TicketValidator getTicketValidator(final FilterConfig filterConfig) {
final String allowAnyProxy = getPropertyFromInitParams(filterConfig, "acceptAnyProxy", null);
final String allowedProxyChains = getPropertyFromInitParams(filterConfig, "allowedProxyChains", null);
final String casServerUrlPrefix = getPropertyFromInitParams(filterConfig, "casServerUrlPrefix", null);
final boolean allowAnyProxy = getBoolean(ConfigurationKeys.ACCEPT_ANY_PROXY);
final String allowedProxyChains = getString(ConfigurationKeys.ALLOWED_PROXY_CHAINS);
final String casServerUrlPrefix = getString(ConfigurationKeys.CAS_SERVER_URL_PREFIX);
final Class<? extends Cas20ServiceTicketValidator> ticketValidatorClass = getClass(ConfigurationKeys.TICKET_VALIDATOR_CLASS);
final Cas20ServiceTicketValidator validator;
if (CommonUtils.isNotBlank(allowAnyProxy) || CommonUtils.isNotBlank(allowedProxyChains)) {
final Cas20ProxyTicketValidator v = new Cas20ProxyTicketValidator(casServerUrlPrefix);
v.setAcceptAnyProxy(parseBoolean(allowAnyProxy));
if (allowAnyProxy || CommonUtils.isNotBlank(allowedProxyChains)) {
final Cas20ProxyTicketValidator v = createNewTicketValidator(ticketValidatorClass, casServerUrlPrefix,
this.defaultProxyTicketValidatorClass);
v.setAcceptAnyProxy(allowAnyProxy);
v.setAllowedProxyChains(CommonUtils.createProxyList(allowedProxyChains));
validator = v;
} else {
validator = new Cas20ServiceTicketValidator(casServerUrlPrefix);
validator = createNewTicketValidator(ticketValidatorClass, casServerUrlPrefix,
this.defaultServiceTicketValidatorClass);
}
validator.setProxyCallbackUrl(getPropertyFromInitParams(filterConfig, "proxyCallbackUrl", null));
validator.setProxyCallbackUrl(getString(ConfigurationKeys.PROXY_CALLBACK_URL));
validator.setProxyGrantingTicketStorage(this.proxyGrantingTicketStorage);
validator.setProxyRetriever(new Cas20ProxyRetriever(casServerUrlPrefix, getPropertyFromInitParams(filterConfig, "encoding", null)));
validator.setRenew(parseBoolean(getPropertyFromInitParams(filterConfig, "renew", "false")));
validator.setEncoding(getPropertyFromInitParams(filterConfig, "encoding", null));
final Map<String,String> additionalParameters = new HashMap<String,String>();
final HttpURLConnectionFactory factory = new HttpsURLConnectionFactory(getHostnameVerifier(),
getSSLConfig());
validator.setURLConnectionFactory(factory);
validator.setProxyRetriever(new Cas20ProxyRetriever(casServerUrlPrefix, getString(ConfigurationKeys.ENCODING), factory));
validator.setRenew(getBoolean(ConfigurationKeys.RENEW));
validator.setEncoding(getString(ConfigurationKeys.ENCODING));
final Map<String, String> additionalParameters = new HashMap<String, String>();
final List<String> params = Arrays.asList(RESERVED_INIT_PARAMS);
for (final Enumeration<?> e = filterConfig.getInitParameterNames(); e.hasMoreElements();) {
for (final Enumeration<?> e = filterConfig.getInitParameterNames(); e.hasMoreElements(); ) {
final String s = (String) e.nextElement();
if (!params.contains(s)) {
@ -150,12 +200,13 @@ public class Cas20ProxyReceivingTicketValidationFilter extends AbstractTicketVal
}
}
validator.setCustomParameters(additionalParameters);
validator.setHostnameVerifier(getHostnameVerifier(filterConfig));
validator.setPrivateKey(this.privateKey);
validator.setCustomParameters(additionalParameters);
return validator;
}
@Override
public void destroy() {
super.destroy();
this.timer.cancel();
@ -164,7 +215,9 @@ public class Cas20ProxyReceivingTicketValidationFilter extends AbstractTicketVal
/**
* This processes the ProxyReceptor request before the ticket validation code executes.
*/
protected final boolean preFilter(final ServletRequest servletRequest, final ServletResponse servletResponse, final FilterChain filterChain) throws IOException, ServletException {
@Override
protected final boolean preFilter(final ServletRequest servletRequest, final ServletResponse servletResponse,
final FilterChain filterChain) throws IOException, ServletException {
final HttpServletRequest request = (HttpServletRequest) servletRequest;
final HttpServletResponse response = (HttpServletResponse) servletResponse;
final String requestUri = request.getRequestURI();
@ -176,7 +229,7 @@ public class Cas20ProxyReceivingTicketValidationFilter extends AbstractTicketVal
try {
CommonUtils.readAndRespondToProxyReceptorRequest(request, response, this.proxyGrantingTicketStorage);
} catch (final RuntimeException e) {
log.error(e.getMessage(), e);
logger.error(e.getMessage(), e);
throw e;
}

View File

@ -1,33 +1,31 @@
/**
* Licensed to Jasig under one or more contributor license
* Licensed to Apereo 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,
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at:
* 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
* 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
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jasig.cas.client.validation;
import org.jasig.cas.client.util.XmlUtils;
import java.util.Arrays;
import java.util.List;
import org.jasig.cas.client.util.XmlUtils;
/**
* Extension to the traditional Service Ticket validation that will validate service tickets and proxy tickets.
*
* @author Scott Battaglia
* @version $Revision$ $Date$
* @since 3.1
*/
public class Cas20ProxyTicketValidator extends Cas20ServiceTicketValidator {
@ -37,39 +35,84 @@ public class Cas20ProxyTicketValidator extends Cas20ServiceTicketValidator {
/** This should be a list of an array of Strings */
private ProxyList allowedProxyChains = new ProxyList();
/** Allows for an empty chain of proxy callback urls. **/
private boolean allowEmptyProxyChain = true;
public Cas20ProxyTicketValidator(final String casServerUrlPrefix) {
super(casServerUrlPrefix);
}
public ProxyList getAllowedProxyChains() {
protected final ProxyList getAllowedProxyChains() {
return this.allowedProxyChains;
}
@Override
protected String getUrlSuffix() {
return "proxyValidate";
}
protected void customParseResponse(final String response, final Assertion assertion) throws TicketValidationException {
final List<String> proxies = XmlUtils.getTextForElements(response, "proxy");
final String[] proxiedList = proxies.toArray(new String[proxies.size()]);
@Override
protected void customParseResponse(final String response, final Assertion assertion)
throws TicketValidationException {
final List<String> proxies = parseProxiesFromResponse(response);
if (proxies == null) {
throw new InvalidProxyChainTicketValidationException(
"Invalid proxy chain: No proxy could be retrieved from response. "
+ "This indicates a problem with CAS validation. Review logs/configuration to find the root cause."
);
}
// this means there was nothing in the proxy chain, which is okay
if (proxies.isEmpty() || this.acceptAnyProxy) {
if (this.allowEmptyProxyChain && proxies.isEmpty()) {
logger.debug("Found an empty proxy chain, permitted by client configuration");
return;
}
if (this.acceptAnyProxy) {
logger.debug("Client configuration accepts any proxy. "
+ "It is generally dangerous to use a non-proxied CAS filter "
+ "specially for protecting resources that require proxy access.");
return;
}
final String[] proxiedList = proxies.toArray(new String[proxies.size()]);
if (this.allowedProxyChains.contains(proxiedList)) {
return;
}
logger.warn("Proxies received from the CAS validation response are {}. "
+ "However, none are allowed by allowed proxy chain of the client which is {}",
Arrays.toString(proxiedList), this.allowedProxyChains);
throw new InvalidProxyChainTicketValidationException("Invalid proxy chain: " + proxies.toString());
}
public void setAcceptAnyProxy(final boolean acceptAnyProxy) {
protected List<String> parseProxiesFromResponse(final String response) {
return XmlUtils.getTextForElements(response, "proxy");
}
public final void setAcceptAnyProxy(final boolean acceptAnyProxy) {
this.acceptAnyProxy = acceptAnyProxy;
}
public void setAllowedProxyChains(final ProxyList allowedProxyChains) {
public final void setAllowedProxyChains(final ProxyList allowedProxyChains) {
this.allowedProxyChains = allowedProxyChains;
}
protected final boolean isAcceptAnyProxy() {
return this.acceptAnyProxy;
}
protected final boolean isAllowEmptyProxyChain() {
return this.allowEmptyProxyChain;
}
/**
* Set to determine whether empty proxy chains are allowed.
* @see #customParseResponse(String, Assertion)
* @param allowEmptyProxyChain whether to allow empty proxy chains or not. True if so, false otherwise.
*/
public final void setAllowEmptyProxyChain(final boolean allowEmptyProxyChain) {
this.allowEmptyProxyChain = allowEmptyProxyChain;
}
}

View File

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

View File

@ -0,0 +1,40 @@
/**
* Licensed to Apereo under one or more contributor license
* agreements. See the NOTICE file distributed with this work
* for additional information regarding copyright ownership.
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at the following location:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jasig.cas.client.validation;
import org.jasig.cas.client.Protocol;
/**
* Creates either a Cas30ProxyTicketValidator or a Cas30ServiceTicketValidator depending on whether any of the
* proxy parameters are set.
* <p/>
* This filter can also pass additional parameters to the ticket validator. Any init parameter not included in the
* reserved list {@link org.jasig.cas.client.validation.Cas20ProxyReceivingTicketValidationFilter#RESERVED_INIT_PARAMS}.
*
* @author Jerome Leleu
* @since 3.4.0
*/
public class Cas30ProxyReceivingTicketValidationFilter extends Cas20ProxyReceivingTicketValidationFilter {
public Cas30ProxyReceivingTicketValidationFilter() {
super(Protocol.CAS3);
this.defaultServiceTicketValidatorClass = Cas30ServiceTicketValidator.class;
this.defaultProxyTicketValidatorClass = Cas30ProxyTicketValidator.class;
}
}

View File

@ -0,0 +1,37 @@
/**
* Licensed to Apereo under one or more contributor license
* agreements. See the NOTICE file distributed with this work
* for additional information regarding copyright ownership.
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at the following location:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jasig.cas.client.validation;
/**
* Service and proxy tickets validation service for the CAS protocol v3.
*
* @author Jerome Leleu
* @since 3.4.0
*/
public class Cas30ProxyTicketValidator extends Cas20ProxyTicketValidator {
public Cas30ProxyTicketValidator(final String casServerUrlPrefix) {
super(casServerUrlPrefix);
}
@Override
protected String getUrlSuffix() {
return "p3/proxyValidate";
}
}

View File

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

View File

@ -1,22 +1,21 @@
/**
* Licensed to Jasig under one or more contributor license
* Licensed to Apereo 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,
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at:
* 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
* 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
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jasig.cas.client.validation;
/**
@ -29,11 +28,11 @@ package org.jasig.cas.client.validation;
public final class InvalidProxyChainTicketValidationException extends TicketValidationException {
/**
* Unique Id for Serialization
*/
private static final long serialVersionUID = -7736653266370691534L;
* Unique Id for Serialization
*/
private static final long serialVersionUID = -7736653266370691534L;
/**
/**
* Constructs an exception with the supplied message.
* @param string the supplied message.
*/

View File

@ -1,29 +1,31 @@
/**
* Licensed to Jasig under one or more contributor license
* Licensed to Apereo 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,
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at:
* 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
* 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
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jasig.cas.client.validation;
import org.jasig.cas.client.util.CommonUtils;
import java.util.ArrayList;
import java.util.List;
import java.util.Arrays;
import org.jasig.cas.client.authentication.ExactUrlPatternMatcherStrategy;
import org.jasig.cas.client.authentication.RegexUrlPatternMatcherStrategy;
import org.jasig.cas.client.authentication.UrlPatternMatcherStrategy;
import org.jasig.cas.client.util.CommonUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Holding class for the proxy list to make Spring configuration easier.
@ -34,28 +36,66 @@ import java.util.Arrays;
*/
public final class ProxyList {
private final List<String[]> proxyChains;
private final Logger logger = LoggerFactory.getLogger(getClass());
private final List<List<UrlPatternMatcherStrategy>> proxyChains;
public ProxyList(final List<String[]> proxyChains) {
CommonUtils.assertNotNull(proxyChains, "List of proxy chains cannot be null.");
this.proxyChains = proxyChains;
this.proxyChains = new ArrayList<List<UrlPatternMatcherStrategy>>();
for (final String[] list : proxyChains) {
final List<UrlPatternMatcherStrategy> chain = new ArrayList<UrlPatternMatcherStrategy>();
for (final String item : list) {
if (item.startsWith("^")) {
chain.add(new RegexUrlPatternMatcherStrategy(item));
} else {
chain.add(new ExactUrlPatternMatcherStrategy(item));
}
}
this.proxyChains.add(chain);
}
}
public ProxyList() {
this(new ArrayList<String[]>());
}
public boolean contains(String[] proxiedList) {
for (final String[] list : this.proxyChains) {
if (Arrays.equals(proxiedList, list)) {
return true;
public boolean contains(final String[] proxiedList) {
StringBuilder loggingOutput;
for (final List<UrlPatternMatcherStrategy> proxyChain : this.proxyChains) {
loggingOutput = new StringBuilder();
if (proxyChain.size() == proxiedList.length) {
for (int linkIndex = 0; linkIndex < proxyChain.size(); linkIndex++) {
final String linkToTest = proxiedList[linkIndex];
loggingOutput.append(linkToTest);
if (proxyChain.get(linkIndex).matches(linkToTest)) {
//If we are at the last link, we found a good proxyChain.
if (linkIndex == proxyChain.size() - 1) {
logger.info("Proxy chain matched: {}", loggingOutput.toString());
return true;
}
} else {
logger.warn("Proxy chain did not match at {}. Skipping to next allowedProxyChain", loggingOutput.toString());
break;
}
loggingOutput.append("->");
}
}
}
logger.warn("No proxy chain matched the allowedProxyChains list.");
return false;
}
public String toString() {
return this.proxyChains.toString();
return this.proxyChains.toString();
}
}

View File

@ -1,32 +1,30 @@
/**
* Licensed to Jasig under one or more contributor license
* Licensed to Apereo 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,
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at:
* 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
* 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
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jasig.cas.client.validation;
import org.jasig.cas.client.util.CommonUtils;
import java.beans.PropertyEditorSupport;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.List;
import org.jasig.cas.client.util.CommonUtils;
/**
* Convert a String-formatted list of acceptable proxies to an array.
@ -38,27 +36,28 @@ import java.util.List;
*/
public final class ProxyListEditor extends PropertyEditorSupport {
public void setAsText(final String text) throws IllegalArgumentException {
final BufferedReader reader = new BufferedReader(new StringReader(text));
final List<String[]> proxyChains = new ArrayList<String[]>();
@Override
public void setAsText(final String text) throws IllegalArgumentException {
final BufferedReader reader = new BufferedReader(new StringReader(text));
final List<String[]> proxyChains = new ArrayList<String[]>();
try {
String line;
while ((line = reader.readLine()) != null) {
if (CommonUtils.isNotBlank(line)) {
proxyChains.add(line.trim().split(" "));
}
}
} catch (final IOException e) {
// ignore this
} finally {
try {
reader.close();
} catch (final IOException e) {
// nothing to do
}
}
try {
String line;
while ((line = reader.readLine()) != null) {
if (CommonUtils.isNotBlank(line)) {
proxyChains.add(line.trim().split(" "));
}
}
} catch (final IOException e) {
// ignore this
} finally {
try {
reader.close();
} catch (final IOException e) {
// nothing to do
}
}
setValue(new ProxyList(proxyChains));
}
setValue(new ProxyList(proxyChains));
}
}

View File

@ -1,64 +0,0 @@
/**
* Licensed to Jasig under one or more contributor license
* agreements. See the NOTICE file distributed with this work
* for additional information regarding copyright ownership.
* Jasig licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jasig.cas.client.validation;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
/**
* Implementation of TicketValidationFilter that can instanciate a SAML 1.1 Ticket Validator.
* <p>
* Deployers can provide the "casServerUrlPrefix" and "tolerance" properties of the Saml11TicketValidator via the
* context or filter init parameters.
* <p>
* Note, the "final" on this class helps ensure the compliance required in the initInternal method.
*
* @author Scott Battaglia
* @version $Revision$ $Date$
* @since 3.1
*/
public final class Saml11TicketValidationFilter extends AbstractTicketValidationFilter {
public Saml11TicketValidationFilter() {
setArtifactParameterName("SAMLart");
setServiceParameterName("TARGET");
}
protected void initInternal(final FilterConfig filterConfig) throws ServletException {
super.initInternal(filterConfig);
log.warn("SAML1.1 compliance requires the [artifactParameterName] and [serviceParameterName] to be set to specified values.");
log.warn("This filter will overwrite any user-provided values (if any are provided)");
setArtifactParameterName("SAMLart");
setServiceParameterName("TARGET");
}
protected final TicketValidator getTicketValidator(final FilterConfig filterConfig) {
final Saml11TicketValidator validator = new Saml11TicketValidator(getPropertyFromInitParams(filterConfig, "casServerUrlPrefix", null));
final String tolerance = getPropertyFromInitParams(filterConfig, "tolerance", "1000");
validator.setTolerance(Long.parseLong(tolerance));
validator.setRenew(parseBoolean(getPropertyFromInitParams(filterConfig, "renew", "false")));
validator.setHostnameVerifier(getHostnameVerifier(filterConfig));
validator.setEncoding(getPropertyFromInitParams(filterConfig, "encoding", null));
validator.setDisableXmlSchemaValidation(parseBoolean(getPropertyFromInitParams(filterConfig, "disableXmlSchemaValidation", "false")));
return validator;
}
}

View File

@ -1,242 +0,0 @@
/**
* Licensed to Jasig under one or more contributor license
* agreements. See the NOTICE file distributed with this work
* for additional information regarding copyright ownership.
* Jasig licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jasig.cas.client.validation;
import org.jasig.cas.client.authentication.AttributePrincipal;
import org.jasig.cas.client.authentication.AttributePrincipalImpl;
import org.jasig.cas.client.util.CommonUtils;
import org.opensaml.*;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.Charset;
import java.util.*;
import javax.net.ssl.HttpsURLConnection;
/**
* TicketValidator that can understand validating a SAML artifact. This includes the SOAP request/response.
*
* @author Scott Battaglia
* @version $Revision$ $Date$
* @since 3.1
*/
public final class Saml11TicketValidator extends AbstractUrlBasedTicketValidator {
/** Time tolerance to allow for time drifting. */
private long tolerance = 1000L;
public Saml11TicketValidator(final String casServerUrlPrefix) {
super(casServerUrlPrefix);
}
protected String getUrlSuffix() {
return "samlValidate";
}
protected void populateUrlAttributeMap(final Map<String, String> urlParameters) {
final String service = urlParameters.get("service");
urlParameters.remove("service");
urlParameters.remove("ticket");
urlParameters.put("TARGET", service);
}
@Override
protected void setDisableXmlSchemaValidation(final boolean disabled) {
if (disabled) {
// according to our reading of the SAML 1.1 code, this should disable the schema checking. However, there may be a couple
// of error messages that slip through on start up!
XML.parserPool.setDefaultSchemas(null, null);
}
}
protected Assertion parseResponseFromServer(final String response) throws TicketValidationException {
try {
final String removeStartOfSoapBody = response.substring(response.indexOf("<SOAP-ENV:Body>") + 15);
final String removeEndOfSoapBody = removeStartOfSoapBody.substring(0, removeStartOfSoapBody.indexOf("</SOAP-ENV:Body>"));
final SAMLResponse samlResponse = new SAMLResponse(new ByteArrayInputStream(CommonUtils.isNotBlank(getEncoding()) ? removeEndOfSoapBody.getBytes(Charset.forName(getEncoding())) : removeEndOfSoapBody.getBytes()));
if (!samlResponse.getAssertions().hasNext()) {
throw new TicketValidationException("No assertions found.");
}
for (final Iterator<?> iter = samlResponse.getAssertions(); iter.hasNext();) {
final SAMLAssertion assertion = (SAMLAssertion) iter.next();
if (!isValidAssertion(assertion)) {
continue;
}
final SAMLAuthenticationStatement authenticationStatement = getSAMLAuthenticationStatement(assertion);
if (authenticationStatement == null) {
throw new TicketValidationException("No AuthentiationStatement found in SAML Assertion.");
}
final SAMLSubject subject = authenticationStatement.getSubject();
if (subject == null) {
throw new TicketValidationException("No Subject found in SAML Assertion.");
}
final SAMLAttribute[] attributes = getAttributesFor(assertion, subject);
final Map<String,Object> personAttributes = new HashMap<String,Object>();
for (final SAMLAttribute samlAttribute : attributes) {
final List<?> values = getValuesFrom(samlAttribute);
personAttributes.put(samlAttribute.getName(), values.size() == 1 ? values.get(0) : values);
}
final AttributePrincipal principal = new AttributePrincipalImpl(subject.getNameIdentifier().getName(), personAttributes);
final Map<String,Object> authenticationAttributes = new HashMap<String,Object>();
authenticationAttributes.put("samlAuthenticationStatement::authMethod", authenticationStatement.getAuthMethod());
return new AssertionImpl(principal, authenticationAttributes);
}
} catch (final SAMLException e) {
throw new TicketValidationException(e);
}
throw new TicketValidationException("No Assertion found within valid time range. Either there's a replay of the ticket or there's clock drift. Check tolerance range, or server/client synchronization.");
}
private boolean isValidAssertion(final SAMLAssertion assertion) {
final Date notBefore = assertion.getNotBefore();
final Date notOnOrAfter = assertion.getNotOnOrAfter();
if (assertion.getNotBefore() == null || assertion.getNotOnOrAfter() == null) {
log.debug("Assertion has no bounding dates. Will not process.");
return false;
}
final long currentTime = getCurrentTimeInUtc().getTime();
if (currentTime + tolerance < notBefore.getTime()) {
log.debug("skipping assertion that's not yet valid...");
return false;
}
if (notOnOrAfter.getTime() <= currentTime - tolerance) {
log.debug("skipping expired assertion...");
return false;
}
return true;
}
private SAMLAuthenticationStatement getSAMLAuthenticationStatement(final SAMLAssertion assertion) {
for (final Iterator<?> iter = assertion.getStatements(); iter.hasNext();) {
final SAMLStatement statement = (SAMLStatement) iter.next();
if (statement instanceof SAMLAuthenticationStatement) {
return (SAMLAuthenticationStatement) statement;
}
}
return null;
}
private SAMLAttribute[] getAttributesFor(final SAMLAssertion assertion, final SAMLSubject subject) {
final List<SAMLAttribute> attributes = new ArrayList<SAMLAttribute>();
for (final Iterator<?> iter = assertion.getStatements(); iter.hasNext();) {
final SAMLStatement statement = (SAMLStatement) iter.next();
if (statement instanceof SAMLAttributeStatement) {
final SAMLAttributeStatement attributeStatement = (SAMLAttributeStatement) statement;
// used because SAMLSubject does not implement equals
if (subject.getNameIdentifier().getName().equals(attributeStatement.getSubject().getNameIdentifier().getName())) {
for (final Iterator<?> iter2 = attributeStatement.getAttributes(); iter2.hasNext();)
attributes.add((SAMLAttribute) iter2.next());
}
}
}
return attributes.toArray(new SAMLAttribute[attributes.size()]);
}
private List<?> getValuesFrom(final SAMLAttribute attribute) {
final List<Object> list = new ArrayList<Object>();
for (final Iterator<?> iter = attribute.getValues(); iter.hasNext();) {
list.add(iter.next());
}
return list;
}
private Date getCurrentTimeInUtc() {
final Calendar c = Calendar.getInstance();
c.setTimeZone(TimeZone.getTimeZone("UTC"));
return c.getTime();
}
protected String retrieveResponseFromServer(final URL validationUrl, final String ticket) {
String MESSAGE_TO_SEND;
try {
MESSAGE_TO_SEND = "<SOAP-ENV:Envelope xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\"><SOAP-ENV:Header/><SOAP-ENV:Body><samlp:Request xmlns:samlp=\"urn:oasis:names:tc:SAML:1.0:protocol\" MajorVersion=\"1\" MinorVersion=\"1\" RequestID=\"" + SAMLIdentifierFactory.getInstance().getIdentifier() + "\" IssueInstant=\"" + CommonUtils.formatForUtcTime(new Date()) + "\">"
+ "<samlp:AssertionArtifact>" + ticket
+ "</samlp:AssertionArtifact></samlp:Request></SOAP-ENV:Body></SOAP-ENV:Envelope>";
} catch (final SAMLException e) {
throw new RuntimeException(e);
}
HttpURLConnection conn = null;
try {
conn = (HttpURLConnection) validationUrl.openConnection();
if (this.hostnameVerifier != null && conn instanceof HttpsURLConnection) {
((HttpsURLConnection)conn).setHostnameVerifier(this.hostnameVerifier);
}
conn.setRequestMethod("POST");
conn.setRequestProperty("Content-Type", "text/xml");
conn.setRequestProperty("Content-Length", Integer.toString(MESSAGE_TO_SEND.length()));
conn.setRequestProperty("SOAPAction", "http://www.oasis-open.org/committees/security");
conn.setUseCaches(false);
conn.setDoInput(true);
conn.setDoOutput(true);
final DataOutputStream out = new DataOutputStream(conn.getOutputStream());
out.writeBytes(MESSAGE_TO_SEND);
out.flush();
out.close();
final BufferedReader in = new BufferedReader(CommonUtils.isNotBlank(getEncoding()) ? new InputStreamReader(conn.getInputStream(), Charset.forName(getEncoding())) : new InputStreamReader(conn.getInputStream()));
final StringBuilder buffer = new StringBuilder(256);
String line;
while ((line = in.readLine()) != null) {
buffer.append(line);
}
return buffer.toString();
} catch (final IOException e) {
throw new RuntimeException(e);
} finally {
if (conn != null) {
conn.disconnect();
}
}
}
public void setTolerance(final long tolerance) {
this.tolerance = tolerance;
}
}

View File

@ -1,22 +1,21 @@
/**
* Licensed to Jasig under one or more contributor license
* Licensed to Apereo 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,
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at:
* 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
* 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
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jasig.cas.client.validation;
/**
@ -29,11 +28,11 @@ package org.jasig.cas.client.validation;
public class TicketValidationException extends Exception {
/**
* Unique Id for Serialization
*/
private static final long serialVersionUID = -7036248720402711806L;
* Unique Id for Serialization
*/
private static final long serialVersionUID = -7036248720402711806L;
/**
/**
* Constructs an exception with the supplied message.
*
* @param string the message

View File

@ -1,22 +1,21 @@
/**
* Licensed to Jasig under one or more contributor license
* Licensed to Apereo 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,
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at:
* 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
* 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
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jasig.cas.client.validation;
/**

View File

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

View File

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

View File

@ -0,0 +1,62 @@
/**
* Licensed to Apereo under one or more contributor license
* agreements. See the NOTICE file distributed with this work
* for additional information regarding copyright ownership.
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at the following location:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jasig.cas.client.validation.json;
import com.fasterxml.jackson.core.JsonProcessingException;
import org.jasig.cas.client.validation.Assertion;
import org.jasig.cas.client.validation.Cas30ServiceTicketValidator;
import org.jasig.cas.client.validation.TicketValidationException;
import java.io.IOException;
import java.util.Collections;
import java.util.Map;
/**
* This is {@link Cas30JsonServiceTicketValidator} that attempts to parse the CAS validation response
* as JSON. If the response is not formatted as JSON, it shall fallback to the XML default syntax.
* The JSON response provides advantages in terms of naming and parsing CAS attributes that have special
* names that otherwise may not be encoded as XML, such as the invalid {@code <cas:special:attribute>value</cas:special:attribute>}
*
* @author Misagh Moayyed
*/
public class Cas30JsonServiceTicketValidator extends Cas30ServiceTicketValidator {
public Cas30JsonServiceTicketValidator(final String casServerUrlPrefix) {
super(casServerUrlPrefix);
setCustomParameters(Collections.singletonMap("format", "JSON"));
}
@Override
protected Assertion parseResponseFromServer(final String response) throws TicketValidationException {
try {
final TicketValidationJsonResponse json = new JsonValidationResponseParser().parse(response);
return json.getAssertion(getProxyGrantingTicketStorage(), getProxyRetriever());
} catch (final JsonProcessingException e) {
logger.warn("Unable parse the JSON response. Falling back to XML", e);
return super.parseResponseFromServer(response);
} catch (final IOException e) {
throw new TicketValidationException(e.getMessage(), e);
}
}
@Override
protected Map<String, Object> extractCustomAttributes(final String xml) {
return Collections.emptyMap();
}
}

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