Skip to content

CAS Overlay Template 4.x 版本指南

官方介绍

CAS Overlay Template 4.x 是 Apereo CAS 项目的官方推荐部署方式,它基于 Apache Maven 的 overlay 机制,允许开发者在不修改 CAS 源代码的情况下进行定制化开发。Overlay 模板提供了一种干净、可维护的方式来集成 CAS 并添加自定义功能。

CAS (Central Authentication Service) 4.x 是一个企业级的单点登录系统,支持多种认证协议,包括 SAML1.1、SAML2、CAS 协议等。


版本特性

核心特性

  • 轻量级部署: 基于 Spring Framework,简化了部署过程
  • 模块化架构: 支持插件化扩展
  • 协议支持: 支持 CAS、SAML1.1、SAML2
  • 多认证源: 支持 LDAP、数据库、JAAS、RDBMS 等多种认证方式
  • 安全性: 内置安全机制,支持 MFA(多因素认证)

4.x 版本演进

  • 4.0.x: 初始版本,奠定了基础架构
  • 4.1.x: 增强了配置管理,改进了安全性
  • 4.2.x: 改进了对 Spring Webflow 的集成,支持更多认证协议,改进了性能
  • 4.3.x: 增强了对 REST 接口的支持,增强了监控和日志功能
  • 4.4.x: 最终长期支持版本,提供了更好的稳定性,增加了对 JWT、OAuth2 的更好支持

官方获取地址

bash
# 通过 Git Clone 获取 CAS Overlay Template 4.x
git clone -b 4.2.x https://github.com/apereo/cas-overlay-template.git cas-overlay-4.x

或者指定特定版本:

bash
git clone -b 4.2.7 https://github.com/apereo/cas-overlay-template.git cas-overlay-4.2.7

环境要求

  • Java: JDK 8 或更高版本
  • Maven: 3.2.1 或更高版本
  • Git: 用于版本控制
  • 操作系统: 跨平台支持(Linux、Windows、macOS)

部署方法

1. 克隆项目

bash
git clone -b 4.2.x https://github.com/apereo/cas-overlay-template.git cas-overlay-4.x
cd cas-overlay-4.x

2. 构建项目

bash
# 清理并构建项目
mvn clean compile

# 构建 WAR 包
mvn clean package

# 直接运行(开发模式)
mvn clean spring-boot:run

3. 配置文件说明

CAS 4.x 使用以下配置文件:

application.properties

properties
# 服务器配置
server.port=8443
server.ssl.enabled=true
server.ssl.key-store=file:/etc/cas/thekeystore
server.ssl.key-store-password=changeit
server.ssl.key-password=changeit

# CAS 服务器名称
cas.server.name=https://cas.example.org:8443
cas.server.prefix=https://cas.example.org:8443/cas

# 认证配置
cas.authn.accept.users=casuser::Mellon

# 日志配置
logging.config=file:/etc/cas/log4j2.xml

4. 部署到应用服务器

bash
# 构建 WAR 文件
mvn clean package

# 将生成的 WAR 文件部署到 Tomcat
cp target/cas.war /path/to/tomcat/webapps/

二次开发

自定义认证处理器

创建自定义认证处理器示例:

src/main/java/com/example/CustomAuthenticationHandler.java

java
package com.example;

import org.jasig.cas.authentication.HandlerResult;
import org.jasig.cas.authentication.PreventedException;
import org.jasig.cas.authentication.UsernamePasswordCredential;
import org.jasig.cas.authentication.handler.support.AbstractPreAndPostProcessingAuthenticationHandler;
import org.jasig.cas.authentication.principal.PrincipalFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.security.auth.login.AccountNotFoundException;
import javax.security.auth.login.FailedLoginException;
import java.security.GeneralSecurityException;

@Component("customAuthenticationHandler")
public class CustomAuthenticationHandler extends AbstractPreAndPostProcessingAuthenticationHandler {

    public CustomAuthenticationHandler() {
        super();
    }

    @Autowired
    public CustomAuthenticationHandler(PrincipalFactory principalFactory) {
        super(principalFactory);
    }

    @Override
    protected HandlerResult doAuthentication(UsernamePasswordCredential credential) throws GeneralSecurityException, PreventedException {
        String username = credential.getUsername();
        String password = credential.getPassword();

        // 自定义认证逻辑
        if (authenticateUser(username, password)) {
            return createHandlerResult(credential, this.principalFactory.createPrincipal(username), null);
        } else {
            throw new FailedLoginException("Authentication failed");
        }
    }

    private boolean authenticateUser(String username, String password) {
        // 实现您的认证逻辑
        return "admin".equals(username) && "password".equals(password);
    }
}

自定义属性解析器

src/main/java/com/example/CustomPersonAttributeDao.java

java
package com.example;

import org.jasig.services.persondir.IPersonAttributes;
import org.jasig.services.persondir.support.NamedStubPersonAttributeDao;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Component("customPersonAttributeDao")
public class CustomPersonAttributeDao extends NamedStubPersonAttributeDao {

    @Override
    public IPersonAttributes getPerson(String uid) {
        Map<String, List<Object>> attributes = new HashMap<>();
        
        // 添加自定义属性
        attributes.put("mail", List.of(uid + "@example.org"));
        attributes.put("displayName", List.of("User " + uid));
        attributes.put("memberOf", List.of("GROUP1", "GROUP2"));
        
        return new org.jasig.services.persondir.support.StubPersonAttributeTO(uid, attributes);
    }
}

自定义视图

src/main/resources/templates 目录下可以自定义 CAS 的视图模板。例如,创建自定义登录页面:

src/main/resources/templates/casLoginView.html

