Apereo CAS 爬坑

心血来潮想给公司搭个单点登录系统,毕竟内网这么多系统,每个系统都一套账号密码,这样好low。CAS提供了一个统一认证服务,所有系统直接向CAS去请求登陆认证,而用户只在CAS登陆一次就够了,在大一点的公司里基本都有这种服务,叫SSO(Single sign-on)。
找了找开源的SSO,看到了CAS,感觉挺屌的,一直在更新,就他了。然后就开始爬坑了,记录一下,免得日后忘了又爬一次。

CAS-Overlay-Template

这个项目很大,还需要很多自定义配置,所以不可能做成开箱即用。CAS-Overlay-Template 就是一个模板项目,clone下来, 修改配置,然后是直接跑还是打包war或者打包docker都好说。
新版本的 CAS-Overlay-Template 已经改为Gradle编译,我喜欢Gradle。
clone下来后,直接 先运行
./build.sh copy
再运行
./build.sh run
就跑起来了。

编译配置

跑起来个屁。
默认是CAS 6.0版本,直接用Java11了,要跑6.0版本先去装个jdk11,配好环境。我踩坑的时候6.0还是RC版本,发现有bug就还是滚回5.3.5,配置这些东西在gradle.properties

# Versions
cas.version=5.3.5  // 可以改成6.0.0-rc3
springBootVersion=2.1.0.RELEASE

appServer=-tomcat

gradleVersion=4.10.2
tomcatVersion=9
tomcatFullVersion=9.0.12

group=你的组织名
sourceCompatibility=8   // 6.0以上就改成11
targetCompatibility=8    // 6.0以上就改成11

# Location of the downloaded CAS shell JAR
shellDir=build/libs

# use without "-slim" in tag name if you want tools like jstack, adds about 100MB to image size
baseDockerImage=openjdk:8-slim   // 6.0以上就改成11

同时,还有增加几个依赖,因为CAS完全是插件化设计

    compile "org.apereo.cas:cas-server-support-jdbc:${casServerVersion}"
    compile "org.apereo.cas:cas-server-support-jdbc-drivers:${casServerVersion}"
    compile "org.apereo.cas:cas-server-support-pm:${casServerVersion}"
    compile "org.apereo.cas:cas-server-support-pm-jdbc:${casServerVersion}"

然后下1个小时依赖就可以跑起来了,可喜可贺,可喜可贺。

配置目录

image.png

这个目录,里面包含了所有的配置,基本上改这里面的东西就够了。

这个配置目录是如何生效的?

之所以先运行 ./build.sh copy 是因为

