CAS入门

CAS简介

CAS(Central Authentication Service)是一个

  • 开源的
  • 企业级的
  • 支持多语言(Java, .Net, Python, PHP...)的
  • SSO(single sign-on, 单点登录)
  • authentication(认证)
  • authorization(授权)

解决方案,

  • 适用于web平台
  • 其核心是由Java和Spring实现,
  • CAS支持多种协议CAS, SAML v1, SAML v2, WS-Federation,OAuth2, OpenID, OpenID Connect, REST,
  • 支持插件式(Pluggable)的认证LDAP, Database, X.509, SPNEGO, JAAS, JWT, RADIUS, MongoDb, …,
  • 支持MFA(multifactor authentication)、代理认证(delegated authentication)、实时监控、统一日志管理与输出…
    在这里插入图片描述

CAS系统包含两个核心组件,即CAS server和CAS client,
且CAS server和CAS clients是一对多的关系,即一个CAS server可以对应多个CAS client。

CAS Server即认证的服务端,负责认证用户,授予用户访问权(即向CAS client颁发tickets),

CAS clients即认证的客户端,需要用户认证的具体web服务,
即指代应用(任何支持CAS协议的应用 或者 集成client软件包的应用,亦称为CAS applications, CAS services),
又指代软件包(即特定编程语言支持的软件包,通过认证协议如CAS, SAML, OAuth与CAS Server进行交互),
通常没有特殊说明,CAS client即指的软件包,
例如: Java CAS Client.NET CAS ClientPycas, …



CAS协议

关于CAS server和client的具体职责及交互,可参考CAS 3.0.3协议时序图
整个时序图即描绘了一个完整的SSO过程。
在这里插入图片描述
注:
Protected App:受保护的应用,即集成CAS client软件包的web服务,需要用户认证通过后,携带用户凭证才可访问该应用。

关于CAS协议时序图的具体说明如下:

First Access(首次访问web服务)

(1)用户通过浏览器访问web服务(Protected App);
(2)web服务判断用户是否登录,若未登录(没有session cookie或者session不存在,此处的session为web服务对应的session),则重定向到CAS Server登录界面且携带query参数service(需要URL encoded),该service参数对应CAS Server认证成功后重定向回web服务的url;

302 Location: https://cas.example.com/cas/login?service=https://app.example.com

(3)浏览器重定向到CAS Server登录界面,即请求CAS Server,此时CAS Server检测该请求是否包含SSO Session(CASTGC),若不存在TGC,则返回具体的登录表单form;

TGC(Ticket Granting Cookie):CAS server用于存储用户session id的cookie,实际对应CASTGC
TGT(Ticket Granting Ticket):代表CAS用户session id,存储在浏览器的TGC cookie中
ST (Service Ticket):在CAS Server登录成功后,通过url(即service参数对应的url)中的GET参数ticket传递给具体CAS client,后续CAS client需验证该ST并获取到对应的用户信息

(4)用户在CAS登录表单填写正确的用户名密码后,点击提交按钮后将登录请求发送到CAS Server,CAS Server验证用户信息无误后,生成当前用户session并写入CASTGC到浏览器cookie中,并重定向请求回web服务,且重定向url中包含ticket参数

Set-Cookie: CASTGC=TGT-2345678
302 Location: https://app.example.com/?ticket=ST-12345678

(5)浏览器重定向到web服务,即请求web服务(Protected App),web服务需要请求CAS Server来验证url参数ticket(即ST),CAS Server返回一个XML响应体,该XML中包含是否验证成功、被认证的用户信息、可选属性。

# 浏览器重定向到web服务
https://app.example.com/?ticket=ST-12345678
# web服务调用CAS server验证ticket
https://cas.example.com/serviceValidate?service=https://app.example.com&ticket=ST-12345678

(6)验证通过后,web服务可根据CAS验证结果生成当前web服务自身的用户session及cookie,并使浏览器重定向到web服务的具体path(省去ticket参数,避免长时间暴露在浏览器地址栏中)

Set-Cookie: JSESSIONID=ABC1234567
302 Location: https://app.example.com

Second Access To Same Application(后续访问同一个登录过的web服务)

(7)之后再向web服务在发送请求时,即会携带自身的cookie,web服务后端仅需验证session cookie的合法性即可,验证通过后则返回具体请求内容。

Cookie: JSESSIONID=ABC1234567
GET https://app.example.com/

First Access To Second Application(首次访问其他的web服务)

