Cas 4.2.7 OAuth+Rest 实现SSO

栏目: 编程工具 · 发布时间: 6年前

内容简介:一: 遇到的问题使用Rest接口实现登陆后,再访问其他使用Cas单点登陆的系统时,Cas认定为当前用户未登陆并要求登陆。经过分析发现,当访问其他使用Cas单点登录系统时Cas无法获取到当前客户端Cookie中的TGC,也就是说使用Rest接口实现登陆Cas无法往客户端Cookie写入TGC。有关TGC的解析这里不详述。问题适用场景

一: 遇到的问题

使用Rest接口实现登陆后,再访问其他使用Cas单点登陆的系统时,Cas认定为当前用户未登陆并要求登陆。经过分析发现,当访问其他使用Cas单点登录系统时Cas无法获取到当前客户端Cookie中的TGC,也就是说使用Rest接口实现登陆Cas无法往客户端Cookie写入TGC。有关TGC的解析这里不详述。

问题适用场景

  1. 部分系统使用授权免登的方式进入到CAS单点登录系统,同时又希望能使用SSO切换到其他系统。
  2. 部分业务系统有自己的登陆页面,在自己的登陆逻辑中调用Cas的Rest接口实现登陆,同时希望能使用SSO切换到其他系统

二: 解决问题过程

  1. 分析Rest接口发现,调用 cas/v1/tickets/ 接口登陆成功后cas返回了用户的身份信息TGT,那么TGT和TGC有什么关联呢?

Cas 4.2.7 OAuth+Rest 实现SSO 收发

2. 继续分析cas登陆流程,Cas使用spring-webflow控制登陆流程,找到WEB-INF/webflow/login/login-webflow.xml。在flow执行之前Cas先做了些处理,如下配置

<on-start>
      <evaluate expression="initialFlowSetupAction"/>
</on-start>

追踪到InitialFlowSetupAction类的doExecute方法发现核心代码:

WebUtils.putTicketGrantingTicketInScopes(context,this.ticketGrantingTicketCookieGenerator.retrieveCookieValue(request));

代码说明:当用户访问Cas登陆页时,程序调用this.ticketGrantingTicketCookieGenerator.retrieveCookieValue(request)方法获取TGT并存放入当前作用域中。

继续追踪到CookieRetrievingCookieGenerator类的retrieveCookieValue方法中:

     try {
            final Cookie cookie = org.springframework.web.util.WebUtils.getCookie(
                    request, getCookieName());
            return cookie == null ? null : this.casCookieValueManager.obtainCookieValue(cookie, request);
        } catch (final Exception e) {
            logger.debug(e.getMessage(), e);
        }
        return null;

代码说明:逻辑比较简单,直接从cookie中获取TGC(getCookieName()方法有兴趣可以追踪下看看),如果TGC不为空,调用this.casCookieValueManager.obtainCookieValue(cookie, request)方法解析TGC得到TGT,问题逐渐明朗了,TGT是根据TGC获取到的。

再追踪到DefaultCasCookieValueManager(为什么选择DefaultCasCookieValueManager实现类,有兴趣可以追踪看看)类的obtainCookieValue方法中:

        final String cookieValue = this.cipherExecutor.decode(cookie.getValue());
        LOGGER.debug("Decoded cookie value is [{}]", cookieValue);
        if (StringUtils.isBlank(cookieValue)) {
            LOGGER.debug("Retrieved decoded cookie value is blank. Failed to decode cookie [{}]", cookie.getName());
            return null;
        }
 
        final String[] cookieParts = cookieValue.split(String.valueOf(COOKIE_FIELD_SEPARATOR));
        if (cookieParts.length != COOKIE_FIELDS_LENGTH) {
            throw new IllegalStateException("Invalid cookie. Required fields are missing");
        }
        final String value = cookieParts[0];
        final String remoteAddr = cookieParts[1];
        final String userAgent = cookieParts[2];
 
        if (StringUtils.isBlank(value) || StringUtils.isBlank(remoteAddr)
                || StringUtils.isBlank(userAgent)) {
            throw new IllegalStateException("Invalid cookie. Required fields are empty");
        }
 
        if (!remoteAddr.equals(request.getRemoteAddr())) {
            throw new IllegalStateException("Invalid cookie. Required remote address does not match "
                    + request.getRemoteAddr());
        }
 
        if (!userAgent.equals(request.getHeader("user-agent"))) {
            throw new IllegalStateException("Invalid cookie. Required user-agent does not match "
                    + request.getHeader("user-agent"));
        }
        return value;

