第 3 章 使用 SAML 保护应用程序和服务


本节论述了如何使用 Red Hat Single Sign-On 客户端适配器或通用 SAML 供应商库通过 SAML 保护应用程序和服务。

3.1. Java 适配器

Red Hat Single Sign-On 附带了一系列不同的 Java 应用程序适配器。选择正确的适配器取决于目标平台。

3.1.1. 常规适配器配置

Red Hat Single Sign-On 支持的每个 SAML 客户端适配器都可以通过简单的 XML 文本文件进行配置。它可能类似如下:

<keycloak-saml-adapter xmlns="urn:keycloak:saml:adapter"
                       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                       xsi:schemaLocation="urn:keycloak:saml:adapter https://www.keycloak.org/schema/keycloak_saml_adapter_1_10.xsd">
    <SP entityID="http://localhost:8081/sales-post-sig/"
        sslPolicy="EXTERNAL"
        nameIDPolicyFormat="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified"
        logoutPage="/logout.jsp"
        forceAuthentication="false"
        isPassive="false"
        turnOffChangeSessionIdOnLogin="false"
        autodetectBearerOnly="false">
        <Keys>
            <Key signing="true" >
                <KeyStore resource="/WEB-INF/keystore.jks" password="store123">
                    <PrivateKey alias="http://localhost:8080/sales-post-sig/" password="test123"/>
                    <Certificate alias="http://localhost:8080/sales-post-sig/"/>
                </KeyStore>
            </Key>
        </Keys>
        <PrincipalNameMapping policy="FROM_NAME_ID"/>
        <RoleIdentifiers>
            <Attribute name="Role"/>
        </RoleIdentifiers>
        <RoleMappingsProvider id="properties-based-role-mapper">
            <Property name="properties.resource.location" value="/WEB-INF/role-mappings.properties"/>
        </RoleMappingsProvider>
        <IDP entityID="idp"
             signaturesRequired="true">
        <SingleSignOnService requestBinding="POST"
                             bindingUrl="http://localhost:8081/auth/realms/demo/protocol/saml"
                    />

            <SingleLogoutService
                    requestBinding="POST"
                    responseBinding="POST"
                    postBindingUrl="http://localhost:8081/auth/realms/demo/protocol/saml"
                    redirectBindingUrl="http://localhost:8081/auth/realms/demo/protocol/saml"
                    />
            <Keys>
                <Key signing="true">
                    <KeyStore resource="/WEB-INF/keystore.jks" password="store123">
                        <Certificate alias="demo"/>
                    </KeyStore>
                </Key>
            </Keys>
        </IDP>
     </SP>
</keycloak-saml-adapter>
Copy to Clipboard Toggle word wrap

其中一些配置切换可能特定于适配器,一些在所有适配器中都很常见。对于 Java 适配器,您可以使用 ${…​} 213ure 作为系统属性替换。例如,${jboss.server.config.dir}

3.1.1.1. SP 元素

以下是 SP 元素属性的说明:

<SP entityID="sp"
    sslPolicy="ssl"
    nameIDPolicyFormat="format"
    forceAuthentication="true"
    isPassive="false"
    keepDOMAssertion="true"
    autodetectBearerOnly="false">
...
</SP>
Copy to Clipboard Toggle word wrap
entityID
这是此客户端的标识符。IdP 需要这个值来确定正在与之通信的客户端。此设置是 REQUIRED
sslPolicy
这是适配器将强制执行的 SSL 策略。有效值为: ALLEXTERNALNONE。对于 all,所有请求都必须通过 HTTPS 访问。对于 EXTERNAL,只有非私有 IP 地址必须通过 HTTPS 出现在线上。对于 NONE,不需要通过 HTTPS 发出请求。此设置选项为 选项。默认值为 EXTERNAL
nameIDPolicyFormat
SAML 客户端可以请求特定的 NameID 主题格式。如果您想要一个特定的格式,请填写这个值。它必须是标准的 SAML 格式标识符:urn :oasis:names:tc:SAML:2.0:name-format:transient。此设置选项为 选项。默认情况下,没有请求特殊格式。
forceAuthentication
SAML 客户端可以请求用户被重新验证,即使他们已在 IdP 中登录。把它设置为 true 来启用。此设置选项为 选项。默认值为 false
isPassive
SAML 客户端可以请求用户永远不会被要求验证,即使用户没有在 IdP 中登录。如果您想要这样做,则将其设置为 true。请勿与 forceAuthentication 一起使用,因为它们相反。此设置选项为 选项。默认值为 false
turnOffChangeSessionIdOnLogin
在某些平台上成功登录时,会话 ID 被修改,以插入安全攻击向量。将此选项更改为 true 以禁用此功能。建议您不要关闭它。默认值为 false
autodetectBearerOnly
如果您的应用程序同时为 Web 应用程序和 Web 服务(如 SOAP 或 REST)提供,则此项应设为 true。它允许您将 Web 应用的未经身份验证的用户重定向到 Red Hat Single Sign-On 登录页面,但向未经身份验证的 SOAP 或 REST 客户端发送 HTTP 401 状态代码,而不是将它们了解到登录页面。Red Hat Single Sign-On auto-detects SOAP 或 REST 客户端基于 X-Requested-WithSOAPActionAccept 等典型标头。默认值为 false
logoutPage
这会将页面设置为在注销后显示。如果页面是完整的 URL,如 http://web.example.com/logout.html,则在使用 HTTP 302 状态代码注销后,用户会被重定向到该页面。如果指定了没有方案部分的链接,如 /logout.jsp,则该页会在注销 后显示,无论它依赖于 web.xml 中的 security-constraint 声明,且页面针对部署上下文 root 解析。
keepDOMAssertion
此属性应设置为 true,以便适配器将断言的 DOM 表示存储在与请求关联的 SamlPrincipal 内部的原始表单中。可以使用主体中的 getAsertionDocument 来检索 断言文档。这在重新显示已签名的断言时特别有用。返回的文档是由 Red Hat Single Sign-On 服务器接收的 SAML 响应生成解析。此设置是 OPTIONAL,其默认值为 false (文档没有在主体中保存)。

3.1.1.2. 服务提供商键和密钥元素

如果 IdP 要求客户端应用程序(或 SP)签署其所有请求,如果 IdP 将加密断言,则必须定义用于执行此操作的密钥。对于客户端签名文档,您必须定义用于签署文档的私钥和公钥或证书。要进行加密,您只需要定义用于解密它的私钥。

