【CAS配置】服务端配置

CAS的全称Central Authentication Service即中央认证服务,是Web系统中企业单点登录(SSO)的一个解决方案

1 基础概念

1.1 CAS协议包含三部分

  • 客户端浏览器
  • CAS服务器
  • 请求验证身份的应用程序

1.2  环境

1.3 CAS术语

TGC

TGT

ST

PGT

2 CAS服务部署

2.1 基础环境准备

CAS的官方文档

https://apereo.github.io/cas/5.3.x/index.html

 本文以Maven方式编译CAS服务端,overlay方式是指可以基于配置文件覆盖CAS原工程中的配置,达到自定义CAS服务目的。

将github中的工程克隆到本地

https://github.com/apereo/cas-overlay-template

2.2 基础配置

本文基于自定义配置方案配置CAS服务端,使用CAS自带的Tomcat。

2.2.1 添加maven镜像

办法1:直接在cas的pom.xml文件中添加aliyun镜像

    <repositories>
      <repository>
            <id>maven-ali</id>
            <url>http://maven.aliyun.com/nexus/content/groups/public//</url>
            <releases>
                <enabled>true</enabled>
            </releases>
            <snapshots>
                <enabled>true</enabled>
                <updatePolicy>always</updatePolicy>
                <checksumPolicy>fail</checksumPolicy>
            </snapshots>
        </repository>
    </repositories>

办法2:在maven的settings.xml

  <mirrors>
    <mirror>
        <id>nexus-aliyun</id>
        <mirrorOf>*</mirrorOf>
        <name>Nexus aliyun</name>
        <url>http://maven.aliyun.com/nexus/content/groups/public</url>
    </mirror>
  </mirrors>

2.2.2 配置证书

需求是基于https登陆CAS服务端,我们使用JDK自带的工具keytool在当前目录生成证书,sso.bob.net就是当前CAS服务端的地址,后续基于此地址访问。

密钥口令是:123456

➜  ca keytool -genkey -alias caskeystore -keypass 123456 -keyalg RSA -keystore thekeystore
输入密钥库口令:
再次输入新口令:
您的名字与姓氏是什么?
  [Unknown]:  sso.bob.net
您的组织单位名称是什么?
  [Unknown]:  bob
您的组织名称是什么?
  [Unknown]:  bob
您所在的城市或区域名称是什么?
  [Unknown]:  sz
您所在的省/市/自治区名称是什么?
  [Unknown]:  js
该单位的双字母国家/地区代码是什么?
  [Unknown]:  cn
CN=sso.bob.net, OU=bob, O=bob, L=sz, ST=js, C=cn是否正确?
  [否]:  y

2.2.3 导出数字证书

密钥口令是:123456

keytool -export -alias caskeystore -keystore thekeystore -rfc -file cas.crt

2.2.4 将数字证书导入到JDK下的JRE

导入JDK,输入的密码是changeit,

sudo keytool -import -alias caskeystore -keystore $JAVA_HOME/jre/lib/security/cacerts -file cas.crt -trustcacerts -storepass changeit

2.2.5 配置本地IP域名映射

windows系统需要编辑

C:\Windows\System32\drivers\etc\hosts

2.2.6 keytool相关命令

# 查看thekeystore证书信息

keytool -list -keystore thekeystore

# 查看证书列表

keytool -list -keystore $JAVA_HOME/jre/lib/security/cacerts -storepass changeit

# 删除指定证书

keytool -delete -alias taobao -keystore $JAVA_HOME/jre/lib/security/cacerts -storepass changeit

2.3 更改CAS配置

使用idea导入CAS工程,mvn clean package,在根目录下得到target目录,打开WEB-INF目录下的classes里面的application.properties文件。根目录新建src/main/resources文件夹,同时将刚才的application.properties文件复制到该目录下。整个工程目录如下:

打开application.properties文件,我们可以发现在开头有配置信息如下:

server.ssl.key-store=file:/etc/cas/thekeystore
server.ssl.key-store-password=changeit
server.ssl.key-password=changeit

修改成

#SSL配置
server.ssl.enabled=true
server.ssl.key-store=classpath:thekeystore
server.ssl.key-store-password=123456
server.ssl.key-password=123456
server.ssl.keyAlias=caskeystore

其中server.ssl.key-store=classpath:thekeystore表示证书放在工程目录下,每次编译就使用此证书,方便迁移,本文就不在将证书放在本机的/etc/cas目录下。

在根目录下执行

# 清理工程

