21. Java Authentication and Authorization Service

Posted on

21. Java Authentication and Authorization Service (JAAS) Provider

  1. Java Authentication and Authorization Service (JAAS) ProviderPrev Part V. Additional Topics Next

Java Authentication and Authorization Service (JAAS) Provider

21.1 Overview

Spring Security provides a package able to delegate authentication requests to the Java Authentication and Authorization Service (JAAS). This package is discussed in detail below.

21.2 AbstractJaasAuthenticationProvider

The

AbstractJaasAuthenticationProvider is the basis for the provided JAAS

AuthenticationProvider implementations. Subclasses must implement a method that creates the

LoginContext . The

AbstractJaasAuthenticationProvider has a number of dependencies that can be injected into it that are discussed below.

21.2.1 JAAS CallbackHandler

Most JAAS

LoginModule s require a callback of some sort. These callbacks are usually used to obtain the username and password from the user.

In a Spring Security deployment, Spring Security is responsible for this user interaction (via the authentication mechanism). Thus, by the time the authentication request is delegated through to JAAS, Spring Security's authentication mechanism will already have fully-populated an

Authentication object containing all the information required by the JAAS

LoginModule .

Therefore, the JAAS package for Spring Security provides two default callback handlers,

JaasNameCallbackHandler and

JaasPasswordCallbackHandler . Each of these callback handlers implement

JaasAuthenticationCallbackHandler . In most cases these callback handlers can simply be used without understanding the internal mechanics.

For those needing full control over the callback behavior, internally

AbstractJaasAuthenticationProvider wraps these

JaasAuthenticationCallbackHandler s with an

InternalCallbackHandler . The

InternalCallbackHandler is the class that actually implements JAAS’ normal

CallbackHandler interface. Any time that the JAAS

LoginModule is used, it is passed a list of application context configured

InternalCallbackHandler s. If the

LoginModule requests a callback against the

InternalCallbackHandler s, the callback is in-turn passed to the

JaasAuthenticationCallbackHandler s being wrapped.

21.2.2 JAAS AuthorityGranter

JAAS works with principals. Even "roles" are represented as principals in JAAS. Spring Security, on the other hand, works with

Authentication objects. Each

Authentication object contains a single principal, and multiple

GrantedAuthority s. To facilitate mapping between these different concepts, Spring Security's JAAS package includes an

AuthorityGranter interface.

An

AuthorityGranter is responsible for inspecting a JAAS principal and returning a set of

String s, representing the authorities assigned to the principal. For each returned authority string, the

AbstractJaasAuthenticationProvider creates a

JaasGrantedAuthority (which implements Spring Security’s

GrantedAuthority interface) containing the authority string and the JAAS principal that the

AuthorityGranter was passed. The

AbstractJaasAuthenticationProvider obtains the JAAS principals by firstly successfully authenticating the user’s credentials using the JAAS

LoginModule , and then accessing the

LoginContext it returns. A call to

LoginContext.getSubject().getPrincipals() is made, with each resulting principal passed to each

AuthorityGranter defined against the

AbstractJaasAuthenticationProvider.setAuthorityGranters(List) property.

Spring Security does not include any production

AuthorityGranter s given that every JAAS principal has an implementation-specific meaning. However, there is a

TestAuthorityGranter in the unit tests that demonstrates a simple

AuthorityGranter implementation.

21.3 DefaultJaasAuthenticationProvider

The

DefaultJaasAuthenticationProvider allows a JAAS

Configuration object to be injected into it as a dependency. It then creates a

LoginContext using the injected JAAS

Configuration . This means that

DefaultJaasAuthenticationProvider is not bound any particular implementation of

Configuration as

JaasAuthenticationProvider is.

21.3.1 InMemoryConfiguration

In order to make it easy to inject a

Configuration into

DefaultJaasAuthenticationProvider , a default in memory implementation named

InMemoryConfiguration is provided. The implementation constructor accepts a

Map where each key represents a login configuration name and the value represents an

Array of

AppConfigurationEntry s.

InMemoryConfiguration also supports a default

Array of

AppConfigurationEntry objects that will be used if no mapping is found within the provided

Map . For details, refer to the class level javadoc of

InMemoryConfiguration .

21.3.2 DefaultJaasAuthenticationProvider Example Configuration

While the Spring configuration for

InMemoryConfiguration can be more verbose than the standarad JAAS configuration files, using it in conjuction with

DefaultJaasAuthenticationProvider is more flexible than

JaasAuthenticationProvider since it not dependant on the default

Configuration implementation.

An example configuration of

DefaultJaasAuthenticationProvider using

InMemoryConfiguration is provided below. Note that custom implementations of

Configuration can easily be injected into

DefaultJaasAuthenticationProvider as well.

## 21.4 JaasAuthenticationProvider The JaasAuthenticationProvider assumes the default Configuration is an instance of ConfigFile. This assumption is made in order to attempt to update the Configuration . The JaasAuthenticationProvider then uses the default Configuration to create the LoginContext . Let’s assume we have a JAAS login configuration file, /WEB-INF/login.conf , with the following contents: JAASTest { sample.SampleLoginModule required; }; Like all Spring Security beans, the JaasAuthenticationProvider is configured via the application context. The following definitions would correspond to the above JAAS login configuration file:

21.5 Running as a Subject

If configured, the

JaasApiIntegrationFilter will attempt to run as the

Subject on the

JaasAuthenticationToken . This means that the

Subject can be accessed using:

Subject subject = Subject.getSubject(AccessController.getContext());

This integration can easily be configured using the jaas-api-provision attribute. This feature is useful when integrating with legacy or external API's that rely on the JAAS Subject being populated. Prev Up Next20. JSP Tag Libraries Home 22. CAS Authentication

allSpringSourceGrailsHypericGemstoneRabbitMQ

部署CAS单点登录服务器

Posted on

部署CAS单点登录服务器 - 萧飒的日志 - 网易博客

网易

新闻微博邮箱相册阅读有道摄影爱拍云笔记闪电邮手机邮印像派游戏江湖 更多

博客

手机博客博客搬家博客VIP服务 LiveWriter写博word写博邮件写博短信写博 群博客博客油菜地博客话题博客热点博客圈子找朋友 发现