可以通过两种方式描述您的键:它们可以存储在 Java KeyStore 中,或者直接以 PEM 格式在 keycloak-saml.xml 中复制/粘贴密钥。

        <Keys>
            <Key signing="true" >
               ...
            </Key>
        </Keys>
Copy to Clipboard Toggle word wrap

Key 元素有两个可选属性 签名和加密 。当设置为 true 时,这些会告知适配器将什么密钥用于什么。如果这两个属性都设为 true,那么密钥将同时用于签名文档和解密加密断言。您必须至少将其中一个属性设置为 true。

3.1.1.2.1. keystore 元素

Key 元素中,您可以从 Java 密钥存储加载您的密钥和证书。这在 KeyStore 元素中声明。

        <Keys>
            <Key signing="true" >
                <KeyStore resource="/WEB-INF/keystore.jks" password="store123">
                    <PrivateKey alias="myPrivate" password="test123"/>
                    <Certificate alias="myCertAlias"/>
                </KeyStore>
            </Key>
        </Keys>
Copy to Clipboard Toggle word wrap

以下是使用 KeyStore 元素定义的 XML 配置属性。

file
密钥存储的文件路径。此选项是 选项。必须设置 file 或 resource 属性。
resource
KeyStore 的 WAR 资源路径。这是对 ServletContext.getResourceAsStream ()的方法调用时使用的路径。此选项是 选项。必须设置 file 或 resource 属性。
password
KeyStore 的密码。此选项是 REQUIRED

如果您要定义 SP 将用来记录文档的密钥,还必须在 Java KeyStore 中指定对私钥和证书的引用。上例中的 PrivateKey 和证书元素定义了一个指向密钥存储内密钥或证书的别名。 密钥存储需要额外的密码才能访问私钥。在 PrivateKey 元素中,您必须在 password 属性中定义此密码。

3.1.1.2.2. 密钥 PEMS

Key 元素中,您直接使用 PrivateKeyPemPublicKeyPemCertificatePem 的子元素声明您的密钥和证书。这些元素中包含的值必须符合 PEM 密钥格式。如果您使用 openssl 或类似的命令行工具生成密钥,您通常会使用这个选项。

<Keys>
   <Key signing="true">
      <PrivateKeyPem>
         2341251234AB31234==231BB998311222423522334
      </PrivateKeyPem>
      <CertificatePem>
         211111341251234AB31234==231BB998311222423522334
      </CertificatePem>
   </Key>
</Keys>
Copy to Clipboard Toggle word wrap

3.1.1.3. SP PrincipalNameMapping element

这个元素是可选的。在创建从 HttpServletRequest.getUserPrincipal () 等方法中获取的 Java Principal 对象时,您可以定义 Principal.getName () 方法返回的名称。

<SP ...>
  <PrincipalNameMapping policy="FROM_NAME_ID"/>
</SP>

<SP ...>
  <PrincipalNameMapping policy="FROM_ATTRIBUTE" attribute="email" />
</SP>
Copy to Clipboard Toggle word wrap

policy 属性定义用于填充此值的策略。这个属性的可能值有:

FROM_NAME_ID
这个策略只使用任何 SAML 主题值。这是默认设置
FROM_ATTRIBUTE
这将从从服务器接收的 SAML 断言中声明的其中一个属性中提取值。您需要指定在属性 XML 属性中使用的 SAML 断言属性的名称。

3.1.1.4. RoleIdentifiers 元素

RoleIdentifiers 元素定义从用户接收的断言内接收的 SAML 属性应该用作用户的 Jakarta EE 安全上下文中的角色标识符。

<RoleIdentifiers>
     <Attribute name="Role"/>
     <Attribute name="member"/>
     <Attribute name="memberOf"/>
</RoleIdentifiers>
Copy to Clipboard Toggle word wrap

默认情况下 ,角色 属性值转换为 Jakarta EE 角色。有些 IdP 使用 membermemberOf 属性断言来发送角色。您可以定义一个或多个属性元素,以指定必须将哪些 SAML 属性转换为角色。

3.1.1.5. RoleMappingsProvider 元素

RoleMappingsProvider 是一个可选元素,它可用于规范 org.keycloak.adapters.saml.RoleMappingsProvider SPI 实施,供 SAML 适配器使用。

当 Red Hat Single Sign-On 用作 IDP 时,可以使用角色映射程序中的构建来映射任何角色,然后再将它们添加到 SAML 断言。但是,可以使用 SAML 适配器将 SAML 请求发送到第三方 IDP,在这种情况下,可能需要将从断言提取的角色映射到 SP 需要的不同角色。RoleMappingsProvider SPI 允许配置可用于执行必要的映射的可插拔角色映射。

供应商的配置类似如下:

...
<RoleIdentifiers>
    ...
</RoleIdentifiers>
<RoleMappingsProvider id="properties-based-role-mapper">
    <Property name="properties.resource.location" value="/WEB-INF/role-mappings.properties"/>
</RoleMappingsProvider>
<IDP>
    ...
</IDP>
Copy to Clipboard Toggle word wrap

id 属性标识要使用哪个安装供应商。Property 子元素可以多次使用来为提供程序指定配置属性。

3.1.1.5.1. 基于属性的角色映射供应商

红帽单点登录包括 RoleMappingsProvider 实施,它利用属性文件执行 角色映射。此提供程序由 id properties-based-role-mapper 标识,它由 org.keycloak.adapters.saml.PropertiesBasedRoleMapper 类实施。

此提供程序依赖于两个配置属性,可用于指定要使用的 属性 文件的位置。首先,它利用配置的值来检查 properties.file.location 属性是否已指定,以 在文件系统中 定位属性文件。如果所配置的文件不在,则提供程序将引发 RuntimeException。以下代码片段演示了使用 properties.file.configuration 选项从文件系统中的 /opt/mappers/ 目录中加载 roles.properties 文件的供应商示例:

    <RoleMappingsProvider id="properties-based-role-mapper">
        <Property name="properties.file.location" value="/opt/mappers/roles.properties"/>
    </RoleMappingsProvider>
Copy to Clipboard Toggle word wrap

如果尚未设置 properties.file.location 配置,提供程序会检查 properties.resource.location 属性,使用配置的值从 WAR 资源加载属性文件。如果这个配置属性也不存在,则提供程序会尝试默认尝试从 /WEB-INF/role-mappings.properties 中载入该文件。未能从资源加载文件将导致提供程序引发 RuntimeException。以下代码片段演示了使用 properties.resource.location 从应用程序的 /WEB-INF/conf/ 目录中加载 roles.properties 文件的示例:

    <RoleMappingsProvider id="properties-based-role-mapper">
        <Property name="properties.resource.location" value="/WEB-INF/conf/roles.properties"/>
    </RoleMappingsProvider>
