背景介绍
Cas Management 6.5.x 无法使用http访问,而公司内部系统使用时https无疑是给部署带来很大的麻烦,所以最好的解决办法就是兼容http访问。
通过模板搭建工程
官方模板地址:https://github.com/apereo/cas-management-overlay
编译工程
编译工程
打开idea右侧gradle菜单栏(类似maven),选择build命令进行工程编译
编译如果失败,有可能是因为jar包没下成功,可以通过根目录下的build.gradle添加国内仓库,比如阿里云仓库(https://maven.aliyun.com/nexus/content/groups/public),编译成功的话会生成build文件夹
配置文件
打开build文件夹,找到overlays文件夹下的配置文件,拷贝到工程的src/main/resources文件夹中,如果没有自行创建即可
打开bootstrap.properties添加cas跳转地址,用于cas management 单点登录
cas.server.name=http://xxx:xxxx
cas.server.prefix=${cas.server.name}/cas
server.ssl.enabled=false
配置完启动,输入CAS management 地址如(http://localhost:8443/cas-management)会发现一直循环重定向导致地址变成http://localhost:8443/cas-management/cas-management/cas-management/cas-management/cas-management/cas-management/cas-management/cas-management/…
循环重定向问题分析
通过研究cas mgmt源码(源码地址: https://github.com/apereo/cas-management)可以发现cas使用spring security框架进行认证,主要代码位于CasManagementSecurityConfiguration中,而且访问通道只允许https访问,否则中断返回,如下图
具体可自行百度requireSecure方法,解决方法就是将requireSecure改成requiresInsecure,所以解决办法要么就是获取源码通过改源码自行编译依赖,要么就是将该类对应的jar包排除掉,将jar包中的代码拷贝到外面的工程来,本文选择后面一种方式,前面的可由读者自己进行尝试。
解决循环重定向问题
排除官方包
通过源码可知道CasManagementSecurityConfiguration位于cas-mgmt-webapp-config中,所以工程打包的时候需要将该jar包排除,打开gradle/springboot.gradle进行排除,如下图:
将源包中的源码拷贝出来
修改CasManagementSecurityConfiguration代码,将requireSecure改成requiresInsecure,如下图:
并且将配置类添加到META-INF/spring.factories(没有自行创建)中如下图:
解决依赖问题
查看cas-mgmt-webapp-config工程中的build.gradle可以发现里面依赖了其他jar包,所以我们也需要依赖这些jar包
找到自己工程中的build.gradle将依赖添加到dependencies中
implementation libraries.pac4j
implementation libraries.thymeleaf
implementation libraries.casServer.authentication
implementation libraries.casServer.oidc
implementation libraries.springboot
implementation "org.apereo.cas:cas-mgmt-api-configuration:${project.'cas.version'}"
implementation "org.apereo.cas:cas-mgmt-core-authentication:${project.'cas.version'}"
implementation "org.apereo.cas:cas-mgmt-core:${project.'cas.version'}"
我们会发现依赖的时候有libraries.xxxx,这个是gradle自定义变量,位于源码工程根目录中的gradle/dependencies.gradle,然后找到我们需要的变量拷贝到我们工程即可。
ext.libraries = [
thymeleaf : [
dependencies.create("org.thymeleaf:thymeleaf-spring5:$thymeleafVersion") {
exclude(group: "org.slf4j", module: "slf4j-api")
exclude(group: "org.javassist", module: "javassist")
exclude(group: "org.sourceforge.nekohtml", module: "nekohtml")
},
dependencies.create("org.springframework.boot:spring-boot-starter-thymeleaf:$springBootVersion") {
exclude(group: "com.fasterxml", module: "classmate")
exclude(group: "com.fasterxml.jackson.core", module: "jackson-annotations")
exclude(group: "ch.qos.logback", module: "logback-core")
exclude(group: "ch.qos.logback", module: "logback-classic")
exclude(group: "nz.net.ultraq.thymeleaf", module: "thymeleaf-layout-dialect")
exclude(group: "org.springframework.boot", module: "spring-boot-starter-logging")
exclude(group: "org.sourceforge.nekohtml", module: "nekohtml")
}
],
pac4j : [
dependencies.create("org.pac4j:pac4j-cas:$pac4jVersion") {
exclude(group: "org.slf4j", module: "slf4j-api")
exclude(group: "joda-time", module: "joda-time")
exclude(group: "org.slf4j", module: "jcl-over-slf4j")
exclude(group: "commons-collections", module: "commons-collections")
exclude(group: "com.google.guava", module: "guava")
exclude(group: "com.fasterxml.jackson.core", module: "jackson-databind")
exclude(group: "com.fasterxml.jackson.core", module: "jackson-core")
},
dependencies.create("org.pac4j:pac4j-config:$pac4jVersion") {
exclude(group: "org.apache.commons", module: "commons-lang3")
exclude(group: "org.slf4j", module: "slf4j-api")
exclude(group: "com.zaxxer", module: "HikariCP")
exclude(group: "joda-time", module: "joda-time")
exclude(group: "org.springframework", module: "spring-core")
exclude(group: "org.slf4j", module: "jcl-over-slf4j")
exclude(group: "com.fasterxml.jackson.core", module: "jackson-databind")
exclude(group: "com.google.guava", module: "guava")
exclude(group: "org.cryptacular", module: "cryptacular")
exclude(group: "org.bouncycastle", module: "bcprov-jdk15on")
exclude(group: "commons-codec", module: "commons-codec")
exclude(group: "org.apache.httpcomponents", module: "httpclient")
exclude(group: "org.apache.httpcomponents", module: "httpclient-cache")
exclude(group: "commons-httpclient", module: "commons-httpclient")
exclude(group: "commons-collections", module: "commons-collections")
exclude(group: "net.minidev", module: "json-smart")
exclude(group: "org.opensaml", module: "opensaml-core")
exclude(group: "org.opensaml", module: "opensaml-saml-impl")
exclude(group: "org.opensaml", module: "opensaml-saml-api")
exclude(group: "org.opensaml", module: "opensaml-xmlsec-api")
exclude(group: "org.opensaml", module: "opensaml-security-impl")
exclude(group: "org.opensaml", module: "opensaml-profile-api")
exclude(group: "org.opensaml", module: "opensaml-profile-impl")
exclude(group: "org.opensaml", module: "opensaml-soap-api")
exclude(group: "org.opensaml", module: "opensaml-messaging-api")
exclude(group: "org.opensaml", module: "opensaml-messaging-impl")
exclude(group: "org.opensaml", module: "opensaml-xmlsec-impl")
exclude(group: "org.opensaml", module: "opensaml-security-api")
exclude(group: "org.springframework", module: "spring-expression")
exclude(group: "net.shibboleth.ext", module: "spring-extensions")
exclude(group: "net.shibboleth.utilities", module: "java-support")
exclude(group: "xml-apis", module: "xml-apis")
exclude(group: "org.opensaml", module: "xmltooling")
exclude(group: "org.cryptacular", module: "cryptacular")
},
dependencies.create("org.pac4j:pac4j-core:$pac4jVersion") {
exclude(group: "org.slf4j", module: "slf4j-api")
exclude(group: "joda-time", module: "joda-time")
exclude(group: "commons-codec", module: "commons-codec")
exclude(group: "commons-collections", module: "commons-collections")
exclude(group: "org.cryptacular", module: "cryptacular")
exclude(group: "com.fasterxml.jackson.core", module: "jackson-databind")
exclude(group: "com.fasterxml.jackson.core", module: "jackson-core")
exclude(group: "com.zaxxer", module: "HikariCP")
},
dependencies.create("org.pac4j:pac4j-http:$pac4jVersion") {
exclude(group: "org.apache.commons", module: "commons-lang3")
exclude(group: "org.slf4j", module: "slf4j-api")
exclude(group: "joda-time", module: "joda-time")
exclude(group: "org.slf4j", module: "jcl-over-slf4j")
exclude(group: "commons-collections", module: "commons-collections")
exclude(group: "com.fasterxml.jackson.core", module: "jackson-databind")
exclude(group: "com.fasterxml.jackson.core", module: "jackson-core")
},
dependencies.create("org.pac4j:spring-webmvc-pac4j:$pac4jSpringWebmvcVersion") {
exclude(group: "org.springframework", module: "spring-webmvc")
exclude(group: "org.springframework", module: "spring-core")
exclude(group: "org.slf4j", module: "slf4j-api")
exclude(group: "org.pac4j", module: "pac4j-core")
exclude(group: "joda-time", module: "joda-time")
exclude(group: "org.slf4j", module: "jcl-over-slf4j")
exclude(group: "commons-collections", module: "commons-collections")
exclude(group: "com.fasterxml.jackson.core", module: "jackson-databind")
exclude(group: "com.fasterxml.jackson.core", module: "jackson-core")
},
dependencies.create("org.pac4j:spring-security-pac4j:$pac4jSpringSecurityVersion") {
exclude(group: "org.springframework", module: "spring-webmvc")
exclude(group: "org.springframework", module: "spring-core")
exclude(group: "org.springframework", module: "spring-web")
exclude(group: "org.springframework", module: "spring-aop")
exclude(group: "org.springframework", module: "spring-context")
exclude(group: "org.slf4j", module: "slf4j-api")
exclude(group: "org.aspectj", module: "aspectjweaver")
exclude(group: "org.pac4j", module: "pac4j-core")
exclude(group: "joda-time", module: "joda-time")
exclude(group: "org.slf4j", module: "jcl-over-slf4j")
exclude(group: "com.fasterxml.jackson.core", module: "jackson-databind")
exclude(group: "com.fasterxml.jackson.core", module: "jackson-core")
exclude(group: "commons-collections", module: "commons-collections")
}
],
springboot : [
dependencies.create("org.springframework.boot:spring-boot-starter-mail:$springBootVersion") {
exclude(group: "org.springframework.boot", module: "spring-boot-starter-logging")
exclude(group: "org.slf4j", module: "slf4j-api")
exclude(group: "org.slf4j", module: "log4j-over-slf4j")
exclude(group: "org.slf4j", module: "jul-to-slf4j")
exclude(group: "org.springframework", module: "spring-web")
exclude(group: "org.springframework", module: "spring-core")
exclude(group: "org.springframework", module: "spring-webmvc")
exclude(group: "org.springframework", module: "spring-context")
exclude(group: "org.springframework", module: "spring-context-support")
exclude(group: "org.springframework", module: "spring-beans")
},
dependencies.create("org.springframework.boot:spring-boot-starter-web:$springBootVersion") {
exclude(group: "org.slf4j", module: "slf4j-api")
exclude(group: "org.slf4j", module: "log4j-over-slf4j")
exclude(group: "org.slf4j", module: "jul-to-slf4j")
exclude(group: "org.jboss.logging", module: "jboss-logging")
exclude(group: "com.fasterxml", module: "classmate")
exclude(group: "org.hibernate", module: "hibernate-entitymanager")
exclude(group: "org.springframework", module: "spring-web")
exclude(group: "org.springframework", module: "spring-core")
exclude(group: "org.springframework", module: "spring-webmvc")
exclude(group: "org.springframework", module: "spring-context")
exclude(group: "com.fasterxml.jackson.core", module: "jackson-annotations")
exclude(group: "com.fasterxml.jackson.core", module: "jackson-databind")
exclude(group: "org.springframework.boot", module: "spring-boot-starter-json")
exclude(group: "org.springframework.boot", module: "spring-boot-starter-logging")
exclude(group: "org.springframework.boot", module: "spring-boot-starter-actuator")
exclude(group: "org.slf4j", module: "jcl-over-slf4j")
exclude(group: "org.slf4j", module: "jul-to-slf4j")
exclude(group: "org.apache.tomcat.embed", module: "tomcat-embed-core")
exclude(group: "org.apache.tomcat.embed", module: "tomcat-embed-el")
exclude(group: "org.apache.tomcat.embed", module: "tomcat-embed-websocket")
exclude(group: "org.springframework.boot", module: "spring-boot-starter-tomcat")
},
dependencies.create("org.springframework.boot:spring-boot-autoconfigure:$springBootVersion") {
exclude(group: "org.springframework.boot", module: "spring-boot-starter-actuator")
exclude(group: "org.springframework.boot", module: "spring-boot-starter-json")
exclude(group: "org.springframework", module: "spring-web")
exclude(group: "org.springframework", module: "spring-webmvc")
exclude(group: "org.springframework", module: "spring-core")
exclude(group: "org.springframework", module: "spring-context")
exclude(group: "org.hibernate", module: "hibernate-validator")
exclude(group: "org.hibernate", module: "hibernate-core")
exclude(group: "org.hibernate", module: "hibernate-entitymanager")
exclude(group: "org.slf4j", module: "jcl-over-slf4j")
exclude(group: "org.slf4j", module: "jul-to-slf4j")
exclude(group: "com.fasterxml.jackson.core", module: "jackson-databind")
exclude(group: "com.fasterxml.jackson.core", module: "jackson-core")
exclude(group: "com.fasterxml.jackson.datatype", module: "jackson-datatype-jsr310")
},
dependencies.create("org.springframework.boot:spring-boot:$springBootVersion") {
exclude(group: "org.hibernate", module: "hibernate-validator")
exclude(group: "org.hibernate", module: "hibernate-core")
exclude(group: "org.hibernate", module: "hibernate-entitymanager")
exclude(group: "org.springframework", module: "spring-web")
exclude(group: "org.springframework", module: "spring-webmvc")
exclude(group: "org.springframework", module: "spring-core")
exclude(group: "org.springframework", module: "spring-context")
exclude(group: "org.slf4j", module: "slf4j-api")
exclude(group: "org.slf4j", module: "jul-to-slf4j")
},
dependencies.create("org.springframework.boot:spring-boot-properties-migrator:$springBootVersion") {
exclude(group: "org.hibernate", module: "hibernate-validator")
exclude(group: "org.hibernate", module: "hibernate-core")
exclude(group: "org.hibernate", module: "hibernate-entitymanager")
exclude(group: "org.springframework", module: "spring-web")
exclude(group: "org.springframework", module: "spring-webmvc")
exclude(group: "org.springframework", module: "spring-core")
exclude(group: "org.springframework", module: "spring-context")
exclude(group: "org.slf4j", module: "slf4j-api")
exclude(group: "org.slf4j", module: "jul-to-slf4j")
exclude(group: "com.vaadin.external.google", module: "android-json")
exclude(group: "com.vaadin.external.google", module: "android-json")
},
dependencies.create("org.springframework.boot:spring-boot-starter-actuator:$springBootVersion") {
exclude(group: "org.springframework.boot", module: "spring-boot-starter-web")
exclude(group: "org.springframework.boot", module: "spring-boot-starter-logging")
exclude(group: "org.springframework.boot", module: "spring-boot-starter-json")
exclude(group: "com.fasterxml.jackson.core", module: "jackson-annotations")
exclude(group: "com.fasterxml.jackson.core", module: "jackson-databind")
exclude(group: "org.hibernate", module: "hibernate-validator")
exclude(group: "org.hibernate", module: "hibernate-core")
exclude(group: "org.hibernate", module: "hibernate-entitymanager")
exclude(group: "org.springframework", module: "spring-web")
exclude(group: "org.springframework", module: "spring-webmvc")
exclude(group: "org.springframework", module: "spring-core")
exclude(group: "org.springframework", module: "spring-context")
exclude(group: "org.slf4j", module: "slf4j-api")
exclude(group: "org.slf4j", module: "jul-to-slf4j")
},
dependencies.create("org.springframework.boot:spring-boot-actuator:$springBootVersion") {
exclude(group: "com.fasterxml.jackson.core", module: "jackson-annotations")
exclude(group: "com.fasterxml.jackson.core", module: "jackson-databind")
exclude(group: "org.springframework", module: "spring-web")
exclude(group: "org.springframework", module: "spring-webmvc")
exclude(group: "org.springframework", module: "spring-core")
exclude(group: "org.springframework", module: "spring-context")
exclude(group: "org.slf4j", module: "slf4j-api")
}
],
casServer : [
util : [
dependencies.create("org.apereo.cas:cas-server-core-util:$casVersion") {
},
dependencies.create("org.apereo.cas:cas-server-core-notifications:$casVersion") {
},
dependencies.create("org.apereo.cas:cas-server-core-logging-api:$casVersion") {
}
],
utilApi :
dependencies.create("org.apereo.cas:cas-server-core-util-api:$casVersion") {
},
configuration : [
dependencies.create("org.apereo.cas:cas-server-core-api-configuration-model:$casVersion") {
},
dependencies.create("org.apereo.cas:cas-server-core-services:$casVersion") {
},
dependencies.create("org.apereo.cas:cas-server-support-json-service-registry:$casVersion") {
},
],
testCore : [
dependencies.create("org.apereo.cas:cas-server-core-services:$casVersion") {
}
],
core : [
dependencies.create("org.apereo.cas:cas-server-core-util-api:$casVersion") {
},
dependencies.create("org.apereo.cas:cas-server-support-ws-idp-api:$casVersion") {
},
dependencies.create("org.apereo.cas:cas-server-support-grouper-core:$casVersion") {
exclude group: 'org.apereo.cas', module: 'cas-server-core-webflow'
exclude group: 'org.apereo.cas', module: 'cas-server-core-web'
},
dependencies.create("org.apereo.cas:cas-server-support-oidc-services:$casVersion") {
},
dependencies.create("org.apereo.cas:cas-server-support-oidc-core:$casVersion") {
}
],
versionControl : [
],
audit :
dependencies.create("org.apereo.cas:cas-server-core-audit-api:$casVersion") {
},
ldap :
dependencies.create("org.apereo.cas:cas-server-support-ldap-core:$casVersion") {
},
personDirectory:
dependencies.create("org.apereo.cas:cas-server-support-person-directory:$casVersion") {
},
discovery :
dependencies.create("org.apereo.cas:cas-server-support-discovery-profile:$casVersion") {
transitive = false
},
saml : [
dependencies.create("org.apereo.cas:cas-server-support-saml-core-api:$casVersion") {
transitive = false
},
dependencies.create("org.apereo.cas:cas-server-support-saml-idp-core:$casVersion") {
transitive = false
},
dependencies.create("org.apereo.cas:cas-server-support-saml-idp-metadata:$casVersion") {
transitive = false
},
dependencies.create("org.apereo.cas:cas-server-support-saml-idp-web:$casVersion") {
transitive = false
}
],
services : [
dependencies.create("org.apereo.cas:cas-server-core-services-api:$casVersion") {
},
dependencies.create("org.apereo.cas:cas-server-support-surrogate-api:$casVersion") {
},
dependencies.create("org.apereo.cas:cas-server-core-services-registry:$casVersion") {
}
],
authentication : [
dependencies.create("org.apereo.cas:cas-server-core-authentication-api:$casVersion") {
},
dependencies.create("org.apereo.cas:cas-server-core-authentication-attributes:$casVersion") {
}
],
oauth : [
dependencies.create("org.apereo.cas:cas-server-support-token-core-api:$casVersion") {
exclude group: 'org.apereo.cas', module: 'cas-server-core-webflow'
},
dependencies.create("org.apereo.cas:cas-server-support-oauth-api:$casVersion") {
exclude group: 'org.apereo.cas', module: 'cas-server-core-webflow'
},
dependencies.create("org.apereo.cas:cas-server-support-oauth-services:$casVersion") {
},
dependencies.create("org.apereo.cas:cas-server-support-oauth-core-api:$casVersion") {
exclude group: 'org.apereo.cas', module: 'cas-server-core-webflow'
},
dependencies.create("org.apereo.cas:cas-server-core-services-authentication:$casVersion") {
}
],
oidc :
dependencies.create("org.apereo.cas:cas-server-support-oidc-core:$casVersion") {
},
web :
dependencies.create("org.apereo.cas:cas-server-core-web-api:$casVersion") {
}
]
]
里面的版本号,可以在源码工程根目录上的gradle.properties中找到
casVersion=6.5.3
thymeleafVersion=3.0.15.RELEASE
pac4jSpringWebmvcVersion=5.1.0
pac4jVersion=5.3.1
pac4jSpringSecurityVersion=7.0.0
至此改造完毕,重新编译启动工程。输入地址
总结
由于本人对spring security不太懂,所以整个解决过程很繁琐,实际核心就是想把CasManagementSecurityConfiguration中的requireSecure改成requiresInsecure,如果有更好的办法也请麻烦告诉我一下,我总觉得这个方法很笨。
官方文档: https://apereo.github.io/cas/6.6.x/index.html
Cas management地址: https://github.com/apereo/cas-management
模板工程地址: https://github.com/apereo/cas-management-overlay