小组 风格

网易真人搭配社区iStyle

网易轻博客LOFTER

创建博客 登录

加关注

显示下一条 | 关闭

萧飒的博客

未来的成功往往是现在无法想象的……

导航

日志

cas改造随笔

jsessionid的困扰

部署CAS单点登录服务器

2012-05-03 15:16:28| 分类: 编程 | 标签: |字号大中小 订阅

第0步:环境配置

操作系统:CentOS 5.5 64位

JDK:1.7

Tomcat:7.0

CAS Server:3.4.11

CAS Client:3.2.1

第1步:安装JAVA并设置环境变量

http://www.oracle.com/technetwork/java/javase/downloads/jdk-7u3-download-1501626.html

下载并安装Linux x64 RPM包 rpm -i jdk-7u3-linux-x64.rpm

设置环境变量

vi /etc/profile

加入

JAVA_HOME=/usr/java/jdk1.7.0_03 export JAVA_HOME

方便操作将keytool加入/usr/bin/

ln -s /usr/java/jdk1.7.0_03/bin/keytool /usr/bin/keytool

第2步:安装Tomcat

http://tomcat.apache.org/download-70.cgi

下载Tomcat并解压

tar -zxvf apache-tomcat-7.0.26.tar.gz

方便操作将启动关闭加入/usr/bin/ ln -s /usr/local/tomcat/bin/startup.sh /usr/bin/tomcat-start ln -s /usr/local/tomcat/bin/shutdown.sh /usr/bin/tomcat-stop

第3步:创建、导出、导入证书

创建一个生成证书的脚本 vi create_https_cert.sh /# 删除原证书库 keytool -delete -keystore /home/cas/cascerts -storepass changeit /# 删除原别名 keytool -delete -alias sgstsso -storepass changeit /# 生成证书,需要注意的是dname需要使用域名或主机名,不能用IP,keystore 为生成的证书库地址,后面TOMCAT会用到 keytool -genkey -keyalg RSA -alias sgstsso -keystore /home/cas/cascerts -dname "CN=cas.sgst.cn" -storepass changeit /# 导出证书,导出的证书用在各客户端的JDK导入 keytool -export -alias sgstsso -keystore /home/cas/cascerts -file /home/cas/sgstsso.crt -storepass changeit /# 导入证书 keytool -import -alias sgstsso -file /home/cas/sgstsso.crt -keystore $JAVA_HOME/jre/lib/security/cacerts -storepass changeit

执行该脚本。

第4步:应用证书到Tomcat

编辑conf/server.xml加入下面这段(如果8443 https已开启使用的则在其基础上修改)

重启Tomcat,访问https://localhost:8443,如果能否访问则配置成功。

第5步:配置CAS服务器

http://www.jasig.org/cas/download下载CAS Server 3.4.11 Release压缩包

解压后将其中的cas-server-3.4.11.war改名为cas.war放在tomcat下面

此时打开https://localhost:8443/cas/login即可访问

输入sgst/sgst登录成功(默认为简单认证,即用户名密码一样就算通过)

编辑tomcat/conf/server.xml在原Host下面增加以下这段

这样实现以https://cas.sgst.cn:8443 访问cas

CAS的认证改为查询数据库用户名密码验证:

编辑cas/WEB-INF/deployerConfigContext.xml

注释掉,新增下面这段

上面的加密根据个人需求可自行开发,这里用的是MD5 64位加密,以一个独立bean跟在后面

casDataSource则同样以一个独立bean跟在后面 oracle.jdbc.driver.OracleDriver jdbc:oracle:thin:@(DESCRIPTION =(ADDRESS = (PROTOCOL = TCP)(HOST = 10.10.29.104)(PORT = 1521))(ADDRESS = (PROTOCOL = TCP)(HOST = 10.10.29.105)(PORT = 1521))(ADDRESS = (PROTOCOL = TCP)(HOST = 10.10.29.106)(PORT = 1521))(LOAD_BALANCE = yes)(CONNECT_DATA = (SERVER = DEDICATED) (SERVICE_NAME = genome))) trs_ids 123456

保存该文件,复制压缩包中的modules里的cas-server-support-jdbc-3.4.11.jar和ojdbc14.jar到cas/WEB-INF/lib下

重启Tomcat后CAS便以用户名密码进行验证。

第6步:配置CAS客户端

http://www.jasig.org/cas/client-integration参考适合的客户端,JAVA的在这里下载http://downloads.jasig.org/cas-clients/

客户端中相应的JAR包都有,对应的maven为 org.jasig.cas.client cas-client-core 3.2.1

修改web.xml增加以下filter

org.jasig.cas.client.session.SingleSignOutHttpSessionListener CAS Single Sign Out Filter org.jasig.cas.client.session.SingleSignOutFilter CAS Single Sign Out Filter /check// CASFilter org.jasig.cas.client.authentication.AuthenticationFilter casServerLoginUrl https://cas.sgst.cn:8443/login serverName http://localhost:8080 CASFilter /check// CAS Validation Filter org.jasig.cas.client.validation.Cas20ProxyReceivingTicketValidationFilter casServerUrlPrefix https://cas.sgst.cn:8443 serverName http://localhost:8080 CAS Validation Filter /check// CAS HttpServletRequest Wrapper Filter org.jasig.cas.client.util.HttpServletRequestWrapperFilter CAS HttpServletRequest Wrapper Filter /check// CAS Assertion Thread Local Filter org.jasig.cas.client.util.AssertionThreadLocalFilter CAS Assertion Thread Local Filter /check//*

2012-03-21更新: CAS filter-mapping一定要放在整个项目的encodingFilter之后,否则会造成中文乱码

第7步:美化服务器界面

具体页面在cas\WEB-INF\view\jsp\default\ui\

登录界面:casLoginView.jsp 登录成功:casGenericSuccess.jsp 登出界面:casLogoutView.jsp 评论这张

转发至微博 转发至微博

0人 | 分享到:

阅读(7)| 评论(0)| 转载 (0) |举报

cas改造随笔

jsessionid的困扰

历史上的今天

相关文章

最近读者

评论