Copy to Clipboard Toggle word wrap

属性 文件可以包含 roles 和 principals 作为键,以及用逗号分开的零个或多个角色列表,作为值。调用时,实施会迭代从断言中提取的角色集合,并在存在映射时对每个角色进行检查。如果角色映射到空角色,它将被丢弃。如果映射到一个或多个不同角色的集合,则会在结果集中设置这些角色。如果没有为角色找到映射,它将包含在结果集合中。

处理角色后,实施会检查从断言中提取的主体是否包含条目 属性文件。如果存在主体的映射,作为值列出的任何角色都会添加到结果集中。这允许将额外角色分配给主体。

例如,我们假设供应商已配置有以下属性文件:

roleA=roleX,roleY
roleB=

kc_user=roleZ
Copy to Clipboard Toggle word wrap

如果从具有 roleAroleBroleC 的断言器提取了主体的 kc_user,则分配给主体的最终角色集为 roleCroleXroleYroleZ,因为 roleA 都被映射到 roleXroleYroleB 映射到空角色(因此被丢弃),roleC 会被原样使用,最后将一个额外的角色添加到 kc_user 主体(roleZ)。

注: 要在角色名称中使用空格进行映射,请使用 unicode 替换空间。例如,传入 'role A' 将显示为:

role\u0020A=roleX,roleY
Copy to Clipboard Toggle word wrap
3.1.1.5.2. 添加您自己的角色映射供应商

要添加自定义角色映射提供程序,只需实施 org.keycloak.adapters.saml.RoleMappingsProvider SPI。如需了解更多详细信息,请参阅 服务器开发人员指南中的 SAML 角色映射 SPI 部分。

3.1.1.6. IDP 元素

IDP 元素中的所有内容都描述了 SP (身份验证服务器)与 SP 通信的身份提供商(身份验证服务器)的设置。

<IDP entityID="idp"
     signaturesRequired="true"
     signatureAlgorithm="RSA_SHA1"
     signatureCanonicalizationMethod="http://www.w3.org/2001/10/xml-exc-c14n#">
...
</IDP>
Copy to Clipboard Toggle word wrap

以下是您可以在 IDP 元素声明中指定的属性配置选项。

entityID
这是 IDP 的签发者 ID。此设置是 REQUIRED
signaturesRequired
如果设置为 true,客户端适配器会将它发送的每个文档签名给 IDP。另外,客户端还希望 IDP 发送的所有文档都会被签名。此切换为所有请求和响应类型设置默认值,但您稍后您对此具有一些细致的控制。此设置包括 选项,默认为 false
signatureAlgorithm
这是 IDP 要求使用签名文档的签名算法。允许的值有: RSA_SHA1RSA_SHA256RSA_SHA512DSA_SHA1。此设置是 OPTIONAL,默认为 RSA_SHA256
signatureCanonicalizationMethod
这是 IDP 需要使用签名文档的签名规范方法。此设置选项为 选项。默认值为 http://www.w3.org/2001/10/xml-exc-c14n#,它适用于大多数 IDP。
metadataUrl
用于检索 IDP 元数据的 URL 目前仅用于定期获取签名和加密密钥,允许在 IDP 上无手动更改的情况下对这些密钥进行循环。

3.1.1.7. IDP AllowedClockSkew 子元素

AllowedClockSkew 可选子元素定义 IDP 和 SP 之间允许的时钟偏移。默认值为 0。

<AllowedClockSkew unit="MILLISECONDS">3500</AllowedClockSkew>
Copy to Clipboard Toggle word wrap
unit
可以定义附加到这个元素的值的时间单元。允许的值是 MICROSECONDS、MILLISECONDS、MINUTES、NANOSECONDS 和 SECONDS。这是 选项。默认值为 SECONDS

3.1.1.8. IDP SingleSignOnService 子元素

SingleSignOnService 子元素定义了 IDP 的登录 SAML 端点。客户端适配器将请求发送到通过这个元素中的设置进行格式化的 IDP。

<SingleSignOnService signRequest="true"
                     validateResponseSignature="true"
                     requestBinding="post"
                     bindingUrl="url"/>
Copy to Clipboard Toggle word wrap

以下是您可以在这个元素上定义的配置属性:

signRequest
客户端是否应该为 authn 请求签名?此设置选项为 选项。默认为 IDP 签名必需 元素值的任何 IDP。
validateResponseSignature
客户端是否应该为 IDP 签署从 auhtn 请求发回的断言响应文档?此设置 选项选项.默认为 IDP 签名必需 元素值的任何 IDP。
requestBinding
这是用于与 IDP 通信的 SAML 绑定类型。此设置选项为 选项。默认值为 POST,但您也可以将其设置为 REDIRECT
responseBinding
SAML 允许客户端请求希望 authn 响应的绑定类型。这个值可以是 POSTREDIRECT。此设置选项为 选项。默认为客户端不会请求特定的绑定类型响应。
assertionConsumerServiceUrl
IDP 登录服务(ACS)的断言使用者服务(ACS)的 URL 应向其中发送响应。此设置选项为 选项。默认情况下取消设置,它依赖于 IdP 中的配置。设置后,它必须以 /saml 结尾,例如 http://sp.domain.com/my/endpoint/for/saml。此属性的值在 SAML AuthnRequest 消息的 AssertionConsumerServiceURL 属性中发送。此属性通常附带 responseBinding 属性。
bindingUrl
这是客户端将发送请求的 IDP 登录服务的 URL。此设置是 REQUIRED

3.1.1.9. IDP SingleLogoutService 子元素

SingleLogoutService 子元素定义了 IDP 的 SAML 端点。客户端适配器将在需要注销时,通过这个元素中的设置将请求发送到 IDP。

<SingleLogoutService validateRequestSignature="true"
                     validateResponseSignature="true"
                     signRequest="true"
                     signResponse="true"
                     requestBinding="redirect"
                     responseBinding="post"
                     postBindingUrl="posturl"
                     redirectBindingUrl="redirecturl">