代码说明:首先解密TGC后得到一个由@符号分隔的字符串,分隔后获取到TGT、客户端IP、客户端代理信息。并将从TGC中解密的客户端IP信息和客户端代理信息与当前请求的客户端IP信息和客户端代理信息进行比较,若不相等就抛出异常(Cas的安全策略)。

  1. 回到问题的根源,当业务系统调用Cas的Rest接口实现登陆,再切换到其他单点登录系统时,先请求Cas的登陆授权页面,当程序调用this.ticketGrantingTicketCookieGenerator.retrieveCookieValue(request)获取TGT时,此时客户端的TGC为空自然无法解析出TGT。
  1. 思考:既然调用Rest接口实现登陆有返回TGT信息,是否可以再请求一遍Cas的登陆授权页面并传入TGT信息,然后修改源码将TGT加密为TGC并加入到客户端的cookie中,此时Cas认定为当前用户为已登陆并重定向回service地址。
  1. Cas的登陆授权页面需要改造获取传入的TGT信息,还是需要到InitialFlowSetupAction类的doExecute方法进行处理

改造前:

        WebUtils.putTicketGrantingTicketInScopes(context, this.ticketGrantingTicketCookieGenerator.retrieveCookieValue(request));

改造后:

     String cookie = this.ticketGrantingTicketCookieGenerator.retrieveCookieValue(request);
        //增加从request中获取tgt
        if (cookie == null && request.getRequestURI().contains("/login")) {
            String tgt = request.getParameter("tgt");
            if (StringUtils.isNotBlank(tgt)) {
              HttpServletResponse response = WebUtils.getHttpServletResponse(context);
              //TGT生成为TGC并添加客户端cookie中
              this.ticketGrantingTicketCookieGenerator.addCookie(request, response, tgt);
              //tgt直接付值给cookie
              cookie = tgt;
            }
        }
        WebUtils.putTicketGrantingTicketInScopes(context,cookie);

将login-flow.xml中on-start配置修改为自定义的initialFlowSetupExAction

      <on-start>
              <evaluate expression="initialFlowSetupExAction"/>
      </on-start>

关于 this.ticketGrantingTicketCookieGenerator.addCookie(request, response, tgt);方法有兴趣的朋友可以追踪看看。

客户端改造:调用Cas的Rest接口登陆成功后,解析出返回的TGT,并重定向到Cas的登陆页面加上service和tgt参数即可

例:

https://cas.xxxx.com/cas/login?service=https://xxx.xxxx.com&tgt=TGT-817-6QBDc0n7Impr0EguA3mFpaViSeTOEzsMbefbW629nZRihFznoH-cas01.example.org

望大家不吝指教,有任何错误、疑问多交流。

版权声明:本文为博主原创文章,转载需注明出处。http://www.cnblogs.com/bryanx/p/8588270.html


以上所述就是小编给大家介绍的《Cas 4.2.7 OAuth+Rest 实现SSO》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

算法交易:制胜策略与原理

算法交易:制胜策略与原理

[美]欧内斯特·陈(Ernest P. Chan) / 高闻酉、黄蕊 / 机械工业出版社 / 49.00

本书是一本引人入胜、信息量大、覆盖各类交易策略的图书。无论个人投资者,还是机构投资者,都可以借鉴和使用其中的策略。本书中的策略大致可分为均值回归系统和动量系统两大类。书中不仅介绍了如何使用每种类别的交易策略,更解释了各种策略之所以有效的原因。本书始终以简单、线性的交易策略为重心,因为复杂的交易策略容易受到过度拟合及数据窥探的侵害。数学和软件是算法交易的两条腿。本书用到了一定程度的数学知识,使其对各......一起来看看 《算法交易:制胜策略与原理》 这本书的介绍吧!

Base64 编码/解码
Base64 编码/解码

Base64 编码/解码

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具