单点登录(二)| OAuth 授权框架及 CAS 在为 Web 应用系统提供的解决方案实践
作者:阿东
微信公众号:杰哥的IT之旅(ID:Jake_Internet)
一、OAuth 介绍
OAuth2是一个授权框架,或称为授权标准,可以使第三方应用程序或客户端获得对http服务上用户账号信息的有限访问权限。
OAuth2通过将用户身份验证委派给托管用户账户的服务以及授权客户端访问用户账户进行工作上。OAuth2可以为web应用和桌面应用以及移动应用提供授权流程。
角色
OAuth标准定义了以下角色:
资源所有者(resource owner)
资源服务器(resource server)
授权服务器(authorization server)
客户端(client)
资源所有者
资源所有者是OAuth2四大基本角色之一。代表授权客户端访问本身资源信息的用户。也就是应用场景的开发者A,客户端访问用户账户的权限仅限于用户授权的范围。
资源/授权服务器
资源服务器托管了受保护的用户账号信息,而授权服务器验证用户身份然后为客户端派发资源访问令牌。
客户端
在OAuth2中,客户端即代表意图访问受限资源的第三方应用。在访问实现之前,必须先经过用户授权,并且获得的授权凭证将进一步有授权服务器进行验证。
二、CAS
CAS(Central Authentication Service)是耶鲁Yale大学发起的java开源项目,在为web应用系统提供可靠的单点登录解决方案(web sso)。
特点
开源的企业级单点登录解决方案
CAS server为需要独立部署的web应用,一个独立的web应用程序(war包)
Cas client支持非常多的客户端(指单点登录系统中的各个web应用),包括java、php、perl等
原理
从结构上,cas包含两个部分:CAS server和CAS client
CAS server
CAS server 需要独立部署,主要负责对用户的认证工作,处理用户名/密码等凭证(Credentials);
CAS server 负责完成对用户的认证工作,CAS server需要独立部署;
CAS server 会处理用户名/密码等凭证,可能会到数据库检索一条用户账号信息,也可能在XML文件中检索用户密码等,CAS均提供一种灵活但统一的接口/实现分离的方式,CAS协议是分离的,这个认证的实现细节可以自定义和扩展;
CAS client
CAS client部署在客户端,负责处理对本地web应用(客户端)受保护资源的访问请求,并且当需要对请求方进行身份认证是,重定向到CAS server进行认证;
CAS client负责部署在客户端,原则上CAS client的部署意味着:当有对本地web应用的受保护资源的访问请求,并且需要对请求方进行身份认证,web应用不在接受任何的用户名密码等类似的凭证,而是重定向到CAS server进行认证;
CSA相关概念
TGC(ticket-granting cookie):
授权的票据证明
,有 CAS server 通过 SSL 方式发送给客户端;KDC(key Distribution Center):
秘钥发放中心
;ST(service ticket):
服务票据
,由 KDC 的 TGS 发送,ST 只能被尝试验证一次。任何一台 workstation 都需要拥有一张有效的 service ticket,说明在 cas client-cas server 之间的信任关系已经被正确建立起来,通常为一张数字加密的证书;TGT(ticket grantung tieckt):
票据授权票据
,由 KDC 的 AS 发放。即获取这样的一张票据后,以后申请各种其他服务票据(ST)便不必在向 KDC 提交 credentials;AS(authentication service):
认证服务
,索取 Crendential,发放 TGT;TGS(ticket granting service):
票据授权服务
,索取 TGT,发放 ST;
三、工作流程
1.cas client与受保护的客户端应用部署在一起,以Filter方式保护收保护的资源。对于访问受保护资源的每个web请求,Cas client会分析该请求的http请求中是否包含service ticket和ticket granting tieckt,如果没有,说明当前用户尚未登录,于是将请求重定向到指定的csa server登录地址,并传递service,以便登录成功过后转回改地址。用户在第三步中输入认证信息,如果登录成功,csa server随机产生一个相当长度、唯一、不可伪造的service ticket,并缓存以待将来验证,之后系统自动重定向到service所在地址,并为客户端浏览器设置一个ticket granter cookie,cas client在拿到service和新产生的ticket过后,在第5.6步中与cas server进行身份核实,以确保service ticket的合法性。
2.在该协议中,所有与 CAS 的交互均采用 SSL 协议确保 ST 和 TGC 的安全性。协议工作过程中会有 2 次重定向的过程,但是 CAS Client 与 CAS Server 之间进行 Ticket 验证的过程对于用户是透明的。
3.CAS 如何实现 SSO
当用户访问另一服务再次被重定向到 CAS Server 的时候, CAS Server 会主动获到这个 TGC cookie ,然后做下面的事情:
如果 User 的持有 TGC 且其还没失效,那么就走基础协议图的 Step4 ,达到了 SSO 的效果;
如果 TGC 失效,那么用户还是要重新认证 ( 走基础协议图的 Step3) 。
另外,CAS 协议中还提供了 Proxy (代理)模式,以适应更加高级、复杂的应用场景
Cas的验证流程
1.用户浏览受系统保护的url
2.Csa client服务端收到请求,filter拦截该请求,在filter中判断该用户是否已经登录,如果已经登录,就直接进入系统,否则,将请求转发到cas server服务端的login__URL。
3.在login_URL中会获取到用户的cookie,检验用户是否已经在其他相关使用sso的系统登录成功。如果已经在其他的系统登录,则将请求转回cas client,并且带回一个ticket,cas client再次发送请求到validateURL,否则系统提示用户输入ID和passwd。
4.提交后请求到validateURL,cas server验证ticket的有效性。然后返回结果给cas client。如果ticket有效,则cas client应该让用户浏览受保护的资源。否则,重定向到登录页面,提示用户输入ID和Password。
5.校验ID和passwd是否匹配,如果不匹配,再次要求用户输入id和passwd。否则,cas server记录用户登录成功。并向浏览器回送cookie,记录用户已经登录成功。如果浏览器不支持cookie,则无法实现单点登录。
四、部署
Cas:
Github地址:https://apereo.github.io/cas/
Overlay版:https://github.com/apereo/cas-overlay-template
使用版本:5.x
将代码clone本地
git clone
cd cas-overlay-template
打开 pom.xml 文件,找到下面的部分
# vim pom.xml
<dependencies>
<dependency>
<groupId>org.apereo.cas</groupId>
<artifactId>cas-server-webapp${app.server}</artifactId>
<version>${cas.version}</version>
<type>war</type>
<scope>runtime</scope>
</dependency>
<!--
...Additional dependencies may be placed here...
-->
</dependencies>
将注释的部分替换需要的模块
<dependency>
<groupId>org.apereo.cas</groupId>
<artifactId>cas-server-webapp${app.server}</artifactId>
<version>${cas.version}</version>
<type>war</type>
<scope>runtime</scope>
</dependency> <dependency>
<groupId>org.apereo.cas</groupId>
<artifactId>cas-server-support-json-service-registry</artifactId>
<version>${cas.version}</version>
</dependency>
<dependency>
<groupId>org.apereo.cas</groupId>
<artifactId>cas-server-support-oauth-webflow</artifactId>
<version>${cas.version}</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.driver.version}</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.apereo.cas</groupId>
<artifactId>cas-server-support-jdbc</artifactId>
<version>${cas.version}</version>
</dependency>
<dependency>
<groupId>org.apereo.cas</groupId>
<artifactId>cas-server-support-jdbc-drivers</artifactId>
<version>${cas.version}</version>
</dependency>
<!--
<dependency>
<groupId>org.apereo.cas</groupId>
<artifactId>cas-server-support-rest</artifactId>
<version>${cas.version}</version>
<scope>runtime</scope>
</dependency>
-->
<dependency>
<groupId>org.apereo.cas</groupId>
<artifactId>cas-server-support-ldap</artifactId>
<version>${cas.version}</version>
</dependency>
<!--
<dependency>
<groupId>org.apereo.cas</groupId>
<artifactId>cas-server-support-jpa-ticket-registry</artifactId>
<version>${cas.version}</version>
</dependency>
<dependency>
<groupId>org.apereo.cas</groupId>
<artifactId>cas-server-support-jpa-service-registry</artifactId>
<version>${cas.version}</version>
</dependency>
<dependency>
<groupId>org.apereo.cas</groupId>
<artifactId>cas-server-support-rest-services</artifactId>
<version>${cas.version}</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.apereo.cas</groupId>
<artifactId>cas-server-support-json-service-registry</artifactId>
<version>${cas.version}</version>
</dependency>
-->
</dependencies>
上面添加了openLDAP、oauth2.0、mysql的依赖
添加mysql需要指定connector-java连接器的版本
<mysql.driver.version>5.1.47</mysql.driver.version>
编辑好pom文件后,执行下面的命令开始编译
# mvn clean package
编译完成后,会在此目录下生成一个target目录,需要的war包就在里面
下载Tomcat
将war包保存到tomcat的webapps目录下,然后运行tomcat即可
./startup.sh
tail -f /usr/local/tomcat/log/Catalina.out
运行完成后,打开http://localhost:8080/cas 默认用户名密码为:casuser/Mellon
五、开启Oauth2.0授权
修改/usr/local/tomcat/webapps/cas/WEB-INF/class/application.properties文件
cas.authn.oauth.refreshToken.timeToKillInSeconds=2592000
cas.authn.oauth.code.timeToKillInSeconds=30
cas.authn.oauth.code.numberOfUses=1
cas.authn.oauth.accessToken.releaseProtocolAttributes=true
cas.authn.oauth.accessToken.timeToKillInSeconds=7200
cas.authn.oauth.accessToken.maxTimeToLiveInSeconds=28800
cas.authn.oauth.grants.resourceOwner.requireServiceHeader=true
cas.authn.oauth.userProfileViewType=NESTED
cas.server.name=http://devops.top:8080/cas
cas.server.prefix=${cas.server.name}
cas.tgc.secure=false
cas.serviceRegistry.initFromJson=true
将”serviceID”:”^(https|imags)://.*”,改为”serviced”:”^(https|http|imaps)://.*”
添加OAUTH-1002.json.service注册文件
{
"@class" : "org.apereo.cas.support.oauth.services.OAuthRegisteredService",
"clientId": "20181124",
"clientSecret": "123456",
"serviceId" : "^(https|http|imaps)://.*",
"name" : "OAuthService",
"id" : 1002
}
重启完成后,进行测试,浏览器打开:http://localhost:8080/cas/oauth2.0/authorize?response_type=code&client_id=20181124&redirect_uri=https://www.baidu.com
登录成功后后,点击Allow即可成功授权跳转至url,并且uri会携带一个code。
六、整合Opneldap
vi /usr/local/tomcat/webapps/cas/WEB-INF/classes/application.properties
注释掉默认的cas.authn.accept.users认证方式并添加与LDAP server连接的配置
##
# CAS Authentication Credentials
#
# cas.authn.accept.users=casuser::Mellon
cas.authn.ldap[0].type=AUTHENTICATED # ldap服务类型
cas.authn.ldap[0].ldapUrl=ldap://192.168.1.10:389 #ldap地址
cas.authn.ldap[0].useSsl=false
cas.authn.ldap[0].baseDn=dc=dong,dc=com # 修改用户baseDN
cas.authn.ldap[0].searchFilter=(|(uid={user})(mail={user})(mobile={user})) # 用户查询方式
cas.authn.ldap[0].bindDn=cn=admin,dc=dong,dc=com # 配置用户
cas.authn.ldap[0].bindCredential=123456 #配置密码
cas.authn.ldap[0].principalAttributeList=sn,cn:commonName,givenName, eduPersonTargettedId:SOME_IDENTIFIER #配置返回属性
# default values:
cas.authn.ldap[0].minPoolSize=3
cas.authn.ldap[0].maxPoolSize=10
cas.authn.ldap[0].validateOnCheckout=true
cas.authn.ldap[0].validatePeriodically=true
cas.authn.ldap[0].validatePeriod=600
cas.authn.ldap[0].idleTime=5000
cas.authn.ldap[0].prunePeriod=5000
cas.authn.ldap[0].blockWaitTime=5000sonTargette
重启Tomcat查看日志
# ./shutdown.sh
# ./start.sh
# tail -f /usr/local/tomcat/logs/Catalina.out
七、Gitlab集成cas
前提条件:gitlab首先集成openLDAP
相关文档链接
https://gitlab.com/help/integration/cas.md
https://gitlab.com/help/integration/omniauth.md#initial-omniauth-configuration
https://apereo.github.io/cas/4.2.x/protocol/CAS-Protocol-Specification.html
Cas服务器,在配置文件中添加
cas.server.name=http://devops.top:8080/cas
cas.server.prefix=${cas.server.name}
cas.tgc.secure=false
cas.serviceRegistry.initFromJson=true
cas.serviceRegistry.schedule.repeatInterval=120000
cas.serviceRegistry.schedule.startDelay=15000
cas.serviceRegistry.json.location=classpath:/services
========================= 分割线 ==============================
将”serviceID”:”^(https|imags)://.*”,改为”serviced”:”^(https|http|imaps)://.*”
重启Tomcat
Gitlab服务器
1.Gitlab集成openLDAP
修改配置文件/etc/gitlab/gitltb.rb
# vim /etc/gitlab/gitlab.rb
gitlab_rails['ldap_enabled'] = true
gitlab_rails['ldap_servers'] = YAML.load <<-'EOS'
main: # 'main' is the GitLab 'provider ID' of this LDAP server
label: 'LDAP'
host: '192.168.1.30' #openldap的ip
port: 389 #ldap的端口号
uid: 'uid' #以哪个属性作为验证属性,可以为uid,cn等
uid: ’ sAMAccountName’ #配置AD域使用,可以写上,具体没有太多介绍
bind_dn: 'cn=admin,dc=dong,dc=com' #openldap的管理账号,也可以只读的账号
password: '123456' #openldap的管理账号的passwd
encryption: 'plain' # "start_tls" or "simple_tls" or "plain"
verify_certificates: true
active_directory: true #针对连接是否ad域空的标识,为true
allow_username_or_email_login: true #用户登录是否用户名和邮箱都可以,为了方便配置为true
lowercase_usernames: false
block_auto_created_users: false
base: 'dc=dong,dc=com' #用户列表所在的目录。从哪个位置搜索用户。
user_filter: '' # 添加过滤属性,例如只过滤employeeType为developer的用户进行认证
attributes: #gitlab将用于为ldap用户创建账户的ldap属性。
username: ['uid', 'userid', 'sAMAccountName']
email: ['mail', 'email', 'userPrincipalName']
name: 'cn'
first_name: 'givenName'
last_name: 'sn'
EOS
修改完以上配置后需重置gitlab参数
# gitlab-ctl reconfigure
# gitlab-ctl restart
# gitlab-rake gitlab:ldap:check
2.整合CAS
需要配置的相关参数如下:
1.启用Omniauth登录,设置Omniauth_enable参数为true,在版本11.4以后默认是开启的。只是用cas服务进行登录,设置omniauth_auto_sign_in_with_provider参数为cas3。
2.配置omniauth_allow_single_sign_on参数控制第三方登录的用户自动创建,为true时,所有的第三方登录都会自动创建用户,为false时,所有的第三方登录都不会自动创建用户。还可以是list,比如[‘cas3’],只为列表有的第三方登录的自动创建用户。
3.配置omniauth_block_auto_created_users参数控制自动创建的用户是否被锁定,为true时,自动创建的用户全部被多订,需要管理员操作解锁后才能使用,为false时,自动创建的用户可以正常使用,因此设置为false的时候,需要保证,对于第三方的用户完全可控。
4.配置omniauth_providers参数确定具体的cas协议的相关连接。
5.auto_link_ldap_user如果启用了ldap/activeDirectory集成,则可以使用,默认为false。启用后,通过omniauth自动创建的用户也将连接到ldap条目中。
注意:在ldap和omniauth提供程序中,auto_link_ldap_user要求uid用户的ID相同。
修改配置文件/etc/gitlab/gitlab.rb
# vim /etc/gitlab/gitlab.rb
gitlab_rails['omniauth_allow_single_sign_on'] = ['cas3']
gitlab_rails['omniauth_block_auto_created_users'] = false
gitlab_rails['omniauth_auto_link_ldap_user'] = true
gitlab_rails['omniauth_providers'] = [
{
"name" => "cas3",
"label" => "cas",
"args" => {
"url" => "http://192.168.1.133:8080",
"login_url" => "/cas/login",
"service_validate_url" => "/cas/p3/serviceValidate",
"logout_url" => "/cas/logout/"
}
}
]
gitlab_rails['omniauth_providers'] = [
{
"name" => "cas3",
"label" => "cas",
"args" => {
"url" => "CAS_SERVER",
"login_url" => "/CAS_PATH/login",
"service_validate_url" => "/CAS_PATH/p3/serviceValidate",
"logout_url" => "/CAS_PATH/logout/"
}
}
]
其中参数的说明:
CAS_PATH:更改为CAS实例的根。
可能存在的问题及解决方案:
1.配置注销登录的接口
有的版本,存在注销登录时,gitlab不会自动调用配置的cas的注销接口。可以采用登录root账号,然后配置AFTER sign out path为cas的注销接口来解决
登录root账号,进入admin area,选择settings,选择general,选择sign-in retrictions
配置After sign out path为cas服务的注销接口。然后点击save changes保存修改。
After sign out path中的url必须带service参数,该servie参数是cas注销登录后的重定向地址,所以service的值为gitlab的登录url。(根据实际情况而定)。
2.gitlab账号与cas账号之间的关系
Gitlab自身维护一套用户系统,csa服务也有一套用户系统,gitlab可以将两者关联起来,然后用户可以选择其中一种方式进行登录就可以。
根据用户是否有gitlab账号,可以分为两种情况:
1)已有gitlab账号的,用户可按原来的登录方式进行登录,然后在用户设置里关联cas账号,也可以有root账号进行统一的关联。
2)没有gitlab账号的,在直接使用cas服务登录的时候,根据参数的配置,分为以下几种情况:
自动创建同名的gitlab账号,锁定该账号,需要登录root账号,解锁该账号,然后完善个人信息以后,可以使用。配置如下:
gitlab_rails['omniauth_allow_single_sign_on'] = ['cas3']
gitlab_rails['omniauth_block_auto_created_users'] = true
自动创建同名的gitlab账号,不锁定该账号,完善个人信息,即可使用。
gitlab_rails['omniauth_allow_single_sign_on'] = ['cas3']
gitlab_rails['omniauth_block_auto_created_users'] = false
不创建账号,直接提示需要绑定已有的账号。
gitlab_rails['omniauth_allow_single_sign_on'] = false
3.使用root账号将普通gitlab账号和cas账号关联和解除关联
除了用户自己可以进行gitlab账号和cas账号的关联外,root账号可以为所有gitlab 账号关联cas账号。
登录root账号,进入admin area,选择users
点击需要关联cas账号的用户,选择identified,点击new identity,为该用户新增一个identity。
选择一个provider,也就是前面配置的cas服务,输入identity,点击save changes,即可完成gitlab账号与cas账号的绑定。
PS:这里的identifier,是gitlab向cas服务器端发送验证请求的时候,验证成功后,cas服务器返回给gitlab的值。Cas服务器返回的是用户的用户名,因此identifier需要填用户名。
普通gitlab账号和cas账号的关联的解除和修改
与上面关联账号的步骤一样,登录root账号,进入admin area,选择users,点解需要解除关联cas账号的用户,选择identities。Delete相应的identifier,即可解除关联,选择edit进行identifier的编辑修改。
本公众号全部文章已整理成一个目录,请在本公众号后台回复「m
」获取!
推荐阅读
*《“狗屁不通文章生成器”登顶GitHub热榜,分分钟写出万字形式主义大作》
*《如何写出让同事无法维护的代码?》
*《Linux 服务器为什么被黑?》
*《利用 Python 进行多 Sheet 表合并、多工作簿合并、一表按列拆分》
*《有了这个技巧,即便领导盯着你,你都能给他玩出新花样,哼!》
*《2019中国互联网300强》