this.p={ m:2, b:2, id:'fks_087066086087081064092094095065072084088074084084085069087', blogTitle:'部署CAS单点登录服务器', blogAbstract:'

第0步:环境配置

操作系统:CentOS 5.5 64位

JDK:1.7

Tomcat:7.0

CAS Server:3.4.11

CAS Client:3.2.1', blogTag:'编程', blogUrl:'blog/static/2990236320124331628240', isPublished:1, istop:false, type:0, modifyTime:0, publishTime:1336029388240, permalink:'blog/static/2990236320124331628240', commentCount:0, mainCommentCount:0, recommendCount:0, bsrk:-100, publisherId:0, recomBlogHome:false, attachmentsFileIds:[], vote:{}, groupInfo:{}, friendstatus:'none', followstatus:'unFollow', pubSucc:'', visitorProvince:'北京', visitorCity:'西城区', postAddInfo:{}, mset:'000', mcon:'', srk:-100, remindgoodnightblog:false, isBlackVisitor:false, isShowYodaoAd:true, hostIntro:'我,犯溅一样的猪一样的懒,无语……', hmcon:'1', selfRecomBlogCount:'0', lofter_single:'' } {list a as x} {if !!x}

{if x.visitorName==visitor.userName} ${x.visitorNickname|escape} {else} ${x.visitorNickname|escape} {/if}
{if x.moveFrom=='wap'} {elseif x.moveFrom=='iphone'} {elseif x.moveFrom=='android'} {elseif x.moveFrom=='mobile'} {/if} ${fn(x.visitorNickname,8)|escape}
{/if} {/list} {if !!a} ${fn(a.nickname,8)|escape}
${a.selfIntro|escape}{if great260}${suplement}{/if}
{/if} </#--最新日志,群博日志--> {list a as x} {if !!x}
  • ${fn(x.title,26)|escape}
  • {/if} {/list} </#--推荐日志-->

    推荐过这篇日志的人:

    {list a as x} {if !!x} {/if} {/list}
    {if !!b&&b.length>0}

    他们还推荐了:

    {/if} </#--引用记录--> 转载记录: </#--博主推荐--> {list a as x} {if !!x}
  • ${x.title|default:""|escape}
  • {/if} {/list} </#--随机阅读--> {list a as x} {if !!x}
  • ${x.title|default:""|escape}
  • {/if} {/list} </#--首页推荐--> {list a as x} {if !!x}
  • ${x.blogTile|default:""|escape}
  • {/if} {/list} </#--相关文章-->
      {list a as x} {if x_index>9}{break}{/if} {if !!x}
    • ${x.title|default:""|escape}${fn2(parseInt(x.date),'yyyy-MM-dd HH:mm:ss')}
    • {/if} {/list}
    </#--历史上的今天-->
      {list a as x} {if x_index>4}{break}{/if} {if !!x}
    • ${fn1(x.title,60)|escape}${fn2(x.publishTime,'yyyy-MM-dd HH:mm:ss')}
    • {/if} {/list}
    </#--被推荐日志--> {list a as x} {if !!x}
  • ${fn(x.title,26)|escape}
  • {/if} {/list} </#--右边模块结构-->

    被推荐日志

      最新日志

        该作者的其他文章

          博主推荐

            相关日志

              随机阅读

                首页推荐



                  </#--评论模块结构-->
                  </#--引用模块结构-->
                  </#--博主发起的投票--> {list a as x} {if !!x}
                • ${x.nickName|escape} 投票给 {var first_option = true;} {list x.voteDetailList as voteToOption} {if voteToOption==1} {if first_option==false},{/if} “${b[voteToOption_index]}” {/if} {/list} {if (x.role!="-1") },“我是${c[x.role]}” {/if} ${fn1(x.voteTime)} {if x.userName==''}{/if} {/if} {/list}

                  页脚

                  公司简介 - 联系方法 - 招聘信息 - 客户服务 - 隐私政策 - 博客风格 - 手机博客 - VIP博客 - 订阅此博客

                  网易公司版权所有 ©1997-2012

                  帮助 ${u} {list wl as x}

                  ${x.g}
                  {list x.l as y} ${y.n} {/list} {/list} {if defined('wl')} {list wl as x}${x.n}{/list} {/if}

                • 新浪微博如何实现 SSO 的分析

                  Posted on

                  新浪微博如何实现 SSO 的分析 - 企业应用 - Java - ITeye论坛

                  您还未登录 ! 登录 注册

                  ITeye-最棒的软件开发交流社区

                  论坛首页Java企业应用论坛

                  新浪微博如何实现 SSO 的分析

                  全部 Hibernate Spring Struts iBATIS 企业应用 Lucene SOA Java综合 设计模式 Tomcat OO JBoss « 上一页 1 2 3 下一页 »

                  浏览 14772 次 锁定老帖子 主题:新浪微博如何实现 SSO 的分析

                  该帖已经被评为精华帖 作者 正文 * denger

                  • 等级: 四星会员
                  • denger的博客
                  • 性别:
                  • 文章: 176
                  • 积分: 400
                  • 来自: 北京
                  • 发表时间:2011-05-10 最后修改:2011-06-25

                  < > 猎头职位: 上海: 【上海】外资企业高新诚聘web开发工程师

                  相关文章:

                  • CAS 之 跨域 Ajax 登录实践
                  • 跨域的单点登录
                  • 【原创】CAS调研总结 推荐群组: liferay 更多相关推荐 企业应用 最近在使用sina微博时,经常性交替使用 weibo.com 和 t.sina.cm.cn进入我的微博。发现当我在 t.sina.com.cn中登录之后,直接切换至weibo.com,这时候在 weibo.com是已经登录的,当我在 weibo.com进行注销之后,再切换至 t.sina.com.cn,这时候在 t.sina.com.cn也已经是注销的状态了。 对于SSO的实现方案及其机制,早已经不是什么新鲜的技术了,从微软为.net提供的passport机制到java中开源的JBoss SSO、Oracle OpenSSO及经典的 Yale CAS等等之类的开源或一些商业SSO中间件都不失为作为单点登录实现的选择。当然一些企业也会选择自己实现一套适合自己轻量级方案,如采用SESSIONID转递或SESSION同步复制之类的。 可以看得出SSO的价值也是具大的,就拿sina来说吧,增加 weibo.com域名之后,对于用户来说来说没有任何影响,即使你在 t.sina.com.cn中进行登录,可以无缝在两域名之间随意切换,对于它推广weibo.com无非是大大的益处。 由于近年来一直在使用 Yale的CAS作为SSO的方案,觉得 SINA的SSO与Yale-CAS有很多异曲同工之妙,于是便对SINA的SSO进行分析,其中的细节处理还是很值的学习的。当然,由于分析看到的SINA SSO处理都只是一些表现或表面上的东西,再加上其大部分关键的sso js都已经被压缩,及SERVER端的实现机制也只是靠自己的经验及结合CAS的的一些原理进行猜测。其实本文应该叫 更比较贴切。

                    好吧,进入正题。

                  • Sina SSO之分析篇 首先是进入 t.sina.com.cn,提交用户名及密码进行登录,通过 Firebug可以看到它通过类似Aajx POST到了 http://login.sina.com.cn/sso/login.php?client=ssologin.js(v1.3.12),如下图所示: 不难看出,其 http://login.sina.com.cn/sso/login.php 就是类似是 CAS 中的 Server,对sina的所有应用系统提供的统一登录入口。上面的参数中有一个service参数,了解 CAS的GG应该知道 cas 在登录的时候除了username 和 password同样也有一个 service 参数,其CAS该参数含义是子应用系统的服务名标识及登录成功之后所跳转的地址。当然,sina这里使用了 "miniblog"作为微博的服务名,估计他在sso-server端对 miniblog 与登录成功之后的地址进行映射,如 miniblog=http://t.sina.com.cn/,这样就避免了CAS-client中转入service= decodeURIComponent('http://t.sina.com.cn')之类的做法了。 这里的登录与CAS做法一致,将登录验证提交至统一的认证中心进行验证处理,从而避免了跨子域和全域的问题。 验证成功之后路转的路径就是service所向的地址,验证失败之后则返回至当前登录页。下面就SSO中的一些登录方面的核心问题做一些分析,看看SINA和CAS分别是如何处理的:  1.如何授权某个子系统允许其在sso-server进行登录验证呢,类似cas-server中的login-ticket;

                      对于cas来说,在首次进入  /cas/login页时, [会产生一个一次性的login-ticket](http://denger.iteye.com/blog/809170),也就是说在提交登录验证前必须向服务器请求一个login-ticket,在登录提交时,需要将用户名及密码以及login-ticket进行提交至 cas-server端,cas-server端确定login-ticket有效后才会对用户名及密码进行认证。
                      看看sina如何处理的吧,继续看firebug:
                      ![]()       以上截图是当我首次进行 t.sina.com.cn时,通过 ajax/jsonp的方式发起的一个请求,可以看到返回的callback函数中的 json 串中包含了 nonce:"SXK19N"的属性,参数名的汉译是“一次”或“一次性”的意思,估计这里的 nonce就是login-ticket,为再一次确实,我再试着提交登录看看,看它是否将该参数POST过去:
                     ![]()
                     果然不出所料, nonce:"SXK19N"作为参数提交过去了,证明所猜测的应该是正确的。
                    

                    2.比如验证码跨域跨服务器导致从session无法获取的问题,我们曾经遇到过;

                      貌似sina登录没有涉及到验证码之类的东西,当你多次登录失败之后,它采用的是“您的登录过于频繁,请稍后再试吧”,这种方案确实比验证码要好的多,而且还避免了上面的说的问题。
                    

                    3. 当我登录失败了,/sso/login.php 如何将登录的错误信息返回给 t.sina.com.cn并让它进行显示呢,如果我登录成功了/sso/login.php 通过什么方式通知t.sina.com.cn呢,因为它这里使用的是ajax方式登录?

                     对于这方面,cas的处理是将错误信息以参数的方式返回给 client-login,如登录失败,重定向地址: http://cas-client.com?errocode=0,如果登录成功,则直接 重定向至 service 中的url,并生成ST给客户端,表示其已经在cas-server登录成功了。
                     看看sina如何处理的吧,随便输入一个用户名密码,提交登录,继续通过firebug看看它的处理过程:
                    

                      再看看t.sina.com.cn 中的html内容的变化:
                      ![]()
                    

                    以上图1中发生了两次请求,第一次登录验证是访问 sso认证中心,它所返回response是一个html内容,第二次请求的地址: http://t.sina.com.cn/ajaxlogin.php framelogin=1&callback=parent.sinaSSOController.feedBackUrlCallBack&retcode=4038&reason=%B5%C7%C2) 再结合以上图2信息,看到 html 中发生了变化,创建了一个 id=ssoLoginFrame 的iframe,于是便可以得出,sina 的登录并非原生的ajax方式,而是通过创建iframe来模拟提交不刷新的登录。也就是说,当用户点击登录提交时,这时候它会通过js创建iframe,将登录提效至该iframe中。

                       既然已经知道它登录是提交到iframe中,而非ajax方式,那么对于以上截图1中两个请求为什么返回的都是HTML内容就很容易解释了。再回到上面的问题,/sso/login是如何通知t.sina.com.cn登录失败了呢? 首先在以上第一个截图中返回的 HTML包含了一段 javascript:
                    

                  Javascript代码 收藏代码

                  1. location.replace("http://t.sina.com.cn/ajaxlogin.php?framelogin=1&callback=parent.sinaSSOController.feedBackUrlCallBack&retcode=4038&reason=%B5%C7%C2%BC%B3%A%BC%B3%A2%CA%D4%B4%CE%CA%FD%B9%FD%D3%DA%C6%B5%B7%B1%A3%AC%C7%EB%C9%D4%BA%F3%D4%D9%B5%C7%C2%BC");
                    location.replace("http://t.sina.com.cn/ajaxlogin.php?framelogin=1&callback=parent.sinaSSOController.feedBackUrlCallBack&retcode=4038&reason=%B5%C7%C2%BC%B3%A%BC%B3%A2%CA%D4%B4%CE%CA%FD%B9%FD%D3%DA%C6%B5%B7%B1%A3%AC%C7%EB%C9%D4%BA%F3%D4%D9%B5%C7%C2%BC");
                      location.replace的意思与location.href类似,同样都是改变当前的URL地址,具体区别及做法可以参考[这里](http://blog.csdn.net/fangxinggood/archive/2006/02/21/604916.aspx)及[这里](http://developer.apple.com/internet/webcontent/iframe.html)。需要注意的这里所说的通过location.replace改变当前的URL其它并非改变t.sina.com.cn的地址,而是第二个截图里iframe中src的地址,因为这段HTML是在iframe中输出的。
                    在  locaiton.replace 的地址中包含了一个 retcode 及 reason参数,估计这就是当前登录的错误信息。在上面第一个截图的第二个请求实际就是在iframe 中进行的 location.replace操作后的跳转地址。关键看它输出的html内容:
                    

                  Html代码 收藏代码

                  1. null
                    null 这段js是在 iframe中执行的,所以可以通过 parent 进行访问 t.sina.com.cn中的js,可以肯定 parent.sinaSSOController.feedBackUrlCallBack 就是告诉 t.sina.com.cn 当前已经登录失败了,并且将错误信息传至该入该callback了。至此,已经完成了 /sso/login.php 对 t.sina.com.cn的信息传送。 新浪果然是有一手呀,在CAS中AJAX登录一直都是一个问题,而sina它巧妙的通过iframe+callback 进行实现了。 接着,再看看它对于登录成功之后如何通知 t.sina.com.cn的吧,先看看登录成功之后 sina-sso-server 会做什么,看firebug截图: 重点在于 set-Cookie: tgc=TGT-MTc4NTc0NzM0Mw==-1305003116-ja-D51B2EB107B79FC50D8CA424BFE08907; 哈哈,熟悉CAS的应该会很熟悉这个,没想到SINA的TGT与CAS的TGT不但参数命名,居然连生成的规则也一模一样,估计sina肯定是参考了 cas 的实现机制。关于TGT是什么或其作用可以参考:CAS总结之Ticket篇。另外还有一个就是当登录成功之后,sina-sso-server会将用户登陆名等等放在sina.com.cn根域的cookie中。 然后再看看登录成功之后 sina-sso-server所返回的response内容: 以下是从以上摘取JS部分:

                  Javascript代码 收藏代码


                  1. 首先再次声明,以上firebug截图中的请求处理,并非 AJAX,而是在 t.sina.com.cn中放了一个iframe,输出的 reponse都会至iframe当中.
                    以上的js主要重点在于:

                  Javascript代码 收藏代码

                  1. location.replace('http://t.sina.com.cn/ajaxlogin.php?framelogin=1&callback=parent.sinaSSOController.feedBackUrlCallBack&retcode=0')
                    location.replace('http://t.sina.com.cn/ajaxlogin.php?framelogin=1&callback=parent.sinaSSOController.feedBackUrlCallBack&retcode=0') 还是通过设置当前iframe中src地址,再看看跳转至http://t.sina.com.cn/ajaxlogin.php后的response内容吧: 返回用户信息(从cookie中获取的),并且还是类似上面的做法,通过 parent.sinaSSOController.feedBackUrlCallBack回调t.sina.com.cn中的js,告诉它这个用户已经登录成功了。 于是t.sina.com.cn便进行跳转至 t.sina.com.cn/dengers 中,从而实现登录。 整体的处理流程如下: 4. 当我在t.sina.com.cn中登录后,切换至weibo.com,weibo.com我应该也是已经登录的,如何做到呢?
                    对于这个问题,CAS中的处理就是,当我进入 weibo.com的时候,马上跳转至  /cas/login,然后在login中判断cookie是否存在TGT,如果存在,并确定其有效性后,则认为你已经登录,并为你生成一个ST,将ST作为ticket参数使其重定向至 weibo.com?ticket=TG-xxxx 并登录。
                    
                    看看sina怎么处理的吧,首先我直接在t.sina.com.cn登录成功。然后再新建一个选项卡,输入 weibo.com: 可以看得出,当我进入 weibo.com之后,sina并没有直接进入 weibo.com的主页,而是马上重定向至: http://login.sina.com.cn/sso/login.php?url=http%3A%2F%2Fweibo.com%2F&_rand=1305008634.5127&gateway=1&service=miniblog&useticket=1&returntype=META  与cas的做法确实一致。 再看看该 login.php的Response 信息,主要是JS:

                  Js代码 收藏代码


                  1. 看到这里之后,不得不怀疑 SINA 的 SSO 是不是用的就是 CAS 啊!!不但连 TGT 参数名一样,连ST规则及参数名也一模一样,其处理机制也十分相似。 到这里之后就与 CAS 的处理一样了,就不详细写了,可以参考 CAS相关文章。 ────────── PS:由于在分析过程中里面的很多SSO关键JS都压缩了,所以难免会存在误差。 不过SINA的SSO很多细节方面确实处理的很好,作为互联网应用的话,如果单纯的只是把 CAS DOWNLOAD 下来,然后直接配配就用的话很多方面的处理还是很不到位的。 有时间我把我们CAS参考 SINA 调整一下。 到这里,不得不说的一个事情就是,之前在分析淘宝cookie如何跨域获取时,大家都说出了一个taobao的jsonp实际存在一定的安全隐患。后面那个淘宝的GG看到之后加入Refer的判断。而现在,在分析的过程中发现新浪也有这样的问题,可以尝试一下,随便在本地建立一个html,引入jquery,然后使用下面的JS,就可以获取到sina中的登录邮箱名等信息,前提是你需要先在sina中登录: Js代码 收藏代码

                  2. $.ajax({url: 'http://t.sina.com.cn/ajaxlogin.php?framelogin=0&callback=?&retcode=0', dataType:'jsonp',

                  3. success:function(data){
                  4. alert(data.userinfo.userid);
                  5. }});
                    $.ajax({url: 'http://t.sina.com.cn/ajaxlogin.php?framelogin=0&callback=?&retcode=0', dataType:'jsonp', success:function(data){ alert(data.userinfo.userid); }});
                  • 大小: 50.6 KB

                  • 大小: 26.4 KB

                  • 大小: 37.5 KB

                  • 大小: 40 KB

                  • 大小: 134.6 KB

                  • 大小: 56 KB

                  • 大小: 29 KB

                  • 大小: 35.9 KB

                  • 大小: 103.5 KB

                  • 大小: 110.8 KB

                  • 大小: 134.6 KB

                  • 大小: 85.2 KB

                  • 查看图片附件

                  声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。 推荐链接

                  好文章。分析的很详实。慢慢看。 返回顶楼 回帖地址

                  0 0 请登录后投票 * ln1058

                  • 等级: 初级会员
                  • ln1058的博客
                  • 性别:
                  • 文章: 43
                  • 积分: 40
                  • 来自: 北京
                  • 发表时间:2011-05-11

                  我怎么觉得没必要这么麻烦呢。 如果是我来做,直接通过cookie来判断用户是否为登录状态,然后在进行相关的URL跳转。 这种网站对于用户的安全性都不高,真有必要这么麻烦吗? 返回顶楼 回帖地址

                  0 0 请登录后投票 * denger

                  • 等级: 四星会员
                  • denger的博客
                  • 性别:
                  • 文章: 176
                  • 积分: 400
                  • 来自: 北京
                  • 发表时间:2011-05-11 最后修改:2011-05-11

                  ln1058 写道

                  我怎么觉得没必要这么麻烦呢。 如果是我来做,直接通过cookie来判断用户是否为登录状态,然后在进行相关的URL跳转。 实际上说起来确实是这样,CAS和SINA也是这样的,直接从cookie判断用户是否已经登录,如果已经登录进行相关 URL的跳转。但是,cookie只会存储在一个域名下(login.sina.com.cn) , sina很多方面都采用 AJAX/JSONP 或 iframe 的方式,因为基本上全部都是跨全域的"AJAX"方式登录的,所以很多地方处理起来并不是那么方便。 另外一个还要考虑的SSO的灵活和通用信,一个的系统或新的域名整合过来,增加或修改达到最少,这些在设计SSO中都是需要考虑、封装的,而sina这方面确实封装的还可以,整个SSO的处理逻辑也很清楚。他参考了CAS的设计方案或者说直接使用的就是CAS然后进行二次开发的。 引用

                  这种网站对于用户的安全性都不高,真有必要这么麻烦吗? 新浪有着上亿的微博用户噢.... 就你一句话说他安全性不高,他就不高了? 返回顶楼 回帖地址

                  0 0 请登录后投票 * fangin

                  • 等级: 初级会员
                  • fangin的博客
                  • 性别:
                  • 文章: 52
                  • 积分: 30
                  • 来自: 北京
                  • 发表时间:2011-05-11

                  ln1058 写道

                  我怎么觉得没必要这么麻烦呢。 如果是我来做,直接通过cookie来判断用户是否为登录状态,然后在进行相关的URL跳转。 这种网站对于用户的安全性都不高,真有必要这么麻烦吗? 你不能因为用户禁用cookie就登陆不上去啊 返回顶楼 回帖地址

                  0 0 请登录后投票 * denger

                  • 等级: 四星会员
                  • denger的博客
                  • 性别:
                  • 文章: 176
                  • 积分: 400
                  • 来自: 北京
                  • 发表时间:2011-05-11 最后修改:2011-05-11

                  fangin 写道

                  ln1058 写道

                  我怎么觉得没必要这么麻烦呢。 如果是我来做,直接通过cookie来判断用户是否为登录状态,然后在进行相关的URL跳转。 这种网站对于用户的安全性都不高,真有必要这么麻烦吗? 你不能因为用户禁用cookie就登陆不上去啊 你说的没错,不过遗憾的是 sina当你禁用了cookie你确实登录不上去。貌似连iteye也是这样。 返回顶楼 回帖地址

                  0 0 请登录后投票 * aweber

                  • 等级: 初级会员
                  • aweber的博客
                  • 性别:
                  • 文章: 3
                  • 积分: 30
                  • 来自: 福建
                  • 发表时间:2011-05-11

                  亮点是 iframe调用父窗口js函数的解决方法。居然在当前域名下整了一个跳转页面,在跳转页面里面调用父窗口地址。NB。 我之前都是 在子iframe里面再包含一个iframe,简称孙iframe,孙iframe和父窗口同域名,也就是跳转页面,在孙iframe里面调用父窗口的函数 返回顶楼 回帖地址

                  0 0 请登录后投票 * xiang37

                  • 等级: 初级会员
                  • xiang37的博客
                  • 性别:
                  • 文章: 22
                  • 积分: 40
                  • 来自: 南京
                  • 发表时间:2011-05-11

                  支持一个,最近在研究sso,现在想先做个cas的实例出来。 返回顶楼 回帖地址

                  0 0 请登录后投票 * tengfei3003

                  • 等级: 初级会员
                  • tengfei3003的博客
                  • 性别:
                  • 文章: 9
                  • 积分: 40
                  • 来自: 南京
                  • 发表时间:2011-05-11

                  分析透彻,好好研究研究 返回顶楼 回帖地址

                  0 0 请登录后投票 * jeho0815

                  • 等级: 初级会员
                  • jeho0815的博客
                  • 性别:
                  • 文章: 21
                  • 积分: 30
                  • 来自: 深圳
                  • 发表时间:2011-05-11

                  看的有点困难啊,实力太差了! 返回顶楼 回帖地址

                  0 0 请登录后投票

                  « 上一页 1 2 3 下一页 » 论坛首页Java企业应用版 跳转论坛:移动开发技术 Web前端技术 Java企业应用 编程语言技术 综合技术 入门技术 招聘求职 海阔天空

                  © 2003-2012 ITeye.com. [ 京ICP证110151号 京公网安备110105010620 ] 百联优力(北京)投资有限公司 版权所有

                  单点登录CAS Server 介绍

                  Posted on

                  单点登录CAS Server 介绍 - Java综合 - Java - ITeye论坛

                  您还未登录 ! 登录 注册

                  ITeye-最棒的软件开发交流社区

                  论坛首页Java企业应用论坛

                  单点登录CAS Server 介绍

                  全部 Hibernate Spring Struts iBATIS 企业应用 Lucene SOA Java综合 设计模式 Tomcat OO JBoss 浏览 3057 次 锁定老帖子 主题:单点登录CAS Server 介绍

                  精华帖 (0) :: 良好帖 (0) :: 新手帖 (2) :: 隐藏帖 (0) 作者 正文 * boli.jiang

                  • 等级: 初级会员
                  • boli.jiang的博客
                  • 性别:
                  • 文章: 3
                  • 积分: 40
                  • 来自: 成都
                  • 发表时间:2010-04-22 最后修改:2010-04-23

                  < > 猎头职位: 上海: 【上海】外资企业高新诚聘web开发工程师

                  相关文章:

                  下面的讲解基于CAS Server 3.3.5版本。

                  CAS Server 配置文件

                  login-webflow.xml:其中内容指定了当访问cas/login时的程序流程,初始“initialFlowSetup”

                  cas-servlet.xml:servlet与class对应关系

                  deployerConfigContext.xml:认证管理器相关

                  cas.properties:系统属性设置

                  applicationContext.xml:系统属性相关

                  argumentExtractorsConfiguration.xml:不是很了解它的用途

                  ticketExpirationPolicies.xml:ticket过期时间设置

                  ticketGrantingTicketCookieGenerator.xml:TGT cookie属性相关,是否支持http也在这儿修改

                  ticketRegistry.xml:保存ticket的类相关设置

                  uniqueIdGenerators.xml:ticket自动生成类设置

                  warnCookieGenerator.xml:同ticketGrantingTicketCookieGenerator.xml,生成的 cookie名为CASPRIVACY

                  /login

                  当访问/login时,会调用login-webflow.xml中的流程图:

                  /serviceValidate:

                  对应的处理类是org.jasig.cas.web.ServiceValidateController,主要负责对service ticket的验证,失败返回casServiceValidationFailure.jsp,成功返回casServiceValidationSuccess.jsp

                  对service ticket的验证是通过client端向server端发送http(或https)实现的

                  逻辑:

                  1.通过由client端传来的ticket到DefaultTicketRegistry中获取缓存的ServiceTicketImpl对象,并判断其是否已经过期(ST过期时间默认是5分钟,TGT默认是2个小时,可以在ticketExpirationPolicies.xml中进行修改)以及与当前service的id是否相一,以上都满足则表示验证通过。

                  2.通过ServiceTicketImpl对象获取到登录之后的Authentication对象,借助于它生成ImmutableAssertionImpl对象并返回

                  3.成功返回

                  CAS数据流程

                  Credentials-->Principal-->Authentication

                  定义自己的AuthenticationHandler

                  在中心认证进行认证的过程中会调用deployerConfigContext.xml中设置的AuthenticationHandler来进行认证工作。 Java代码 收藏代码

                  1. <!--
                  2. This is the authentication handler that authenticates services by means of callback via SSL, thereby validating
                  3. a server side SSL certificate.
                  4. -->
                  5. <bean class="org.jasig.cas.authentication.handler.support.HttpBasedServiceCredentialsAuthenticationHandler"
                  6. p:httpClient-ref="httpClient" />
                  7. <!--
                  8. This is the authentication handler declaration that every CAS deployer will need to change before deploying CAS
                  9. into production. The default SimpleTestUsernamePasswordAuthenticationHandler authenticates UsernamePasswordCredentials
                  10. where the username equals the password. You will need to replace this with an AuthenticationHandler that implements your
                  11. local authentication strategy. You might accomplish this by coding a new such handler and declaring
                  12. edu.someschool.its.cas.MySpecialHandler here, or you might use one of the handlers provided in the adaptors modules.
                  13. -->
                  14. <bean
                  15. class="org.jasig.cas.authentication.handler.support.SimpleTestUsernamePasswordAuthenticationHandler" />
                  16. </list
                  17. 如上,我们定义了3个AuthenticationHandler,这正是CAS的一个 ,通过配置,我们可以实现针对不同的应用提供不同的认证方式,这样可以实现任意的中心认证。再来看看AuthenticationHandler的代码

                  Java代码 收藏代码

                  1. ///
                  2. /* Method to determine if the credentials supplied are valid.
                  3. /*
                  4. /* @param credentials The credentials to validate.
                  5. /* @return true if valid, return false otherwise.
                  6. /* @throws AuthenticationException An AuthenticationException can contain
                  7. /* details about why a particular authentication request failed.
                  8. /*/
                  9. boolean authenticate(Credentials credentials)
                  10. throws AuthenticationException;
                  11. ///
                  12. /* Method to check if the handler knows how to handle the credentials
                  13. /* provided. It may be a simple check of the Credentials class or something
                  14. /* more complicated such as scanning the information contained in the
                  15. /* Credentials object.
                  16. /*
                  17. /* @param credentials The credentials to check.
                  18. /* @return true if the handler supports the Credentials, false othewrise.
                  19. /*/
                  20. boolean supports(Credentials credentials);
                    /// / Method to determine if the credentials supplied are valid. / / @param credentials The credentials to validate. / @return true if valid, return false otherwise. / @throws AuthenticationException An AuthenticationException can contain / details about why a particular authentication request failed. // boolean authenticate(Credentials credentials) throws AuthenticationException; /// / Method to check if the handler knows how to handle the credentials / provided. It may be a simple check of the Credentials class or something / more complicated such as scanning the information contained in the / Credentials object. / / @param credentials The credentials to check. / @return true if the handler supports the Credentials, false othewrise. /*/ boolean supports(Credentials credentials);

                    我们要做的就是实现这俩个方法而已,特别提醒:可以在cas-servlet.xml中设置你所使用的Credentials,如下:(其中的p:formObjectClass值,如果不指定默认使用UsernamePasswordCredentials)

                  Java代码 收藏代码

                  1. <bean id="authenticationViaFormAction" class="org.jasig.cas.web.flow.AuthenticationViaFormAction"
                  2. p:formObjectClass="com.goldarmor.live800.cas.Live800CasCredentials"
                  3. p:centralAuthenticationService-ref="centralAuthenticationService"
                  4. p:warnCookieGenerator-ref="warnCookieGenerator" />

                  定义自己的credentialsToPrincipalResolvers

                  通过AuthenticationHandler的认证后,会调用在deployerConfigContext.xml中配置的credentialsToPrincipalResolvers来处理Credentials,生成Principal对象: Java代码 收藏代码

                  1. <!--
                  2. UsernamePasswordCredentialsToPrincipalResolver supports the UsernamePasswordCredentials that we use for /login
                  3. by default and produces SimplePrincipal instances conveying the username from the credentials.
                  4. If you've changed your LoginFormAction to use credentials other than UsernamePasswordCredentials then you will also
                  5. need to change this bean declaration (or add additional declarations) to declare a CredentialsToPrincipalResolver that supports the
                  6. Credentials you are using.
                  7. --> <bean
                  8. class="org.jasig.cas.authentication.principal.UsernamePasswordCredentialsToPrincipalResolver" />
                  9. <!--
                  10. HttpBasedServiceCredentialsToPrincipalResolver supports HttpBasedCredentials. It supports the CAS 2.0 approach of
                  11. authenticating services by SSL callback, extracting the callback URL from the Credentials and representing it as a
                  12. SimpleService identified by that callback URL.
                  13. If you are representing services by something more or other than an HTTPS URL whereat they are able to
                  14. receive a proxy callback, you will need to change this bean declaration (or add additional declarations).
                  15. -->
                  16. <bean
                  17. class="org.jasig.cas.authentication.principal.HttpBasedServiceCredentialsToPrincipalResolver" />
                  18. 如上:我们也可以像定义AuthenticationHandler一样,可以定义多个credentialsToPrincipalResolvers来处理Credentials,返回你所需要的Principal对象,下面来看看credentialsToPrincipalResolvers的方法:

                  Java代码 收藏代码

                  1. ///
                  2. /* Turn Credentials into a Principal object by analyzing the information
                  3. /* provided in the Credentials and constructing a Principal object based on
                  4. /* that information or information derived from the Credentials object.
                  5. /*
                  6. /* @param credentials from which to resolve Principal
                  7. /* @return resolved Principal, or null if the principal could not be resolved.
                  8. /*/
                  9. Principal resolvePrincipal(Credentials credentials);
                  10. ///
                  11. /* Determine if a credentials type is supported by this resolver. This is
                  12. /* checked before calling resolve principal.
                  13. /*
                  14. /* @param credentials The credentials to check if we support.
                  15. /* @return true if we support these credentials, false otherwise.
                  16. /*/
                  17. boolean supports(Credentials credentials);
                    /// / Turn Credentials into a Principal object by analyzing the information / provided in the Credentials and constructing a Principal object based on / that information or information derived from the Credentials object. / / @param credentials from which to resolve Principal / @return resolved Principal, or null if the principal could not be resolved. // Principal resolvePrincipal(Credentials credentials); /// / Determine if a credentials type is supported by this resolver. This is / checked before calling resolve principal. / / @param credentials The credentials to check if we support. / @return true if we support these credentials, false otherwise. /*/ boolean supports(Credentials credentials);

                  在CAS验证的时候,通过访问/serviceValidate可知:验证成功之后返回的casServiceValidationSuccess.jsp中的数据来源于Assertion,下面来看看它的代码:

                  Java代码 收藏代码

                  1. List getChainedAuthentications();
                  2. ///
                  3. /* True if the validated ticket was granted in the same transaction as that
                  4. /* in which its grantor GrantingTicket was originally issued.
                  5. /*
                  6. /* @return true if validated ticket was granted simultaneous with its
                  7. /* grantor's issuance
                  8. /*/
                  9. boolean isFromNewLogin();
                  10. ///
                  11. /* Method to obtain the service for which we are asserting this ticket is
                  12. /* valid for.
                  13. /*
                  14. /* @return the service for which we are asserting this ticket is valid for.
                  15. /*/
                  16. Service getService();
                    List getChainedAuthentications(); /// / True if the validated ticket was granted in the same transaction as that / in which its grantor GrantingTicket was originally issued. / / @return true if validated ticket was granted simultaneous with its / grantor's issuance // boolean isFromNewLogin(); /// / Method to obtain the service for which we are asserting this ticket is / valid for. / / @return the service for which we are asserting this ticket is valid for. /*/ Service getService();

                    通过getChainedAuthentications()方法,我们可以得到Authentication对象列表,再看看Authentication的代码:

                  Java代码 收藏代码

                  1. ///
                  2. /* Method to obtain the Principal.
                  3. /*
                  4. /* @return a Principal implementation
                  5. /*/
                  6. Principal getPrincipal();
                  7. ///
                  8. /* Method to retrieve the timestamp of when this Authentication object was
                  9. /* created.
                  10. /*
                  11. /* @return the date/time the authentication occurred.
                  12. /*/
                  13. Date getAuthenticatedDate();
                  14. ///
                  15. /* Attributes of the authentication (not the Principal).
                  16. /* @return the map of attributes.
                  17. /*/
                  18. Map getAttributes();
                    /// / Method to obtain the Principal. / / @return a Principal implementation // Principal getPrincipal(); /// / Method to retrieve the timestamp of when this Authentication object was / created. / / @return the date/time the authentication occurred. // Date getAuthenticatedDate(); /// / Attributes of the authentication (not the Principal). / @return the map of attributes. // Map getAttributes();

                    而这其中的Principal就来源于上面提到的由credentialsToPrincipalResolvers处理得到的Principal对象,最后看一下Principal的代码,我们只要再做一个实现他的代码,整个CAS Server就可以信手拈来了,呵呵

                  Java代码 收藏代码

                  1. ///
                  2. /* Returns the unique id for the Principal
                  3. /* @return the unique id for the Principal.
                  4. /*/
                  5. String getId();
                  6. ///
                  7. /*
                  8. /* @return
                  9. /*/
                  10. Map getAttributes();
                    /// / Returns the unique id for the Principal / @return the unique id for the Principal. // String getId(); /// / / @return // Map getAttributes();

                  我们还可以自定义自己的casServiceValidationSuccess.jsp和casLoginView.jsp页面等,具体的操作办法也是最简单的办法就是备份以前的页面之后修改成自己需要的页面。

                  声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。 推荐链接

                  论坛首页Java企业应用版 跳转论坛:移动开发技术 Web前端技术 Java企业应用 编程语言技术 综合技术 入门技术 招聘求职 海阔天空

                  © 2003-2012 ITeye.com. [ 京ICP证110151号 京公网安备110105010620 ] 百联优力(北京)投资有限公司 版权所有