html
<!DOCTYPE html>
<html xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" layout:decorate="~{layout}">
<head>
    <meta charset="UTF-8"/>
    <title>CAS Login</title>
</head>
<body>
    <div layout:fragment="content">
        <div class="box fl-panel">
            <h2>Custom Login Form</h2>
            <form method="post" th:object="${credential}" id="fm1" class="fm-v clearfix">
                <div class="row fl-controls-left">
                    <label for="username" class="fl-label">Username:</label>
                    <input class="required" id="username" size="25" tabindex="1" 
                           type="text" th:field="*{username}" 
                           autocomplete="off" />
                </div>
                
                <div class="row fl-controls-left">
                    <label for="password" class="fl-label">Password:</label>
                    <input class="required" id="password" size="25" tabindex="2" 
                           type="password" th:field="*{password}" 
                           autocomplete="off" />
                </div>
                
                <div class="row btn-row">
                    <input type="hidden" name="execution" th:value="${flowExecutionKey}" />
                    <input type="hidden" name="_eventId" value="submit" />
                    <input type="hidden" name="geolocation" />
                    
                    <input class="btn-submit" name="submit" accesskey="l" 
                           th:value="#{screen.welcome.button.login}" 
                           tabindex="6" type="submit" />
                </div>
            </form>
        </div>
    </div>
</body>
</html>

配置示例

LDAP 认证配置

application.properties

properties
# LDAP 配置
cas.authn.ldap[0].type=AUTHENTICATED
cas.authn.ldap[0].ldapUrl=ldaps://ldap.example.org:636
cas.authn.ldap[0].baseDn=ou=people,dc=example,dc=org
cas.authn.ldap[0].userFilter=uid={user}
cas.authn.ldap[0].bindDn=cn=admin,dc=example,dc=org
cas.authn.ldap[0].bindCredential=password
cas.authn.ldap[0].principalAttributeList=uid,sn,givenName,mail
cas.authn.ldap[0].principalIdAttribute=uid

数据库认证配置

application.properties

properties
# 数据库认证配置
cas.authn.jdbc.query[0].sql=SELECT password FROM users WHERE username=?
cas.authn.jdbc.query[0].healthQuery=SELECT 1
cas.authn.jdbc.query[0].isolateInternalQueries=false
cas.authn.jdbc.query[0].url=jdbc:mysql://localhost:3306/cas
cas.authn.jdbc.query[0].failFast=true
cas.authn.jdbc.query[0].isolationLevelName=ISOLATION_READ_COMMITTED
cas.authn.jdbc.query[0].dialect=org.hibernate.dialect.MySQL5Dialect
cas.authn.jdbc.query[0].leakThreshold=10
cas.authn.jdbc.query[0].propagationBehaviorName=PROPAGATION_REQUIRED
cas.authn.jdbc.query[0].batchSize=1
cas.authn.jdbc.query[0].user=database_user
cas.authn.jdbc.query[0].password=database_password
cas.authn.jdbc.query[0].driverClass=com.mysql.jdbc.Driver
cas.authn.jdbc.query[0].name=QUERY

Demo 示例

简单的 Hello World 示例

创建一个简单的 CAS 客户端应用来演示集成:

pom.xml

xml
<dependencies>
    <dependency>
        <groupId>org.jasig.cas.client</groupId>
        <artifactId>cas-client-core</artifactId>
        <version>3.4.1</version>
    </dependency>
</dependencies>

web.xml

xml
<filter>
    <filter-name>CAS Authentication Filter</filter-name>
    <filter-class>org.jasig.cas.client.authentication.AuthenticationFilter</filter-class>
    <init-param>
        <param-name>casServerLoginUrl</param-name>
        <param-value>https://cas.example.org:8443/cas/login</param-value>
    </init-param>
    <init-param>
        <param-name>serverName</param-name>
        <param-value>http://client.example.org:8080</param-value>
    </init-param>
</filter>

<filter-mapping>
    <filter-name>CAS Authentication Filter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

常见问题和解决方案

1. SSL 证书问题

如果遇到 SSL 证书问题,可以临时禁用 SSL 验证(仅用于开发环境):

properties
cas.server.ssl.validation=false

2. 认证失败问题

检查日志文件以确定认证失败的原因:

bash
tail -f /path/to/catalina.out

3. 内存溢出问题

增加 JVM 内存设置:

bash
export JAVA_OPTS="-Xms512m -Xmx2048m -XX:MaxPermSize=512m"

性能优化

连接池配置

properties
# 数据库连接池
cas.jdbc.pool.minSize=2
cas.jdbc.pool.maxSize=10
cas.jdbc.pool.maxWait=2000

# LDAP 连接池
cas.authn.ldap[0].minPoolSize=3
cas.authn.ldap[0].maxPoolSize=10
cas.authn.ldap[0].validateOnCheckout=true

缓存配置

properties
# EhCache 配置
cas.ticket.registry.ehcache.maxElementsInMemory=1000
cas.ticket.registry.ehcache.eternal=false
cas.ticket.registry.ehcache.timeToLive=28800
cas.ticket.registry.ehcache.timeToIdle=28800

升级指南

从 4.1.x 升级到 4.2.x:

  1. 备份现有配置
  2. 更新 pom.xml 中的 CAS 版本
  3. 检查废弃的配置属性
  4. 测试认证流程
  5. 部署到生产环境

总结

CAS Overlay Template 4.x 提供了一种简单而强大的方式来部署和自定义 CAS 服务。通过 overlay 机制,开发者可以轻松地添加自定义功能,同时保持与上游版本的兼容性。虽然 4.x 系列已经不再积极维护,但对于仍在使用该版本的组织来说,这个模板仍然是一个很好的起点。