phpcas的几个遗留问题

在之前的博客《企业CAS单点登录的架构思路》介绍过了CAS单点登录的主要思路,在后续的实践过程中遇到了几个不大不小的问题,记录下来也许会帮助到大家。

无法获取attributes

CAS服务端可以配置将LDAP中的属性映射到CAS中的attributes属性,这样在客户端验证ST票据的时候除了可以得到username,还可以得到attributes,也就是LDAP中描述用户信息的一些属性。

当CAS服务端配置正确后,在客户端验证TS时可以读到如下的XML报文应答:

其中<cas:user>是默认会返回的CAS用户名,而<cas:attributes>只有在CAS配置过LDAP映射属性后才会出现,其中的属性从格式上来看就是LDAP风格。

想要获取attributes属性,要求客户端按照CAS 3.0协议与CAS服务端通讯,这是CAS服务端的要求。

对于PHP来说,需要在创建客户端时声明这一点:

我一开始使用了2.0协议,结果导致服务端始终不返回<cas:attributes>标签。

统一登出

背景

此前一直将关注点放在CAS统一登录的流程上,但是忽略了如何实现统一登出。

因为CAS一旦完成ST校验,应用就只会访问自己的登录会话了。

默认CAS登出流程是A应用重定向浏览器到CAS服务的/cas/logout注销单点会话,然后重定向回应用注销本地会话。然而假设B应用此前也有自己的本地会话,那么B应用仍旧处于登录状态,对于企业内的多个应用来说,这个感觉就比较奇怪。

所以希望实现统一登出,也就是一旦CAS服务端单点会话注销,那么所有应用的本地会话也被注销。

原理

CAS是支持这一点的,也就是在CAS服务端单点会话注销时,会通过HTTP调用通知所有的应用注销会话,相当于一个通知机制。

CAS服务端因为维护了所有曾经校验过的ST票据以及票据所属的应用地址,所以可以将每个票据都回调给应用,让应用注销ST对应的会话。

为了实现这一点,CAS客户端默认实现都是用ST票据作为本地登录会话的key,所以当CAS通知注销时应用只需要根据传来的ST删除对应会话即可,对应的注销通知报文如下:

其中<samlp:SessionIndex>就是对应的ST票据,也是应用本地会话的key。

需要CAS服务端为每个CAS应用,分别配置注销回调接口的地址。

一旦某个用户在CAS单点登出,那么该用户所有在此期间使用过的ST(每次登录一个应用会有一个ST),均会被回调给对应的应用,完成本地会话注销。

作为PHPCAS客户端来说,它已经提供了现成的函数来完成本地会话注销,我们只需要在回调接口里调用一下即可完成$_SESSION的注销:

其中check_client=true的话,则会根据调用请求来源IP进行DNS反解到HOSTNAME,判断HOSTNAME是否在白名单allowed_clients里。

这种安全考虑非常自然,否则恶意攻击者随便调用一下注销接口,我们就把会话删掉,这肯定是不行的,所以只能信任来自CAS服务端的请求。

但是从IP反解HOSTNAME对于很多企业是没有配置的,所以建议公司内系统放弃安全检测,也就是check_client=false。

我们可以在CAS服务端配置每个service的注销回调地址,当我们在CAS单点登出后,所有你登录过的应用会收到回调报文如下:

handleLogoutRequests函数会取出其中的<samlp:SessionIndex>,也就是当初登录时用的票据ST,它同时也是本地SESSION的key。

只要把key对应的SESSION删除即可,我这里配置的是redis session,相关代码如下供大家参考:

 

如果文章帮助您解决了工作难题,您可以帮我点击屏幕上的任意广告,或者赞助少量费用来支持我的持续创作,谢谢~