(8)用户通过浏览器访问另一个web服务2(Protected App # 2);
(9)web服务2判断用户是否登录,若未登录(没有session cookie或者session不存在,此处的session为web服务2对应的session),则重定向到CAS Server登录界面且携带query参数service(需要URL encoded),该service参数对应CAS Server认证成功后重定向回web服务2的url;

302 Location: https://cas.example.com/cas/login?service=https://app2.example.com

注: 其中(8)(9)同之前的(1)(2)
(10)浏览器重定向到CAS Server登录界面,即请求CAS Server,由于之前已在浏览器中登录过CAS Server,所以浏览器中CAS Server域名下已经有CASTGC cookie,故再次向CAS Server发起请求时便会携带该CASTGC cookie,此时CAS Server检测该请求发现已经包含SSO Session(CASTGC),即此时已为登录态,则直接重定向到web服务2且重定向url中包含ticket参数;

# 请求CAS server登录界面
Cookie: CASTGC=TGT-2345678
GET https://cas.example.com/cas/login?service=https://app2.example.com
# 重定向到web服务2
Set-Cookie: CASTGC=TGT-2345678
302 Location: https://app2.example.com/?ticket=ST-3455678

(11)浏览器重定向到web服务2,即请求web服务2(Protected App #2),之后重复第(5)(6)(7)步,
即web服务2调用CAS server验证ticket,web服务2生成自身的用户session及cookie、重定向回web服务2,发送到web服务2的请求携带自身的cookie。

两种session

在整个过程中出现两种session:
(1)CAS Server的用户session,对应CAS server域名下的TGC,该TGC仅对CAS server可见,用来标记用户是否已在CAS server端进行过登录,即全局的登录状态,用于SSO,即由CAS server来统一管理用户登录状态(用户认证),在CAS server中登录成功,则接入该CAS server的CAS Clients均为登录成功,无需用户再次输入账户密码,直接跳转到登录回调URL(对应service参数);
(2)web服务的用户session,对应各自web服务域名下的session cookie,仅对各自的web服务可见,用来标记用户已在web服务中分别登录过,各自集成CAS client的web服务在ST验证通过后需要生成各自的session,即web服务需要维护各自的登录态session;



快速启动CAS server

注: 示例中的cas 6.4.x需要依赖JDK 11,所以需要先安装openjdk11并且设置相关环境变量

(1)下载CAS Initializer并解压缩
https://casinit.herokuapp.com/starter.tgz?type=cas-overlay&baseDir=cas-overlay
注: 详细的可参考:cas/6.4.x - WAR Overlay Initializr

在这里插入图片描述
查看README.md内容,并按照内容提示在cas-overlay根目录下依次执行以下命令

(2)构建cas.war

# 构建cas.war(war包输出在build/libs/cas.war)
# Use --refresh-dependencies to force-update SNAPSHOT versions
gradlew clean build

在这里插入图片描述

(3)创建keystore(即https证书)

# 创建keystore,
# 如下命令会生成该cas-server对应的https证书,生成的证书存储在根目录/etc/cas下
gradlew createKeystore

注:
在windows环境环境执行执行以上命令会报错
在这里插入图片描述
即在windows环境无法定位到根目录/,此处需修改gradle.properties中certDir属性:

...
# certDir由原来的/etc/cas修改为D:/etc/cas
# 在windows系统下根目录即对应盘符根目录,比如cas-overlay在D盘下,则根目录则为D:/,即D:/etc/cas
certDir=D:/etc/cas
serverKeystore=thekeystore
exportedServerCert=cas.crt
storeType=PKCS12
...

查看build.gradle文件中

task createKeystore(group: "CAS", description: "Create CAS keystore") { ... }

发现该createKeystore命令其实对应为如下命令:

# Generating keystore for CAS with DN "CN=cas.example.org,OU=Example,OU=Org,C=US"
keytool -genkeypair -alias cas ^
-keyalg RSA ^
-keypass changeit  ^
-storepass changeit ^
-keystore D:/etc/cas/thekeystore ^
-dname CN=cas.example.org,OU=Example,OU=Org,C=US  ^
-ext SAN=dns:example.org,dns:localhost,ip:127.0.0.1 ^
-storetype PKCS12

# Exporting cert from keystore...
keytool -exportcert ^
-alias cas ^
-storepass changeit ^
-keystore D:/etc/cas/thekeystore ^
-file D:/etc/cas/cas.crt

在这里插入图片描述

同时为了后续的CAS client在通过https请求调用CAS server相关接口(如验证ticket)不发生SSL handshake错误,
需要将生成的D:/etc/cas/cas.crt导入到JDK/JRE中,通过keytool导入命令如下

# 导入证书
keytool -import -keystore "D:/programs/dev/java/jdk-11/lib/security/cacerts" -file D:/etc/cas/cas.crt -alias cas
# 删除证书(该命令仅在需要删除证书时执行,非必需执行)
keytool -delete -alias cas -keystore "D:/programs/dev/java/jdk-11/lib/security/cacerts"

在这里插入图片描述

注:
导入后需重启系统后方可生效,
我本地装有jdk8和jdk11,keytool导入时是在jdk11上执行的,而后续client是执行在jdk8上,
所以client通过https调用CAS server时一直报https验证错误,
后续将client也执行在jdk11上即问题消失,此处需要注意执行keytool导入的jdk和CAS server、CAS client执行的jdk需要保持一致

(4)拷贝配置
执行如下命令将cas-overlay/etc/cas/config下的配置文件拷贝到根目录下/etc/cas/config(在windows系统下根目录即对应盘符根目录,比如cas-overlay在D盘下,则根目录则为D:/,即D:/etc/cas/config),
在之后启动cas.war时会自动到/etc/cas/config下读取配置文件

gradlew copyCasConfiguration

在这里插入图片描述

(5)添加用户
修改之前拷贝的配置文件D:/etc/cas/config/cas.properties,添加如下内容:

# 添加账户(用户名为luo,密码为123456)
cas.authn.accept.users=luo::123456

在这里插入图片描述

(6)注册CAS Service(即注册CAS Client应用信息)
修改之前拷贝的配置文件D:/etc/cas/config/cas.properties,添加如下内容使CAS Server从JSON文件中读取service注册信息:

# 从JSON文件读取service注册信息
cas.service-registry.core.init-from-json=true
# service注册对应的JSON文件目录位置
# 可通过classpath:指定resource目录
# 本示例直接指定根目录下/etc/cas/services,即对应D:/etc/cas/services
cas.service-registry.json.location=file:/etc/cas/services

创建service注册对应的JSON文件,建议文件名称遵循{name}-{id}.json,如下配置即对应casSecureApp-1.json

{
  "@class" : "org.apereo.cas.services.RegexRegisteredService",
  //servcieId通过正则表达式定义client应用的URL pattern,该URL模式应该匹配client的URL
  //如"^(https|http)://.*"
  "serviceId" : "http://localhost:8900/login/cas",
  //client的名称
  "name" : "casSecuredApp",
  //client的唯一的ID
  "id" : 1,
  //登出类型
  "logoutType" : "BACK_CHANNEL",
  //登出回调
  "logoutUrl" : "http://localhost:8900/exit/cas"
}

在这里插入图片描述
且使用JSON文件注册service需在build.gradle添加依赖如下:

implementation "org.apereo.cas:cas-server-support-json-service-registry"

在这里插入图片描述

(7)启动CAS server

# 通过gradle启动
gradlew run
# 或者直接通过java命令启动
java -jar build/libs/cas.war

如下看到READY即为启动成功
在这里插入图片描述

(8)访问CAS server
启动成功后即可通过https://localhost:8443/cas进行访问,此时亦可发现之前生成的https证书已生效。
在这里插入图片描述

可通过之前第(6)步添加的用户进行登录,即luo/123456,登录成功后如下图
在这里插入图片描述


SpringSecurity集成CAS

SpringSecurity集成CAS具体可参见示例代码:https://github.com/marqueeluo/cas-secured-app
CAS Server(即cas-overlay)具体可参见示例代码:https://github.com/marqueeluo/cas-overlay

其中cas-secured-app中的核心cas配置如下:

# CAS server基础URL
cas.server.base-url=https://localhost:8443/cas
# CAS server登录页面URL
cas.server.login-url=https://localhost:8443/cas/login
# CAS server登出URL
cas.server.logout-url=https://localhost:8443/cas/logout
# CAS client基础URL
cas.client.base-url=http://localhost:8900
# CAS client service参数(需匹配CAS service注册中的serviceId)
cas.client.service=http://localhost:8900/login/cas
# CAS client在当前应用中登出cas的urlPath(请求该url则自动重定向到cas.server.logout-url)
cas.client.logout-cas-path=/logout/cas
# CAS client在当前应用中单点登出的回调urlPath
cas.client.slo-callback-path=/exit/cas



后续…

后续有时间会进一步记录

参考:
https://apereo.github.io/cas/6.4.x/planning/Architecture.html
https://apereo.github.io/cas/6.4.x/installation/WAR-Overlay-Initializr.html
Maven的overlay插件的用法【结合cas4.0.3】
Stackoverflow - Difference Between OAUTH, OpenID and OPENID Connect in very simple term?
https://www.baeldung.com/spring-security-cas-sso
CSDN - CAS服务器5.3搭建

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

罗小爬EX

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值