function copy() {
    echo -e "Creating configuration directory under /etc/cas"
    mkdir -p /etc/cas/config

    echo -e "Copying configuration files from etc/cas to /etc/cas"
    cp -rfv ./etc/cas/* /etc/cas
}

他会把配置文件复制进系统配置目录,然后 Springboot 启动后会去读这个系统配置目录。
另外,注意一下 src/main/jib/docker/entrypoint.sh 里面是类似 Dockerfile

#!/bin/sh

#echo -e "\nChecking java..."
#java -version

#echo -e "\nCreating CAS configuration directories..."
mkdir -p /etc/cas/config
mkdir -p /etc/cas/services

#echo "Listing provided CAS docker artifacts..."
#ls -R docker/cas

#echo -e "\nMoving CAS configuration artifacts..."
mv docker/cas/thekeystore /etc/cas 2>/dev/null
mv docker/cas/config/*.* /etc/cas/config 2>/dev/null
mv docker/cas/services/*.* /etc/cas/services 2>/dev/null

#echo -e "\nListing CAS configuration under /etc/cas..."
#ls -R /etc/cas

echo -e "\nRunning CAS..."
exec java -Xms512m -Xmx2048M -XX:+TieredCompilation -XX:TieredStopAtLevel=1 -jar docker/cas/war/sso.war

打包镜像时,也会直接把配置目录复制进镜像的系统配置目录

build.sh

常用操作 build.sh 都已经写好了,常用的比如

  • ./build.sh copy 复制配置到系统目录
  • ./build.sh run 运行CAS
  • ./build.sh docker 打包镜像
  • ./build.sh debug Debug CAS

配置

然后几乎所有的服务配置都在 cas/config/cas.properties
一点一点的补充吧,把example.com换成自己的域名。
下面是 5.3.5的配置,5.2.x 的配置不一样,6.0.0也不一样,文档没写,我也不写🙂。
后文会介绍怎么去源码看当前版本的配置项

服务地址

cas.server.name=http://sso.example.com
cas.server.prefix=${cas.server.name}    //要使用根Path访问,比如 http://sso.example.com 就这样。默认值是`${cas.server.name}/cas`
server.context-path=      //对,就是空,这样就可以使用根Path访问了,默认值是 /cas
server.port=443    // HTTPS的端口,默认8443
cas.server.http.enabled=true    // 开启HTTP,默认只有HTTPS,而且我只知道怎么开HTTP,不知道怎么关HTTPS
cas.server.http.port=80  // 设置HTTP端口,默认8080

上面这几个配置挺操蛋的,我以为 cas.server.prefix 改了就可以 http://sso.example.com 直接访问了,结果还是要加上/cas才能访问,这个配置是假的,只是用于各种重定向url填充用。server.context-path 才是真正的 Path。

数据库认证

cas.authn.accept.users=        // 留空才会禁用 Static Authentication
cas.authn.jdbc.query[0].dialect=org.hibernate.dialect.MySQLDialect
cas.authn.jdbc.query[0].driverClass=com.mysql.jdbc.Driver
cas.authn.jdbc.query[0].url=jdbc:mysql://xxxxxxxxxxxxxxxx?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&useSSL=false
cas.authn.jdbc.query[0].user=xxxxxxx
cas.authn.jdbc.query[0].password=xxxxxxxxx
cas.authn.jdbc.query[0].sql=select * from user where name=?

// 这些配置懒得讲了,网上大部分文章讲的都没问题
cas.authn.jdbc.query[0].fieldPassword=password    
cas.authn.jdbc.query[0].fieldExpired=expired
cas.authn.jdbc.query[0].fieldDisabled=disabled
cas.authn.jdbc.query[0].passwordEncoder.type=DEFAULT
cas.authn.jdbc.query[0].passwordEncoder.characterEncoding=UTF-8
cas.authn.jdbc.query[0].passwordEncoder.encodingAlgorithm=MD5

配置数据库认证很简单。去给数据库建个表。填一下字段名和Sql,就可以了。然后跑一下试试吧

密码管理-邮件

CAS支持密码管理功能,直接网页上点忘记密码,就给你邮箱发重置邮件,配置比较多,坑也很多

# 发送邮件,我用的腾讯企业邮
spring.mail.host=smtp.exmail.qq.com
spring.mail.port=465
spring.mail.username=xxxxxx@example.com
spring.mail.password=xxxxxxx

# 这是腾讯企业邮的配置,其他邮箱自己配,可能有些坑,但这个不管CAS的事
spring.mail.properties.mail.smtp.auth=true
spring.mail.properties.mail.smtp.socketFactory.port=465
spring.mail.properties.mail.smtp.socketFactory.class=javax.net.ssl.SSLSocketFactory
spring.mail.properties.mail.smtp.socketFactory.fallback=false
spring.mail.properties.mail.smtp.ssl=true

密码管理-数据库

改改自己的SQL就好了

cas.authn.pm.enabled=true    // 开启修改密码功能
cas.authn.pm.autoLogin=true  // 修改密码后自动登录
cas.authn.pm.jdbc.autocommit=true  // 加就是了
cas.authn.pm.jdbc.sqlFindEmail=SELECT email FROM user WHERE name=?
cas.authn.pm.jdbc.sqlChangePassword=UPDATE user SET password=? WHERE name=?
cas.authn.pm.jdbc.url=${cas.authn.jdbc.query[0].url}
cas.authn.pm.jdbc.user=${cas.authn.jdbc.query[0].user}
cas.authn.pm.jdbc.password=${cas.authn.jdbc.query[0].password}
cas.authn.pm.jdbc.dialect=${cas.authn.jdbc.query[0].dialect}
cas.authn.pm.jdbc.driverClass=${cas.authn.jdbc.query[0].driverClass}
# 密码修改加密规则,这个必须要和原始密码加密规则一致
cas.authn.pm.jdbc.passwordEncoder.type=${cas.authn.jdbc.query[0].passwordEncoder.type}
cas.authn.pm.jdbc.passwordEncoder.characterEncoding=${cas.authn.jdbc.query[0].passwordEncoder.characterEncoding}
cas.authn.pm.jdbc.passwordEncoder.encodingAlgorithm=${cas.authn.jdbc.query[0].passwordEncoder.encodingAlgorithm}
cas.authn.pm.jdbc.passwordEncoder.secret=${cas.authn.jdbc.query[0].passwordEncoder.secret}

密码管理-业务配置

cas.authn.pm.reset.mail.from=${spring.mail.username}
cas.authn.pm.reset.mail.subject=[XXX公司 SSO系统] 重置密码
# 邮件内容,必须要有%s,因为会生成一个连接并且带了token,否则无法打开链接,当然这个链接也和cas.server.prefix有关系
cas.authn.pm.reset.mail.text=[季诺科技 SSO]打开以下链接重置您的密码,10分钟后失效: %s
cas.authn.pm.reset.expirationMinutes=10  // 邮件有效期
cas.authn.pm.reset.securityQuestionsEnabled=false    // 问题验证,我觉得这个操作很蠢,就关了
# 8-32位,必须包含大小写字母,数字,字符。你可以填其他密码检验正则
cas.authn.pm.policyPattern=^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)(?=.*[$@$!%*?&])[A-Za-z\\d$@$!%*?&]{8,32}

神坑

路由转发环境下的IP校验

到这里可能本地跑起来没问题了,修改密码都正常。一部署到线上就不能修改密码,从邮箱验证链接点过去,CAS每次都拒绝此次密码修改请求。为啥?
翻了大片的源码,终于找到了原因。邮箱里收到的链接参数是加了密的,取消加密的话就很容易看出问题。

http://sso.example.com/login?pswdrst={"jti":"ad06632d-dcee-43e0-bf0f-639150912b96","iss":"http://sso.example.com","aud":"http://sso.example.com","exp":1542541827,"iat":1542541227,"origin":"17*.17*.0.11","client":"1*.1*.97.138","sub":"jude"}

token里包含了请求邮件验证时的客户端IP,也不知道为啥,Nginx转发后,他拿到的IP就老是不对,点击链接访问时,IP对不上他就不认这次请求。
普通的直接部署的CAS系统,不加这个没问题。但我们的内网环境是有一台Nginx路由,所有请求都会经过他转发,就出问题。
差点去改源码了,好在无聊翻源码时找到,CAS原来留了一手来处理这个问题。

cas.audit.alternateClientAddrHeaderName=X-Forwarded-For

添加这个配置, CAS就会从Header里读X-Forwarded-For来确认客户端IP,这样就不存在转发后IP不对的问题了。

6.0版本的密码修改BUG

我也不清楚6.0版本加了找回用户名这个积累功能后,为啥找回密码页面他老是发请求到找回用户名的接口上去。导致找回密码和找回用户名2个功能都不能正常工作。源码好多,对JSP无力,没细查,改回5.3.5,BUG消失,放弃6.0。

找配置文档

我上面的配置有很多,官网文档写的很糟,又少又老还跳来跳去,还每个版本都要改配置项(5.2.x, 5.3.x, 6.0.x都很多不一样)。
网上大部分文档都是5.2版本的祖传配置,一开始真是恶心死我了。
还是得自己去翻源码,先找到 CasServerProperties 这个类,他在

image.png

这个类就是配置的映射,还有少数注释讲了很多官方文档没说的操作。
image.png

照着这个类来填配置就行了。

弃坑

好不容易终于跑起来这个坑B玩意了,但十分不建议使用CAS,CAS优势是开放,适合二次开发。
但十分难用......去用keycloak吧。配置简单,界面还好看。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,242评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,769评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,484评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,133评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,007评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,080评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,496评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,190评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,464评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,549评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,330评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,205评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,567评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,889评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,160评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,475评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,650评论 2 335