SAML2 认证集成

1. 前言

在前面的几个小节里,我们讨论了 Spring Security 如何集成 OAuth2.0 认证规范。本节我们讨论另一种统一认证方案「SAML2.0」。

SAML 全称 Security Assertion Markup Language,中文含义为安全断言标记语言,目前该语言规范已升级到 2.0 版本。

和 OAuth2.0 相比,SAML2.0 的设计更为全面,涵盖了联邦认证、身份管理、单点登录的总体标准(OAuth2.0 仅规定了开放授权规范,不处理身份验证)。

SAML 2.0 常用于大型企业内部的统一身份认证服务,而在互联网应用中很少出现。

本节重点讨论 Spring Security 集成 SAML 2.0 认证的方法。

本小节实例开发环境

本小节所使用的实例代码是基于 Spring 官网中提供的最小化 HelloWorld 模板创建,请点此下载完整的 HelloWorld 模板压缩包

2. SAML 2.0 简介

SAML2.0 基于 XML 标准,核心目标是在不同安全域(Security Domain)之间交换认证和授权数据。

SAML2.0 的主要组成有:

  • 服务提供者(SP):类似于 OAuth2.0 中的资源服务,用来提供真正的商业服务;
  • 身份鉴别者(IDP):提供用户的身份鉴别服务,确保用户的身份真实可信;
  • 断言消息(Assertions):用来描述认证的对象,比如用户认证的时间、方式、基本及扩展信息(如:email、电话等);
  • 协议(Protocol):是一系列的 Request 和 Response 对象的合集,代表着某个行为需要执行的操作序列;
  • 绑定(Binding):代表了 SAML 信息通过何种通讯协议被传输,比如 HTTP、HTTP-POST、SOAP等;
  • 元数据(MetaData):是 SAML 中的配置数据,比如 IP 地址、绑定类型等。

SAML 2.0 的认证过程如下:

图片描述

3. SAML 2.0 认证集成

3.1 集成思路

SAML 2.0 认证登录,可以理解为 SP 从 IDP 获取 XML 格式断言消息的过程。目前有两种认证流程:

  • IDP 端发起方式。首先用户直接在 IDP(例如 Okta 认证中心)登录,然后选择一个将要授权的 SP(例如 Web 应用),IDP 随后发送断言消息到 SP。

  • SP 发起方式。用户首先访问一个 SP,SP 向 IDP 发现认证请求,IDP 要求用户登录,如果登录成功,IDP 将发送断言消息到 SP。

当前 Spring Security 对 SAML 2.0 已支持的特性包括:

  1. 通过 entityId = {baseUrl}/saml2/service-provider-metadata/{registrationId} 形式声明 SP;
  2. 通过 HTTP POST \ Redirect 方法,从 {baseUrl}/login/saml2/sso/{registrationId} 接收 SAML 响应中的认证断言;
  3. 断言签名;
  4. 支持断言内容加密;
  5. 支持对 Name ID 元素进行加密;
  6. 支持将认证断言的属性转换为 Converter<Assertion, Collection<? extends GrantedAuthority>> 对象;
  7. 允许使用 GrantedAuthoritiesMapper 管理权限白名单;
  8. 使用 java.security.cert.X509Certificate 公钥格式;
  9. SP 通过 AuthNRequest 初始化认证流程。

3.2 代码集成

  1. 开启 saml2Login() 支持;
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
                .anyRequest().authenticated()
                .and()
            .saml2Login() // 启动 SAML2 认证支持
        ;
    }
}
  1. 为 SAML 2.0 认证配置认证环境;
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
                .anyRequest().authenticated()
                .and()
            .saml2Login()
                .relyingPartyRegistrationRepository(...) // 配置认证环境
        ;
    }
}

在 SAML 2.0 中,SP 和 IDP 都是作为可信成员,将其映射保存在 RelyingPartyRegistration 对象中,RelyingPartyRegistration 对象通过 HttpSecurity 实例中的 .saml2Login().relyingPartyRegistrationRepository() 方法实现其数值配置。

至此,最基础的 SAML 2.0 的认证配置就已经完成了。

3.3 配置 RelyingPartyRegistration

SAML 2.0 认证的核心配置项都存在于 RelyingPartyRegistration 对象中。

3.3.1 URI 模板配置

在 SAML 2.0 协议中,每次请求都会产生一个 URI 参数,在 saml2Login 过程中,URI 可以包含以下变量信息:

  • baseUrl
  • registrationId
  • baseScheme
  • baseHost
  • basePort

使用举例如下:

{baseUrl}/login/saml2/sso/{registrationId}

3.3.2 可信成员配置

可信成员包含以下配置项:

  • registrationId,必填项,是当前配置项的唯一标识。
  • localEntityIdTemplate,可选项,根据请求生成节点 ID 时所选用的模板。
  • remoteIdpEntityId,必填项,IDP 的唯一标识。
  • assertionConsumerServiceUrlTemplate,可选项,当由 SP 发起认证后,断言成功的返回地址模板。
  • idpWebSsoUrl,必填项,IDP 做单点认证时的固定地址。
  • credentials,凭证列表,包含用于签名、验签、加密、解密的证书。

3.3.3 从 SP 发起认证

从 SP 发起认证,最便捷的方法是访问以下地址:

{baseUrl}/saml2/authenticate/{registrationId}

终端被访问后,会通过调用 createAuthenticationRequest 方法生成 AuthNRequest 对象用于认证请求,如果需要对请求进行配置,可以增加通过如下方式:

public interface Saml2AuthenticationRequestFactory {
    String createAuthenticationRequest(Saml2AuthenticationRequest request);
}

4. 小结

本节我们讨论了 Spring Security 集成 SAML2.0 认证服务的方法,主要知识点有:

  • Spring Security 在核心模块中已包含了 saml2Login 启动选项,可以用于构造 Saml 2.0 的 SP;
  • Spring Security 目前版本对 Saml 2.0 支持并不完整,但可以满足基本认证需求。

下节我们讨论 Spring Security 集成 CAS 认证的方法。