Copy to Clipboard Toggle word wrap
signRequest
客户端是否应该注销向 IDP 发出的请求?此设置选项为 选项。默认为 IDP 签名必需 元素值的任何 IDP。
signResponse
客户端是否应该注销它发送到 IDP 请求的响应?此设置选项为 选项。默认为 IDP 签名必需 元素值的任何 IDP。
validateRequestSignature
客户端是否应该从 IDP 中记录已签名的请求文档?此设置选项为 选项。默认为 IDP 签名必需 元素值的任何 IDP。
validateResponseSignature
客户端是否期望从 IDP 进行签名的注销响应文档?此设置选项为 选项。默认为 IDP 签名必需 元素值的任何 IDP。
requestBinding
这是用于向 IDP 发送 SAML 请求的 SAML 绑定类型。此设置选项为 选项。默认值为 POST,但您也可以将其设置为 REDIRECT。
responseBinding
这是用于向 IDP 发送 SAML 响应的 SAML 绑定类型。这个值可以是 POSTREDIRECT。此设置选项为 选项。默认值为 POST,但您也可以将其设置为 REDIRECT
postBindingUrl
这是使用 POST 绑定时 IDP 注销服务的 URL。如果使用 POST 绑定,则此设置是 REQUIRED
redirectBindingUrl
这是使用 REDIRECT 绑定时 IDP 注销服务的 URL。如果使用 REDIRECT 绑定,则此设置是 REQUIRED

3.1.1.10. IDP 键子元素

IDP 的 Keys 子元素仅用于定义用来验证 IDP 签名的证书或公钥。它的定义方式与 SP 的 Keys 元素 相同。但是,您只需要定义一个证书或公钥引用。请注意,如果 Red Hat Single Sign-On server 和 adapter 都实现了 IDP 和 SP,则不需要指定签名验证的密钥,请参阅以下。

可以将 SP 配置为从公布的证书自动获取 IDP 签名验证的公钥,这同时由 Red Hat Single Sign-On 实施 SP 和 IDP。这可以通过删除 Keys 子元素中签名验证密钥的所有声明来完成。如果 Keys 子元素随后保留为空,则可以完全省略。然后,这些密钥由 SP 从 SAML 描述符获得,该位置来自 IDP SingleSignOnService 子元素 中指定的 SAML 端点 URL。用于 SAML 描述符检索的 HTTP 客户端设置通常不需要额外的配置,但可以在 IDP HttpClient 子元素 中配置。

还可以指定多个密钥进行签名验证。这可以通过在 Keys 子元素中声明将 签名 属性设置为 true 的多个 Key 元素来完成。当 IDP 签名密钥轮转时,这很有用:当新的 SAML 协议消息和断言使用新密钥签名时,通常会有一个过渡周期,但应该仍然可以接受之前密钥签名的。

无法将 Red Hat Single Sign-On 配置为自动获取签名验证的密钥,并定义额外的静态签名验证密钥。

       <IDP entityID="idp">
            ...
            <Keys>
                <Key signing="true">
                    <KeyStore resource="/WEB-INF/keystore.jks" password="store123">
                        <Certificate alias="demo"/>
                    </KeyStore>
                </Key>
            </Keys>
        </IDP>
Copy to Clipboard Toggle word wrap

3.1.1.11. IDP HttpClient 子元素

HttpClient 可选子元素定义了用于自动获取证书的 HTTP 客户端的属性,包含通过 IDP 的 SAML 描述符 在启用 时通过 IDP 进行签名验证的公钥。

<HttpClient connectionPoolSize="10"
            disableTrustManager="false"
            allowAnyHostname="false"
            clientKeystore="classpath:keystore.jks"
            clientKeystorePassword="pwd"
            truststore="classpath:truststore.jks"
            truststorePassword="pwd"
            proxyUrl="http://proxy/"
            socketTimeout="5000"
            connectionTimeout="6000"
            connectionTtl="500" />
Copy to Clipboard Toggle word wrap
connectionPoolSize
此配置选项定义了与 Red Hat Single Sign-On 服务器的连接数量。这是 选项。默认值为 10
disableTrustManager
如果 Red Hat Single Sign-On 服务器需要 HTTPS,且这个配置选项被设置为 true,则不必指定信任存储。此设置仅应在开发期间使用,且不应 在生产环境中使用,因为它将禁用 SSL 证书的验证。这是 选项。默认值为 false
allowAnyHostname
如果 Red Hat Single Sign-On 服务器需要 HTTPS,且这个配置选项被设置为 true,Red Hat Single Sign-On 服务器的证书通过 truststore 验证,但没有进行主机名验证。此设置仅应在开发期间使用,且不应在生产环境中使用,因为它部分禁用 SSL 证书的验证。在测试环境中,此集合可能有用。这是 选项。默认值为 false
truststore
该值是 truststore 文件的文件路径。如果您为带有 classpath 的路径添加前缀:,则信任存储将从部署的类路径中获取。用于向 Red Hat Single Sign-On 服务器的外向 HTTPS 通信。进行 HTTPS 请求的客户端需要一种方式来验证所讨论的服务器主机。这是信任者的作用。密钥存储包含一个或多个可信主机证书或证书颁发机构。您可以通过提取红帽单点登录服务器 SSL 密钥存储的公共证书来创建此信任存储。这是 REQUIRED,除非 禁用TrustManagertrue
truststorePassword
truststore 的密码。如果设置了 truststore,则 REQUIRED 为 REQUIRED,并且信任存储需要密码。
clientKeystore
这是密钥存储文件的文件路径。此密钥存储包含在适配器向 Red Hat Single Sign-On 服务器发出 HTTPS 请求时的双向 SSL 客户端证书。这是 选项
clientKeystorePassword
客户端密钥存储的密码和客户端的密钥。如果设置了 clientKeystore,则这是 REQUIRED
proxyUrl
用于 HTTP 连接的 HTTP 代理的 URL。这是 选项
socketTimeout
以毫秒为单位建立连接后等待数据的套接字超时。两个数据数据包间不活跃的时间的最大时间。超时值为零被解释为无限超时。负值解析为未定义(如果适用,则默认为系统)。默认值为 -1。这是 选项
connectionTimeout
以毫秒为单位建立与远程主机建立连接的超时时间。超时值为零被解释为无限超时。负值解析为未定义(如果适用,则默认为系统)。默认值为 -1。这是 选项
connectionTtl
以毫秒为单位的客户端连接时间。值小于或等于零。默认值为 -1。这是 选项

3.1.2. JBoss EAP 适配器

为了保护在 JBoss EAP 上部署的 WAR 应用,您必须安装并配置 Red Hat Single Sign-On SAML Adapter 子系统。

然后,在 web.xml 中提供 keycloak 配置 /WEB-INF/keycloak-saml.xml 文件,并将 auth-method 更改为 KEYCLOAK-SAML。

您可以使用 ZIP 文件或 RPM 安装适配器。

3.1.3. 从 ZIP 文件安装适配器

每个适配器都是 Red Hat Single Sign-On 下载站点的独立下载。

