CAS原理技术
- 背景
- 介绍
- 结构体系
- 术语
- 接口
- 原理
- 基础模式
- 1. 首次访问集成CAS Client的应用
- 2. 再次访问集成CAS Client的同一应用
- 3. 访问集成CAS Client的其他应用
- 代理模式
- 1. 用户在代理服务器上执行身份认证
- 2. 通过代理应用访问其他应用上授权性资源
背景
本文内容大多基于网上其他参考文章及资料整理后所得,并非原创,目的是为了需要时方便查看。
介绍
CAS,Central Authentication Service,统一认证服务,是耶鲁大学发起的一个企业级开源项目,旨在为Web应用系统提供一种可靠的单点登录解决方案。
SSO,Single Sign On,单点登录,指在多个应用系统中,用户只需登录一次就可以访问所有相互信任的应用系统。
CAS和SSO的关系:SSO是一种思想理念,CAS是SSO的一个具体实现。
结构体系
CAS包含两部分:
- CAS Server
负责完成对用户的认证工作,需要独立部署,CAS Server处理用户凭证(Credentials),如用户名/密码。 - CAS Client
负责处理对受保护资源的访问请求,通常与受保护资源所在应用部署在一起,以Filter
形式保护被限制访问的资源。
术语
- KDC:Key Distribution Center
密钥发放中心。 - AS:Authentication Service
认证服务,根据凭证(Credentials)签发TGT(Ticket Granting Ticket)。 - ST:Service Ticket
服务票据,服务的唯一标识码,由CAS Server签发(HTTP传输),一个特定服务只能有一个唯一的ST。 - TGS:Ticket Granting Service
票据授权服务,根据TGT(Ticket Granting Ticket)签发ST(Service Ticket)。 - TGT:Ticket Granting Ticket
由KDC的AS签发的登录票据,拥有过TGT证明该用户已在CAS上成功登录。TGT封装了Cookie值以及此Cookie值对应的用户信息。获取了TGT后,以后申请服务票据(ST,Service Ticket)时便不再需要向KDC提交身份认证信息(Credentials)。 - TGC:Ticket Granting Cookie
存放身份认证凭证的Cookie,在浏览器和CAS Server间通信时使用,只能基于安全通道传输(HTTPS),是CAS Server用来明确用户身份的凭证。 - PT:Proxy Ticket
应用程序代理用户身份对目标程序进行访问的凭证。 - PGT:Proxy Granting Ticket
由CAS Server签发给拥有ST凭证的服务,PGT绑定一个用户的特定服务,使其拥有向CAS Server申请获得PT的能力。 - PGTIOU:Proxy Granting Ticket I Owe You
将通过凭证校验时的应答信息由CAS Server返回给CAS Client,同时,与该PGTIOU对应的PGT将通过回调链接传给Web应用,Web应用负责维护PGTIOU与PGT之间映射关系的内容表。
接口
/login
:登录接口/logout
:登出接口/validate
:验证用户是否登录中心服务器/serviceValidate
:提供给每个业务服务,用于验证用户是否已登录中心服务器
原理
基础模式
1. 首次访问集成CAS Client的应用
- 用户访问应用A(
https://a.com/
); - 浏览器发送GET请求(
GET https://a.com/
)到应用A服务器; - 应用A服务器收到请求后,在请求 Cookie 中并未找到 session,将请求重定向到CAS服务器的登录接口(
302 Location http://cas.com/cas/login?service=https%3A%2F%2Fa.com%2F
),重定向URL中携带 service 请求参数,值为 编码后的用户访问的应用A地址(https://a.com/
); - 浏览器收到来自应用A服务器的重定向响应后,发送请求到CAS服务器的登录接口(
GET http://cas.com/cas/login?service=https%3A%2F%2Fa.com%2F
); - CAS服务器接收到请求后,在请求 Cookie 中并未找到带有 CASTGC,说明发起请求的客户端身份尚未认证,返回统一登录表单页;
- 用户在CAS返回的统一登录表单页上填写用于身份认证的凭证(通常是用户名/密码),然后向CAS服务器发起身份认证请求(
POST https://cas.com/cas/login?service=https%3A%2F%2Fa.com%2F
); - CAS认证身份成功,生成一个TGT(Ticket Granting Ticket)并写入响应的Cookie(
Set-Cookie: CASTGC=TGT-2345678
),同时根据URL中的 service 请求参数(service=https%3A%2F%2Fa.com%2F
)为应用A生成一个ST(Service Ticket),将请求重定向到用户访问的应用A地址,并添加请求参数 ticket(Set-Cookie: CASTGC=TGT-2345678 302 Location: https://a.com/?ticket=ST-12345678
); - 浏览器收到来自CAS服务器的重定向响应后,发送请求到应用A服务器(
GET https://a.com?ticket=ST-12345678
); - 应用A服务器收到浏览器请求后,取出 ticket 请求参数,向CAS服务器发起认证 ticket 合法性的请求(
GET https://cas.com/serviceValidate?service=https%3A%2F%2Fa.com%2F&ticket=ST-12345678
); - CAS服务器验证 ticket 合法后返回
200 [XML Content]
,其中包含验证成功结果、认证对象及一些可选属性; - 应用A服务器得到 ticket 合法的认证结果后,生成一个 session 写入响应的 Cookie(图中的 JSESSIONID 是Tomcat生成的),并返回浏览器一个重定向地址,此地址指向用户最初发起访问请求的地址(
Cookie: JSESSIONID=ABC1234567 302 Location: https://a.com/
); - 浏览器接收到重定向响应后再次向应用A发起访问请求,请求的 Cookie 中携带应用A返回的 JSESSIONID(
Cookie: JSESSIONID=ABC1234567 GET https://a.com/
); - 应用A服务器验证浏览器请求Cookie中 JSESSIONID 合法后返回实际资源。
2. 再次访问集成CAS Client的同一应用
- 用户使用同一浏览器访问应用A的资源;
- 浏览器发送GET请求到应用A服务器(
GET http://a.com/resource
),注意,因为在上一步中应用A已经给浏览器写入了带有 JSESSIONID 的Cookie,因此此时发送的GET请求的Cookie中也有这部分信息(Cookie: JSESSIONID=ABC1234567
); - 应用A接收到资源访问请求后,验证请求Cookie中 session 是否合法,如果合法则返回用户请求的资源信息。
3. 访问集成CAS Client的其他应用
- 用户使用同一浏览器访问应用B,应用B和应用A共用一套CAS;
- 浏览器发送GET请求(
GET https://b.com/
)到应用B服务器; - 应用B服务器收到请求后,在请求 Cookie 中并未找到 session,将请求重定向到CAS服务器的登录接口(
302 Location http://cas.com/cas/login?service=https%3A%2F%2Fb.com%2F
),重定向URL中携带 service 请求参数,值为 编码后的用户访问的应用B地址(https://b.com/
); - 浏览器收到来自应用B服务器的重定向响应后,发送请求到CAS服务器的登录接口(
Cookie: CASTGC=TGT-2345678 GET http://cas.com/cas/login?service=https%3A%2F%2Fb.com%2F
),注意:因为之前访问应用A时CAS已执行身份认证并写入 CASTGC 到 Cookie 中,因此浏览器向CAS服务器发送的后续请求中都会带上此 Cookie; - CAS服务器接收到请求后,验证请求 Cookie 中的 CASTGC 合法,根据URL中的 service 请求参数(
service=https%3A%2F%2Fb.com%2F
)为应用B生成一个ST(Service Ticket),将请求重定向到用户访问的应用B地址,并添加请求参数 ticket(302 Location: https://b.com/?ticket=ST-345678
); - 浏览器收到来自CAS服务器的重定向响应后,发送请求到应用B服务器(
GET https://b.com?ticket=ST-345678
); - 应用B服务器收到浏览器请求后,取出 ticket 请求参数,向CAS服务器发起认证 ticket 合法性的请求(
GET https://cas.com/serviceValidate?service=https%3A%2F%2Fb.com%2F&ticket=ST-345678
); - CAS服务器验证 ticket 合法后返回
200 [XML Content]
,其中包含验证成功结果、认证对象及一些可选属性; - 应用B服务器得到 ticket 合法的认证结果后,生成一个 session 写入响应的 Cookie(
Set-Cookie: MOD_AUTH_CAS_S=XYZ1234567
),并返回浏览器一个重定向地址,此地址指向用户最初发起访问请求的地址(302 Location: https://b.com/
); - 浏览器接收到重定向响应后再次向应用B发起访问请求,请求的 Cookie 中携带应用B返回的 MOD_AUTH_CAS_S(
Cookie: MOD_AUTH_CAS_S=XYZ1234567 GET https://b.com/
); - 应用B服务器验证浏览器请求Cookie中 MOD_AUTH_CAS_S 合法后返回实际资源。
代理模式
应用场景:用户访问应用A,应用A又要访问应用B的授权性资源,应用A想代表用户去访问应用B,因此应用A需要告诉应用B用户是谁,以便应用B对当前用户请求进行授权。
为解决以上问题,CAS引入代理模式。代理模式的前提是CAS Client拥有用户的身份信息凭据(Credentials)。
CAS基础模式中 TGT(Ticket Granting Ticket) 是用户(浏览器)持有的身份信息凭据,CAS代理模式中引入 PGT(Proxy Granting Ticket),是CAS Client持有的身份信息凭据。凭借 TGT 用户可以免登录访问其他服务,同理,凭借 PGT CAS Client可以免用户登录访问其他服务。
1. 用户在代理服务器上执行身份认证
- 用户访问应用A;
- 浏览器发送GET请求(
GET https://proxy.com/
)到应用A服务器; - 应用A服务器收到请求后,在请求 Cookie 中并未找到 session,将请求重定向到CAS服务器的登录接口(
302 Location http://cas.com/cas/login?service=https%3A%2F%2Fproxy.com%2F
),重定向URL中携带 service 请求参数,值为 编码后的用户访问的应用A地址(https://proxy.com/
); - 浏览器收到来自应用A服务器的重定向响应后,发送请求到CAS服务器的登录接口(
GET http://cas.com/cas/login?service=https%3A%2F%2Fproxy.com%2F
); - CAS服务器接收到请求后,在请求 Cookie 中并未找到带有 CASTGC,说明发起请求的客户端身份尚未认证,返回统一登录表单页;
- 用户在CAS返回的统一登录表单页上填写用于身份认证的凭证(通常是用户名/密码),然后向CAS服务器发起身份认证请求(
POST https://cas.com/cas/login?service=https%3A%2F%2Fproxy.com%2F
); - CAS认证身份成功,生成一个TGT(Ticket Granting Ticket)并写入响应的Cookie(
Set-Cookie: CASTGC=TGT-2345678
),同时根据URL中的 service 请求参数(service=https%3A%2F%2Fproxy.com%2F
)为应用A生成一个ST(Service Ticket),将请求重定向到用户访问的应用A地址,并添加请求参数 ticket(Set-Cookie: CASTGC=TGT-2345678 302 Location: https://proxy.com/?ticket=ST-12345678
); - 浏览器收到来自CAS服务器的重定向响应后,发送请求到应用A服务器(
GET https://proxy.com?ticket=ST-12345678
); - 应用A服务器收到浏览器请求后,取出 ticket 请求参数,向CAS服务器发起认证 ticket 合法性的请求(
GET https://cas.com/serviceValidate?service=https%3A%2F%2Fproxy.com%2F&ticket=ST-12345678&pgtUrl=https%3A%2F%2Fproxy.com%2FpgtCallbackURL
),注意请求参数pgtUrl; - CAS服务器收到请求后发现请求参数 pgtUrl,生成 pgtId 和 pgtIou 后调用 pgtUrl 指向的回调地址(
GET https://proxy.com/pgtCallbackURL?pgtId=TGT-23456789&pgtIou=PGTIOU-12345678
); - 应用A服务器存储 PGTIOU 和 PGT 之间的映射关系;
- 应用A服务器生成一个 session 写入响应的 Cookie(图中的 JSESSIONID 是Tomcat生成的),并返回浏览器一个重定向地址,此地址指向用户最初发起访问请求的地址(
Cookie: JSESSIONID=ABC1234567 302 Location: https://proxy.com/
); - 浏览器接收到重定向响应后再次向应用A发起访问请求,请求的 Cookie 中携带应用A返回的 JSESSIONID(
Cookie: JSESSIONID=ABC1234567 GET https://proxy.com/
); - 应用A服务器验证浏览器请求Cookie中 JSESSIONID 合法后返回实际资源。
2. 通过代理应用访问其他应用上授权性资源
- 用户通过应用A访问应用B上资源;
- 浏览器发送GET请求(
GET https://app.com/resource
)到应用A服务器,因此上一步中应用A已向 Cookie 中写入 session,所以此请求的 Cookie 中也带有此 session(Cookie: JSESSIONID=ABC1234567
); - 应用A服务器收到请求后,发现需要获取应用B上资源,因此向CAS服务器发起一个代理请求,要求为应用B生成一个ST(Service Ticket),请求URL:
GET https://cas.com/proxy?pgt=TGT-23456789&targetService=https:%3A%2F%2Fapp.com%2F
,URL中 pgt 参数值为上一步中生成 pgtId; - CAS服务器收到请求后生成一个ST(
ST-2345678
)返回; - 应用A收到CAS服务器返回的ST后,向应用B发起一个GET请求(
GET https://app.com/?ticket=ST-2345678
); - 应用B服务器收到浏览器请求后,取出 ticket 请求参数,向CAS服务器发起认证 ticket 合法性的请求(
GET https://cas.com/serviceValidate?service=https%3A%2F%2Fapp.com%2F&ticket=ST-2345678
); - CAS服务器验证 ticket 合法后返回
200 [XML Content]
,其中包含验证成功结果、认证对象及一些可选属性; - 应用B服务器得到 ticket 合法的认证结果后,生成一个 session 写入响应的 Cookie,并返回一个重定向地址给应用A(
Set-Cookie: MOD_AUTH_CAS_S=XYZ1234567 302 Location: https://app.com/
); - 应用A服务器接收到重定向响应后再次向应用B发起访问请求,请求的 Cookie 中携带应用B返回的 MOD_AUTH_CAS_S(
Cookie: MOD_AUTH_CAS_S=XYZ1234567 GET https://app.com/
); - 应用B服务器验证请求Cookie中 MOD_AUTH_CAS_S 合法后,将被访问资源返回给应用A服务器;
- 应用A服务器收到应用B服务器的响应后,对响应进行处理后返回给浏览器。