sh build.sh clean

# 打包

sh build.sh package

# 打包运行

sh build.sh run

# 直接运行war包

java -jar target/cas.war

CAS服务端启动失败,可以查看这里

2.4 基于JDBC的认证配置

2.4.1 JDBC依赖

默认的用户认证方式是在application.properties中配置用户名以及密码,但是这个只是用于demo。本文需要使用JDBC方式验证登录用户,即将用户名以及密码存入数据库,基于JDBC查询数据库,验证用户密码是否可以通过。

<!--新增支持jdbc验证-->
        <dependency>
            <groupId>org.apereo.cas</groupId>
            <artifactId>cas-server-support-jdbc</artifactId>
            <version>${cas.version}</version>
        </dependency>

        <!--若不想找驱动可以直接写下面的依赖即可,其中包括HSQLDB、Oracle、MYSQL、PostgreSQL、MariaDB、Microsoft SQL Server-->
        <dependency>
            <groupId>org.apereo.cas</groupId>
            <artifactId>cas-server-support-jdbc-drivers</artifactId>
            <version>${cas.version}</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>${mysql.driver.version}</version>
        </dependency>

2.4.2 表信息

expired:过期字段,1为过期,需要修改密码。

disabled:不可用字段,1为不可用。

Mysql表结构信息如下:

CREATE TABLE `auth`.`user`  (
  `id` varchar(255) CHARACTER SET latin1 COLLATE latin1_swedish_ci NOT NULL,
  `username` varchar(255) CHARACTER SET latin1 COLLATE latin1_swedish_ci NULL DEFAULT NULL,
  `password` varchar(255) CHARACTER SET latin1 COLLATE latin1_swedish_ci NULL DEFAULT NULL,
  `expired` varchar(255) CHARACTER SET latin1 COLLATE latin1_swedish_ci NULL DEFAULT NULL,
  `disabled` varchar(255) CHARACTER SET latin1 COLLATE latin1_swedish_ci NULL DEFAULT NULL,
  `email` varchar(255) CHARACTER SET latin1 COLLATE latin1_swedish_ci NULL DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = latin1 COLLATE = latin1_swedish_ci ROW_FORMAT = Dynamic;



CREATE TABLE `auth`.`user_attr`  (
  `id` varchar(255) CHARACTER SET latin1 COLLATE latin1_swedish_ci NOT NULL,
  `username` varchar(255) CHARACTER SET latin1 COLLATE latin1_swedish_ci NULL DEFAULT NULL,
  `role` varchar(255) CHARACTER SET latin1 COLLATE latin1_swedish_ci NULL DEFAULT NULL,
  `company` varchar(255) CHARACTER SET latin1 COLLATE latin1_swedish_ci NULL DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = latin1 COLLATE = latin1_swedish_ci ROW_FORMAT = Dynamic;

表数据如下:

user表:

user_arttr表:

2.4.3 认证

对于密码,常用加密算法如下:

  • MD5
  • SHA
  • HMAC

加密类型包括:

Type Description
NONE No password encoding (i.e. plain-text) takes place.
DEFAULT Use the DefaultPasswordEncoder of CAS. For message-digest algorithms via characterEncoding and encodingAlgorithm.
BCRYPT Use the BCryptPasswordEncoder based on the strengthprovided and an optional secret.
SCRYPT Use the SCryptPasswordEncoder.
PBKDF2 Use the Pbkdf2PasswordEncoder based on the strengthprovided and an optional secret.
STANDARD Use the StandardPasswordEncoder based on the secretprovided.
GLIBC_CRYPT Use the GlibcCryptPasswordEncoder based on the encodingAlgorithmstrength provided and an optional secret.
org.example.MyEncoder An implementation of PasswordEncoder of your own choosing.
file:///path/to/script.groovy Path to a Groovy script charged with handling password encoding operations.

如果需要密码无加密,调整passwordEncoder.type=NONE

现在我们更改application.properties配置,同时注释静态用户配置,具体更改如下:


##
# CAS Authentication Credentials
#
#cas.authn.accept.users=casuser::Mellon

#查询账号密码SQL,必须包含密码字段
cas.authn.jdbc.query[0].sql=select * from user where username=?

#指定上面的SQL查询字段名(必须)
cas.authn.jdbc.query[0].fieldPassword=password

#指定过期字段,1为过期,若过期不可用
cas.authn.jdbc.query[0].fieldExpired=expired

#为不可用字段段,1为不可用,需要修改密码
cas.authn.jdbc.query[0].fieldDisabled=disabled

#数据库连接
cas.authn.jdbc.query[0].url=jdbc:mysql://10.110.149.65:3306/auth?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&useSSL=false

#数据库dialect配置
cas.authn.jdbc.query[0].dialect=org.hibernate.dialect.MySQLDialect

#数据库用户名
cas.authn.jdbc.query[0].user=wes

#数据库用户密码
cas.authn.jdbc.query[0].password=xxss

#数据库事务自动提交
cas.authn.jdbc.query[0].autocommit=false

#数据库驱动
cas.authn.jdbc.query[0].driverClass=com.mysql.jdbc.Driver

#超时配置
cas.authn.jdbc.query[0].idleTimeout=5000

#默认加密策略,通过encodingAlgorithm来指定算法,默认NONE不加密
# NONE|DEFAULT|STANDARD|BCRYPT|SCRYPT|PBKDF2
cas.authn.jdbc.query[0].passwordEncoder.type=DEFAULT
# 字符类型
cas.authn.jdbc.query[0].passwordEncoder.characterEncoding=UTF-8
# 加密算法
cas.authn.jdbc.query[0].passwordEncoder.encodingAlgorithm=MD5
# 加密盐
#cas.authn.jdbc.query[0].passwordEncoder.secret=
# 加密字符长度
#cas.authn.jdbc.query[0].passwordEncoder.strength=16

2.5 服务配置

2.5.1 基础概念

服务管理表示服务端注册各个应用/客户端,可以让这些应用/客户端使用指定的CAS服务。这些服务包括:

  • 授权服务-控制那些客户端可以参与CAS SSO会话
  • 强制身份验证 - 为强制身份验证提供管理控制
  • 属性发布-为客户端提供用户信息详情以进行授权和个性化

2.5.2 基于JSON的服务存储方式

CAS默认初始化使用,注册表在应用程序上下文初始化时从JSON配置文件中读取服务定义,期望在配置的目录位置内找到JSON文件。

添加依赖关系

<dependency>
    <groupId>org.apereo.cas</groupId>
    <artifactId>cas-server-support-json-service-registry</artifactId>
    <version>${cas.version}</version>
</dependency>

resources目录下心间services目录,在resources/services文件夹下面新建web-10000001.json,具体内容如下:

{
  "@class" : "org.apereo.cas.services.RegexRegisteredService",
  "serviceId" : "^(https|imaps|http)://.*",
  "name" : "web",
  "id" : 10000001,
  "evaluationOrder" : 10,
  "attributeReleasePolicy": {
    "@class": "org.apereo.cas.services.ReturnAllAttributeReleasePolicy"
  }
}

注意: Json文件名字规则为${name}-${id}.json,id必须为Json文件内容Json一致。

Json文件解释:

@class:必须为org.apereo.cas.services.RegisteredService的实现类,对其他属性进行一个json反射对象,常用的有RegexRegisteredService,匹配策略为id的正则表达式
serviceId:唯一的服务id
name: 服务名称,会显示在默认登录页
id:全局唯一标志
description:服务描述,会显示在默认登录页
evaluationOrder: 匹配争取时的执行循序,最好是比1大的数字

CAS工程中target目录下有个services目录,存放了CAS默认的服务配置项,本文直接弃用这些配置,即执行服务端时不初始化默认的服务配置项。在pom.xml文件中做如下配置。

</configuration>
    <dependentWarExcludes>
        **/services/*.json
    </dependentWarExcludes>
</configuration>

然后在配置文件application.properties下添加配置:

##
# Service Registry(服务注册)
#
# 开启识别Json文件,默认false
cas.serviceRegistry.initFromJson=true

#自动扫描服务配置,默认开启
#cas.serviceRegistry.watcherEnabled=true

#120秒扫描一遍
cas.serviceRegistry.schedule.repeatInterval=120000

#延迟15秒开启
# cas.serviceRegistry.schedule.startDelay=15000

# Json配置
cas.serviceRegistry.json.location=classpath:/services

启动CAS服务后,日志显示加载了一个服务配置项,如下图所示:

2.6 多属性返回配置

在业务系统的开发中往往少不了返回用户的一些属性,包括单属性以及多属性,例如用户的一些基本信息或者权限,部门角色等等,因为业务系统获取到这些信息可能需要做一些其他业务逻辑

本文基于JDBC方式配置CAS,实现多个属性返回。属性返回策略包括:

  • Return All (所有配置返回的都返回)
  • Deny All (配置拒绝的出现则报错)
  • Return Allowed(只返回允许的主要属性)
  • 自定义Filter(自定义过滤策略)

2.6.1 开启JSON服务配置


##
# Service Registry(服务注册)
#
# 开启识别Json文件,默认false
cas.serviceRegistry.initFromJson=true

#自动扫描服务配置,默认开启
cas.serviceRegistry.watcherEnabled=true

#120秒扫描一遍
cas.serviceRegistry.schedule.repeatInterval=120000

#延迟15秒开启
# cas.serviceRegistry.schedule.startDelay=15000

##
# Json配置
cas.serviceRegistry.json.location=classpath:/services

然后再在pom.xml文件中开启Json依赖包和属性返回依赖包

<!-- Json Service Registry -->
 <dependency>
      <groupId>org.apereo.cas</groupId>
      <artifactId>cas-server-support-json-service-registry</artifactId>
      <version>${cas.version}</version>
</dependency>

 <!-- Authentication Attributes -->
<dependency>
      <groupId>org.apereo.cas</groupId>
      <artifactId>cas-server-core-authentication-attributes</artifactId>
      <version>${cas.version}</version>
</dependency>
具体的JSON配置文件如下:
{
  "@class": "org.apereo.cas.services.RegexRegisteredService",
  "serviceId": "^(https|imaps|http)://.*",
  "name": "t1",
  "id": 1001,
  "evaluationOrder": 10,
  "attributeReleasePolicy": {
    "@class": "org.apereo.cas.services.ReturnAllAttributeReleasePolicy"
  }
}

说明:

  • 将表中所有属性返回
"attributeReleasePolicy": { 
    "@class": "org.apereo.cas.services.ReturnAllAttributeReleasePolicy" 
}
  • 限制属性返回,即返回指定的属性
"attributeReleasePolicy" : {
  	"@class" : "org.apereo.cas.services.ReturnAllowedAttributeReleasePolicy",
 	"allowedAttributes" : [ "java.util.ArrayList", [ "username", "mail" ] ]
}

2.6.2 单行属性配置

#单行属性
#cas.authn.attributeRepository.jdbc[0].attributes.username=username
#cas.authn.attributeRepository.jdbc[0].attributes.password=password
#cas.authn.attributeRepository.jdbc[0].attributes.expired=expired
#
#cas.authn.attributeRepository.jdbc[0].singleRow=true
#cas.authn.attributeRepository.jdbc[0].order=0
#cas.authn.attributeRepository.jdbc[0].requireAllAttributes=true
## cas.authn.attributeRepository.jdbc[0].caseCanonicalization=NONE|LOWER|UPPER
## cas.authn.attributeRepository.jdbc[0].queryType=OR|AND
#
#cas.authn.attributeRepository.jdbc[0].sql=SELECT * FROM user WHERE {0}
#cas.authn.attributeRepository.jdbc[0].username=username
#
##数据库连接
#cas.authn.attributeRepository.jdbc[0].url=jdbc:mysql://10.110.149.65:3306/auth?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&useSSL=false
#
##数据库dialect配置
#cas.authn.attributeRepository.jdbc[0].dialect=org.hibernate.dialect.MySQLDialect
#
##数据库用户名
#cas.authn.attributeRepository.jdbc[0].user=wq
#
##数据库用户密码
#cas.authn.attributeRepository.jdbc[0].password=123
#
##数据库事务自动提交
#cas.authn.attributeRepository.jdbc[0].autocommit=false
#
##数据库驱动
#cas.authn.attributeRepository.jdbc[0].driverClass=com.mysql.jdbc.Driver
#
##超时配置
#cas.authn.attributeRepository.jdbc[0].idleTimeout=5000
#
#cas.authn.attributeRepository.jdbc[0].ddlAuto=none
#
#cas.authn.attributeRepository.jdbc[0].leakThreshold=10
#cas.authn.attributeRepository.jdbc[0].batchSize=1
#cas.authn.attributeRepository.jdbc[0].dataSourceProxy=false

启动CAS服务,查看属性返回情况。

CAS服务端返回信息:

WHO: hebj
WHAT: [result=Service Access Granted,service=http://localhost:5000/cas/login/?orig...,principal=SimplePrincipal(id=hebj, attributes={password=[e10adc3949ba59abbe56e057f20f883e], expired=[0], username=[hebj]}),requiredAttributes={}]
ACTION: SERVICE_ACCESS_ENFORCEMENT_TRIGGERED
APPLICATION: CAS
WHEN: Sun Feb 23 09:28:56 CST 2020
CLIENT IP ADDRESS: 127.0.0.1
SERVER IP ADDRESS: 127.0.0.1

CAS客户端返回信息:

{   'cas:authenticationDate': '2020-02-23T09:28:56.485+08:00[Asia/Shanghai]', 
    'cas:authenticationMethod': 'QueryDatabaseAuthenticationHandler',    
    'cas:credentialType': 'UsernamePasswordCredential', 
    'cas:expired': '0', 
    'cas:isFromNewLogin': 'true', 
    'cas:longTermAuthenticationRequestTokenUsed': 'false', 
    'cas:password': 'e10adc3949ba59abbe56e057f20f883e',   
    'cas:successfulAuthenticationHandlers': 
    'QueryDatabaseAuthenticationHandler','cas:username': 'hebj'
}

2.6.3 多属性返回信息

#多行属性
cas.authn.attributeRepository.jdbc[1].attributes.admin=admin_multi
cas.authn.attributeRepository.jdbc[1].attributes.dev=dev_multi
cas.authn.attributeRepository.jdbc[1].attributes.user=user_multi

cas.authn.attributeRepository.jdbc[1].columnMappings.role=company

cas.authn.attributeRepository.jdbc[1].singleRow=false
cas.authn.attributeRepository.jdbc[1].order=1
cas.authn.attributeRepository.jdbc[1].requireAllAttributes=true
# cas.authn.attributeRepository.jdbc[1].caseCanonicalization=NONE|LOWER|UPPER
# cas.authn.attributeRepository.jdbc[1].queryType=OR|AND

cas.authn.attributeRepository.jdbc[1].sql=SELECT * FROM user_attr WHERE {0}
cas.authn.attributeRepository.jdbc[1].username=username

#数据库连接
cas.authn.attributeRepository.jdbc[1].url=jdbc:mysql://10.110.149.65:3306/auth?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&useSSL=false

#数据库dialect配置
cas.authn.attributeRepository.jdbc[1].dialect=org.hibernate.dialect.MySQLDialect

#数据库用户名
cas.authn.attributeRepository.jdbc[1].user=e q

#数据库用户密码
cas.authn.attributeRepository.jdbc[1].password=123

#数据库事务自动提交
cas.authn.attributeRepository.jdbc[1].autocommit=false

#数据库驱动
cas.authn.attributeRepository.jdbc[1].driverClass=com.mysql.jdbc.Driver

#超时配置
cas.authn.attributeRepository.jdbc[1].idleTimeout=5000

cas.authn.attributeRepository.jdbc[1].ddlAuto=none

cas.authn.attributeRepository.jdbc[1].leakThreshold=10
cas.authn.attributeRepository.jdbc[1].batchSize=1
cas.authn.attributeRepository.jdbc[1].dataSourceProxy=false

重启CAS服务端,查看属性返回信息。

CAS服务端信息:

WHO: hebj
WHAT: [result=Service Access Granted,service=http://localhost:5000/cas/login/?orig...,principal=SimplePrincipal(id=hebj, attributes={admin_multi=1, user_multi=[2, 1]}),requiredAttributes={}]
ACTION: SERVICE_ACCESS_ENFORCEMENT_TRIGGERED
APPLICATION: CAS
WHEN: Sun Feb 23 09:49:17 CST 2020
CLIENT IP ADDRESS: 127.0.0.1
SERVER IP ADDRESS: 127.0.0.1

CAS客户端返回信息:

{
    'cas:admin_multi': '1', 
    'cas:authenticationDate': '2020-02-23T09:49:17.900+08:00[Asia/Shanghai]', 
    'cas:authenticationMethod': 'QueryDatabaseAuthenticationHandler', 
    'cas:credentialType': 'UsernamePasswordCredential', 
    'cas:isFromNewLogin': 'true', 
    'cas:longTermAuthenticationRequestTokenUsed': 'false', 
    'cas:successfulAuthenticationHandlers': 
    'QueryDatabaseAuthenticationHandler',
    'cas:user_multi': ['2', '1']
}

关于客户端接收多属性配置,参看这里

参考:

1. 此博客写的非常详细,且基于MacOS环境做的本地配置,https://blog.csdn.net/Anumbrella/article/details/80821486

发布了58 篇原创文章 · 获赞 2 · 访问量 5515

猜你喜欢

转载自blog.csdn.net/hebaojing/article/details/104442050