流程

  1. Downloads 站点安装适用于您的应用程序服务器的适配器。

    • 在 JBoss EAP 7.x 上安装:

      $ cd $EAP_HOME
      $ unzip rh-sso-saml-eap7-adapter.zip
      Copy to Clipboard Toggle word wrap
    • 在 JBoss EAP 6.x 上安装:

      $ cd $EAP_HOME
      $ unzip rh-sso-saml-eap6-adapter.zip
      Copy to Clipboard Toggle word wrap

      这些 ZIP 文件在您的 JBoss EAP 分发中创建了特定于 JBoss EAP SAML 适配器的新 JBoss 模块。

  2. 使用 CLI 脚本在应用服务器配置中启用 Red Hat Single Sign-On SAML 子系统: domain.xmlstandalone.xml

    启动服务器并运行应用到您的应用程序服务器的脚本。

    • 对 JBoss EAP 7.1 或更高版本使用此命令

      $ cd $JBOSS_HOME
      $ ./bin/jboss-cli.sh -c --file=bin/adapter-elytron-install-saml.cli
      Copy to Clipboard Toggle word wrap
    • 将此命令用于 JBoss EAP 7.0 和 EAP 6.4

      $ cd $JBOSS_HOME
      $ ./bin/boss-cli.sh -c --file=bin/adapter-install-saml.cli
      Copy to Clipboard Toggle word wrap
      注意

      也可以在 JBoss EAP 7.1 或更高版本中使用旧的非Elytron 适配器,这意味着您可以在这些版本中使用 adapter-install-saml.cli。但是,我们建议使用较新的 Elytron 适配器。

      该脚本将添加扩展、子系统和可选 security-domain,如下所述。

<server xmlns="urn:jboss:domain:1.4">

    <extensions>
        <extension module="org.keycloak.keycloak-saml-adapter-subsystem"/>
          ...
    </extensions>

    <profile>
        <subsystem xmlns="urn:jboss:domain:keycloak-saml:1.1"/>
         ...
    </profile>
Copy to Clipboard Toggle word wrap

当您需要在安全 Web 层中创建的安全上下文传播到您正在调用的 EJB (其他 EE 组件)时创建的安全上下文时,应结合使用 keycloak 安全域。否则,这个配置是可选的。

<server xmlns="urn:jboss:domain:1.4">
 <subsystem xmlns="urn:jboss:domain:security:1.2">
    <security-domains>
...
      <security-domain name="keycloak">
         <authentication>
           <login-module code="org.keycloak.adapters.jboss.KeycloakLoginModule"
                         flag="required"/>
          </authentication>
      </security-domain>
    </security-domains>
Copy to Clipboard Toggle word wrap

安全上下文自动传播到 EJB 层。

3.1.3.1. JBoss SSO

JBoss EAP 内置了对部署到相同 JBoss EAP 实例的 Web 应用的单点登录支持。使用 Red Hat Single Sign-On 时不应该启用此功能。

3.1.3.2. 为 JSESSIONID Cookie 设置 SameSite 值

浏览器计划将 Cookie 的 SameSite 属性的默认值设置为 Lax。此设置表示,只有在请求来自同一域中时,才会将 Cookie 发送到应用程序。此行为可能会影响 SAML POST 绑定,这些绑定可能无法正常工作。要保留 SAML 适配器的完整功能,我们建议将容器创建的 JSESSIONID cookie 的 SameSite 值设置为 None。这样做可能会导致为容器的每个请求重置 Red Hat Single Sign-On 的会话。

注意

为了避免将 SameSite 属性设置为 None,请考虑切换到 REDIRECT 绑定(如果可以接受),或者不需要进行这个临时解决方案的 OIDC 协议。

要将 Wildfly/EAP 中的 JSESSIONID cookie 的 SameSite 值设置为 None,请将包含以下内容的文件 undertow-handlers.conf 添加到您的应用程序的 WEB-INF 目录:

samesite-cookie(mode=None, cookie-pattern=JSESSIONID)
Copy to Clipboard Toggle word wrap

对此配置的支持在 19.1.0 版本 19.1.0 的 Wildfly 中提供。

3.1.4. 从 RPM 安装 JBoss EAP 7 适配器

注意

在 Red Hat Enterprise Linux 7 中,术语频道被使用术语仓库替代。在这些说明中,仅使用术语存储库。

前提条件

您必须订阅 JBoss EAP 7 存储库,然后才能从 RPM 安装 EAP 7 适配器。

  • 使用 Red Hat Subscription Manager 确保您的 Red Hat Enterprise Linux 系统已注册到您的帐户。如需更多信息,请参阅 红帽订阅管理文档
  • 如果您已订阅了另一个 JBoss EAP 存储库,必须先退订该存储库。

    对于 Red Hat Enterprise Linux 6,7:使用 Red Hat Subscription Manager,使用以下命令订阅 JBoss EAP 7.4 存储库。根据您的 Red Hat Enterprise Linux 版本,将 <RHEL_VERSION> 替换为 6 或 7。

    $ sudo subscription-manager repos --enable=jb-eap-7-for-rhel-<RHEL_VERSION>-server-rpms
    Copy to Clipboard Toggle word wrap

    对于 Red Hat Enterprise Linux 8:使用 Red Hat Subscription Manager,使用以下命令订阅 JBoss EAP 7.4 存储库:

    $ sudo subscription-manager repos --enable=jb-eap-7.4-for-rhel-8-x86_64-rpms --enable=rhel-8-for-x86_64-baseos-rpms --enable=rhel-8-for-x86_64-appstream-rpms
    Copy to Clipboard Toggle word wrap

流程

  1. 根据您的 Red Hat Enterprise Linux 版本,为 SAML 安装 EAP 7 适配器。

    • 在 Red Hat Linux 7 上安装:

      $ sudo yum install eap7-keycloak-saml-adapter-sso7_5
      Copy to Clipboard Toggle word wrap
    • 在 Red Hat Enterprise Linux 8 中安装:

      $ sudo dnf install eap7-keycloak-adapter-sso7_5
      Copy to Clipboard Toggle word wrap
      注意

      RPM 安装的默认 EAP_HOME 路径为 /opt/rh/eap7/root/usr/share/wildfly。

  2. 为 SAML 模块运行安装脚本:

    $ $EAP_HOME/bin/jboss-cli.sh -c --file=$EAP_HOME/bin/adapter-install-saml.cli
    Copy to Clipboard Toggle word wrap

您的安装已完成。

3.1.5. 从 RPM 安装 JBoss EAP 6 适配器

注意

在 Red Hat Enterprise Linux 7 中,术语频道被使用术语仓库替代。在这些说明中,仅使用术语存储库。

前提条件

您必须订阅 JBoss EAP 6 存储库,然后才能从 RPM 安装 EAP 6 适配器。

  • 使用 Red Hat Subscription Manager 确保您的 Red Hat Enterprise Linux 系统已注册到您的帐户。如需更多信息,请参阅 红帽订阅管理文档
  • 如果您已订阅了另一个 JBoss EAP 存储库,必须先退订该存储库。
  • 使用以下命令,使用红帽订阅管理器订阅 JBoss EAP 6 存储库:根据您的 Red Hat Enterprise Linux 版本,将 <RHEL_VERSION> 替换为 6 或 7。

    $ sudo subscription-manager repos --enable=jb-eap-6-for-rhel-<RHEL_VERSION>-server-rpms
    Copy to Clipboard Toggle word wrap

流程

  1. 使用以下命令为 SAML 安装 EAP 6 适配器:

    $ sudo yum install keycloak-saml-adapter-sso7_5-eap6
    Copy to Clipboard Toggle word wrap
    注意

    RPM 安装的默认 EAP_HOME 路径为 /opt/rh/eap6/root/usr/share/wildfly。

  2. 为 SAML 模块运行安装脚本:

    $ $EAP_HOME/bin/jboss-cli.sh -c --file=$EAP_HOME/bin/adapter-install-saml.cli
    Copy to Clipboard Toggle word wrap

您的安装已完成。

3.1.5.1. 保护 WAR

这部分论述了如何通过在 WAR 软件包中添加配置和编辑文件直接保护 WAR 的安全。

您必须首先在 WAR 的 WEB-INF 目录中创建 keycloak-saml.xml 适配器配置文件。此配置文件的格式在 General Adapter Config 部分中描述。

接下来,您必须在 web.xml 中将 auth-method 设置为 KEYCLOAK-SAML。您还必须使用标准 servlet 安全性来指定 URL 的角色限制。以下是 web.xml 文件示例:

<web-app xmlns="http://java.sun.com/xml/ns/javaee"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
      version="3.0">

	<module-name>customer-portal</module-name>

    <security-constraint>
        <web-resource-collection>
            <web-resource-name>Admins</web-resource-name>
            <url-pattern>/admin/*</url-pattern>
        </web-resource-collection>
        <auth-constraint>
            <role-name>admin</role-name>
        </auth-constraint>
        <user-data-constraint>
            <transport-guarantee>CONFIDENTIAL</transport-guarantee>
        </user-data-constraint>
    </security-constraint>
    <security-constraint>
        <web-resource-collection>
            <web-resource-name>Customers</web-resource-name>
            <url-pattern>/customers/*</url-pattern>
        </web-resource-collection>
        <auth-constraint>
            <role-name>user</role-name>
        </auth-constraint>
        <user-data-constraint>
            <transport-guarantee>CONFIDENTIAL</transport-guarantee>
        </user-data-constraint>
    </security-constraint>

    <login-config>
        <auth-method>KEYCLOAK-SAML</auth-method>
        <realm-name>this is ignored currently</realm-name>
    </login-config>

    <security-role>
        <role-name>admin</role-name>
    </security-role>
    <security-role>
        <role-name>user</role-name>
    </security-role>
</web-app>
Copy to Clipboard Toggle word wrap

auth-method 设置外的所有标准 servlet 设置。

3.1.5.2. 使用红帽单点登录 SAML 子系统保护 WAR

您不必打开 WAR 以通过 Red Hat Single Sign-On 对其进行保护。另外,您还可以通过 Red Hat Single Sign-On SAML Adapter 子系统从外部保护它。虽然您不必将 KEYCLOAK-SAML 指定为 auth-method,但在 web.xml 中定义 security-constraints。但是,您不必创建一个 WEB-INF/keycloak-saml.xml 文件。此元数据在服务器的 domain.xmlstandalone.xml 子系统配置部分中定义。

<extensions>
  <extension module="org.keycloak.keycloak-saml-adapter-subsystem"/>
</extensions>

<profile>
  <subsystem xmlns="urn:jboss:domain:keycloak-saml:1.1">
    <secure-deployment name="WAR MODULE NAME.war">
      <SP entityID="APPLICATION URL">
        ...
      </SP>
    </secure-deployment>
  </subsystem>
</profile>
Copy to Clipboard Toggle word wrap

secure-deployment name 属性标识您要保护的 WAR。它的值是 web.xml 中定义的 module-name,并附加 .war。其余的配置使用与 General Adapter Config 中定义的 keycloak-saml.xml 配置相同的 XML 语法。

配置示例:

<subsystem xmlns="urn:jboss:domain:keycloak-saml:1.1">
  <secure-deployment name="saml-post-encryption.war">
    <SP entityID="http://localhost:8080/sales-post-enc/"
        sslPolicy="EXTERNAL"
        nameIDPolicyFormat="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified"
        logoutPage="/logout.jsp"
        forceAuthentication="false">
      <Keys>
        <Key signing="true" encryption="true">
          <KeyStore resource="/WEB-INF/keystore.jks" password="store123">
            <PrivateKey alias="http://localhost:8080/sales-post-enc/" password="test123"/>
            <Certificate alias="http://localhost:8080/sales-post-enc/"/>
          </KeyStore>
        </Key>
      </Keys>
      <PrincipalNameMapping policy="FROM_NAME_ID"/>
      <RoleIdentifiers>
        <Attribute name="Role"/>
      </RoleIdentifiers>
      <IDP entityID="idp">
        <SingleSignOnService signRequest="true"
            validateResponseSignature="true"
            requestBinding="POST"
            bindingUrl="http://localhost:8080/auth/realms/saml-demo/protocol/saml"/>

        <SingleLogoutService
            validateRequestSignature="true"
            validateResponseSignature="true"
            signRequest="true"
            signResponse="true"
            requestBinding="POST"
            responseBinding="POST"
            postBindingUrl="http://localhost:8080/auth/realms/saml-demo/protocol/saml"
            redirectBindingUrl="http://localhost:8080/auth/realms/saml-demo/protocol/saml"/>
        <Keys>
          <Key signing="true" >
            <KeyStore resource="/WEB-INF/keystore.jks" password="store123">
              <Certificate alias="saml-demo"/>
            </KeyStore>
          </Key>
        </Keys>
      </IDP>
    </SP>
   </secure-deployment>
</subsystem>
Copy to Clipboard Toggle word wrap

3.1.6. Java Servlet 过滤器适配器

如果您希望将 SAML 与没有该 servlet 平台的 Java servlet 应用程序一起使用,您可以选择使用 Red Hat Single Sign-On 的 servlet 过滤器适配器。这个适配器与其他适配器不同。您仍然必须指定 /WEB-INF/keycloak-saml.xml 文件,如 General Adapter Config 部分所定义,但您不会在 web.xml 中定义安全约束。而是使用 Red Hat Single Sign-On servlet 过滤器适配器定义一个过滤器映射来保护您要安全的 url 模式。

注意

Backchannel logout 的工作方式与标准适配器不同。它没有无效的 http 会话,而是将会话 ID 标记为已注销。只能根据会话 ID 对 http 会话进行任意无效。

警告

当使用 SAML 过滤器的集群应用程序时,Backchannel logout 当前无法正常工作。

<web-app xmlns="http://java.sun.com/xml/ns/javaee"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
      version="3.0">

	<module-name>customer-portal</module-name>

    <filter>
        <filter-name>Keycloak Filter</filter-name>
        <filter-class>org.keycloak.adapters.saml.servlet.SamlFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>Keycloak Filter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
</web-app>
Copy to Clipboard Toggle word wrap

Red Hat Single Sign-On 过滤器具有与其他适配器相同的配置参数,但您必须将其定义为过滤 initparams 而不是上下文参数。

如果您有不同的安全且不安全的 url 模式,可以定义多个过滤器映射。

警告

您必须有一个包含 /saml 的过滤器映射。此映射覆盖所有服务器回调。

使用 IdP 注册 SP 时,您必须注册 http[s]://hostname/{context-root}/saml 作为 Assert Consumer Service URL 和 Single Logout Service URL。

要使用此过滤器,请将此 maven 工件包括在您的 WAR poms 中:

<dependency>
   <groupId>org.keycloak</groupId>
   <artifactId>keycloak-saml-servlet-filter-adapter</artifactId>
   <version>15.0.8.redhat-00001</version>
</dependency>
Copy to Clipboard Toggle word wrap

要使用 Multi Tenancy the keycloak.config.resolver 参数,应该作为过滤器参数传递。

    <filter>
        <filter-name>Keycloak Filter</filter-name>
        <filter-class>org.keycloak.adapters.saml.servlet.SamlFilter</filter-class>
        <init-param>
            <param-name>keycloak.config.resolver</param-name>
            <param-value>example.SamlMultiTenantResolver</param-value>
        </init-param>
    </filter>
Copy to Clipboard Toggle word wrap

3.1.7. 使用身份提供程序注册

对于基于 servlet 的适配器,您注册了断言使用者服务 URL 和单个注销服务的端点必须是附加到 servlet 应用的基本 URL,即 https://example.com/contextPath/saml

3.1.8. 退出

您可以通过多种方法从 web 应用程序注销。对于 Jakarta EE servlet 容器,您可以调用 HttpServletRequest.logout ()。对于任何其他浏览器应用程序,您可以将浏览器指向具有安全约束的 Web 应用程序的任何 URL,并在查询参数 GLO (如 http://myapp?GLO=true )中传递。如果您的浏览器有 SSO 会话,这将会登出。

3.1.8.1. 在集群环境中注销

在内部,SAML 适配器在 SAML 会话索引、主体名称(已知)和 HTTP 会话 ID 之间存储映射。此映射可以在 JBoss 应用服务器系列中维护(WildFly 10/11,EAP 6/7,用于可分发的应用程序。作为前提条件,HTTP 会话需要在集群间发布(例如,应用程序在应用程序的 web.xml中被标记为 < distributable /> 标签)。

要启用这个功能,请在 /WEB_INF/web.xml 文件中添加以下部分:

对于 EAP 7,Wildic 10/11:

<context-param>
    <param-name>keycloak.sessionIdMapperUpdater.classes</param-name>
    <param-value>org.keycloak.adapters.saml.wildfly.infinispan.InfinispanSessionCacheIdMapperUpdater</param-value>
</context-param>
Copy to Clipboard Toggle word wrap

对于 EAP 6:

<context-param>
    <param-name>keycloak.sessionIdMapperUpdater.classes</param-name>
    <param-value>org.keycloak.adapters.saml.jbossweb.infinispan.InfinispanSessionCacheIdMapperUpdater</param-value>
</context-param>
Copy to Clipboard Toggle word wrap

如果部署的会话缓存名为 deployment-cache,则用于 SAML 映射的缓存将命名为 deployment-cache.ssoCache。缓存的名称可以被上下文参数 keycloak.sessionIdMapperUpdater.infinispan.cacheName 覆盖。包含缓存的缓存容器与包含部署会话缓存的缓存容器相同,但可以通过上下文参数 keycloak.sessionIdMapperUpdater.infinispan.containerName 覆盖。

默认情况下,SAML 映射缓存的配置将从会话缓存衍生而来。可以在服务器的缓存配置部分中手动覆盖配置,与其它缓存相同。

目前,为了提供可靠的服务,建议为 SAML 会话缓存使用复制缓存。使用分布式缓存可能会导致 SAML 注销请求进入没有访问 SAML 会话索引到 HTTP 会话映射的节点,从而导致注销失败。

3.1.8.2. 在跨站点场景中注销

跨站点方案仅适用于 WildFly 10 及更高版本,EAP 7 及更高版本。

处理跨越多个数据中心的会话需要特殊处理。请考虑以下场景:

  1. 登录请求在数据中心 1 中的集群内处理。
  2. 管理问题注销特定 SAML 会话的请求,即数据中心 2 中的请求登录。

数据中心 2 必须注销数据中心 1 中存在的所有会话(以及共享 HTTP 会话的所有其他数据中心)。

要涵盖这种情况,需要将 上述 SAML 会话缓存不仅需要在一个单个集群内复制,而在所有数据中心中(例如,通过独立的 Infinispan/JDG 服务器 )进行复制:

  1. 缓存必须添加到独立的 Infinispan/JDG 服务器中。
  2. 前面几项中的缓存必须添加为对应的 SAML 会话缓存的远程存储。

在部署期间发现远程存储后,会在 SAML 会话缓存中显示,并相应地更新本地 SAML 会话缓存。

3.1.9. 获取断言属性

成功 SAML 登录后,应用程序代码可能需要获取使用 SAML 断言传递的属性值。HttpServletRequest.getUserPrincipal () 返回一个 Principal 对象,您可以将其输入到名为 org.keycloak.adapters.saml.SamlPrincipal 的红帽单点登录特定类。此对象允许您查看原始断言,并有便利函数来查找属性值。

package org.keycloak.adapters.saml;

public class SamlPrincipal implements Serializable, Principal {
    /**
     * Get full saml assertion
     *
     * @return
     */
    public AssertionType getAssertion() {
       ...
    }

    /**
     * Get SAML subject sent in assertion
     *
     * @return
     */
    public String getSamlSubject() {
        ...
    }

    /**
     * Subject nameID format
     *
     * @return
     */
    public String getNameIDFormat() {
        ...
    }

    @Override
    public String getName() {
        ...
    }

    /**
     * Convenience function that gets Attribute value by attribute name
     *
     * @param name
     * @return
     */
    public List<String> getAttributes(String name) {
        ...

    }

    /**
     * Convenience function that gets Attribute value by attribute friendly name
     *
     * @param friendlyName
     * @return
     */
    public List<String> getFriendlyAttributes(String friendlyName) {
        ...
    }

    /**
     * Convenience function that gets first  value of an attribute by attribute name
     *
     * @param name
     * @return
     */
    public String getAttribute(String name) {
        ...
    }

    /**
     * Convenience function that gets first  value of an attribute by attribute name
     *
     *
     * @param friendlyName
     * @return
     */
    public String getFriendlyAttribute(String friendlyName) {
        ...
    }

    /**
     * Get set of all assertion attribute names
     *
     * @return
     */
    public Set<String> getAttributeNames() {
        ...
    }

    /**
     * Get set of all assertion friendly attribute names
     *
     * @return
     */
    public Set<String> getFriendlyNames() {
        ...
    }
}
Copy to Clipboard Toggle word wrap

3.1.10. 错误处理

Red Hat Single Sign-On 为基于 servlet 的客户端适配器有一些错误处理工具。在身份验证过程中遇到错误时,客户端适配器将调用 HttpServletResponse.sendError ()。您可以在 web.xml 文件中设置 错误页面,以处理错误,但您想要。客户端适配器可能会抛出 400、401、403 和 500 错误。

<error-page>
    <error-code>403</error-code>
    <location>/ErrorHandler</location>
</error-page>
Copy to Clipboard Toggle word wrap

客户端适配器还会设置您可以检索的 HttpServletRequest 属性。属性名称是 org.keycloak.adapters.spi.AuthenticationError。Typecast 这个对象为: org.keycloak.adapters.saml.SamlAuthenticationError。此类可以向您说明发生什么情况。如果没有设置此属性,则适配器不负责错误代码。

public class SamlAuthenticationError implements AuthenticationError {
    public static enum Reason {
        EXTRACTION_FAILURE,
        INVALID_SIGNATURE,
        ERROR_STATUS
    }

    public Reason getReason() {
        return reason;
    }
    public StatusResponseType getStatus() {
        return status;
    }
}
Copy to Clipboard Toggle word wrap

3.1.11. 故障排除

解决问题的方法是,在客户端适配器和 Red Hat Single Sign-On 服务器中为 SAML 启用调试。使用您的日志记录框架,将 org.keycloak.saml 软件包的日志级别设置为 DEBUG。完成此操作后,您可以查看正在发送到和从服务器发送的 SAML 请求和响应文档。

3.1.12. 多租户

SAML 为 密度提供与 OIDC 相同的功能,即单个目标应用程序(WAR)可以使用多个 Red Hat Single Sign-On 域进行保护。域可以位于同一红帽单点登录实例或不同的实例上。

为此,应用必须具有多个 keycloak-saml.xml 适配器配置文件。

虽然您可能有多个 WAR 实例,且不同的适配器配置文件部署到不同的上下文路径,但这可能会不方便,而且您可能还希望根据上下文路径以外的某些域进行选择。

Red Hat Single Sign-On 可以有自定义配置解析器,以便您可以为每个请求选择哪个适配器配置。在 SAML 中,配置只对登录处理非常感兴趣;一旦登录后,会话将进行身份验证,如果返回 keycloak-saml.xml 返回的 keycloak-saml.xml,则会话将不重要。因此,返回同一会话配置是达到的正确方法。

为此,可创建 org.keycloak.adapters.saml.SamlConfigResolver 的实现。以下示例使用 Host 标头来查找正确的配置并加载它以及应用程序的 Java 类路径中的关联元素:

package example;

import java.io.InputStream;
import org.keycloak.adapters.saml.SamlConfigResolver;
import org.keycloak.adapters.saml.SamlDeployment;
import org.keycloak.adapters.saml.config.parsers.DeploymentBuilder;
import org.keycloak.adapters.saml.config.parsers.ResourceLoader;
import org.keycloak.adapters.spi.HttpFacade;
import org.keycloak.saml.common.exceptions.ParsingException;

public class SamlMultiTenantResolver implements SamlConfigResolver {

    @Override
    public SamlDeployment resolve(HttpFacade.Request request) {
        String host = request.getHeader("Host");
        String realm = null;
        if (host.contains("tenant1")) {
            realm = "tenant1";
        } else if (host.contains("tenant2")) {
            realm = "tenant2";
        } else {
            throw new IllegalStateException("Not able to guess the keycloak-saml.xml to load");
        }

        InputStream is = getClass().getResourceAsStream("/" + realm + "-keycloak-saml.xml");
        if (is == null) {
            throw new IllegalStateException("Not able to find the file /" + realm + "-keycloak-saml.xml");
        }

        ResourceLoader loader = new ResourceLoader() {
            @Override
            public InputStream getResourceAsStream(String path) {
                return getClass().getResourceAsStream(path);
            }
        };

        try {
            return new DeploymentBuilder().build(is, loader);
        } catch (ParsingException e) {
            throw new IllegalStateException("Cannot load SAML deployment", e);
        }
    }
}
Copy to Clipboard Toggle word wrap

您还必须配置用于 web.xml 中的 keycloak.config.resolver context-param 的 SamlConfigResolver 实现:

<web-app>
    ...
    <context-param>
        <param-name>keycloak.config.resolver</param-name>
        <param-value>example.SamlMultiTenantResolver</param-value>
    </context-param>
</web-app>
Copy to Clipboard Toggle word wrap
Red Hat logoGithubredditYoutubeTwitter

学习

尝试、购买和销售

社区

关于红帽文档

通过我们的产品和服务,以及可以信赖的内容,帮助红帽用户创新并实现他们的目标。 了解我们当前的更新.

让开源更具包容性

红帽致力于替换我们的代码、文档和 Web 属性中存在问题的语言。欲了解更多详情,请参阅红帽博客.

關於紅帽

我们提供强化的解决方案,使企业能够更轻松地跨平台和环境(从核心数据中心到网络边缘)工作。

Theme

© 2026 Red Hat
返回顶部