SAML认证SSO配置

概述

Fess 支持使用SAML(安全断言标记语言)2.0进行单点登录(SSO)认证。 通过使用SAML认证,由IdP(身份提供者)认证的用户信息可以与Fess集成,结合基于角色的搜索功能,可以根据用户权限显示不同的搜索结果。

SAML认证的工作原理

在SAML认证中,Fess作为SP(服务提供者)运行,并与外部IdP协作进行认证。

  1. 用户访问Fess的SSO端点(/sso/

  2. Fess将认证请求重定向到IdP

  3. 用户在IdP进行认证

  4. IdP将SAML断言发送给Fess

  5. Fess验证断言并登录用户

Note

仅支持如上所述从Fess的SSO端点(/sso/)发起的SP发起(SP-Initiated)登录。 Fess会将每个SAML响应与自身发出的AuthnRequest的ID进行绑定校验, 因此从IdP门户(如Okta仪表板或Microsoft Entra ID的”我的应用”)上的磁贴发起的 IdP发起(IdP-Initiated,即未经请求的unsolicited)SSO没有可匹配的AuthnRequest,会被拒绝。 如果要在IdP侧放置磁贴,请将其链接指向Fess的/sso/端点。

请注意,在15.7中,若设置了tomcat.sameSiteCookies=none,IdP发起的登录会碰巧可用: Fess会将无法匹配的响应退回给IdP,而IdP会立即返回一个经过请求的断言。 15.8不再执行这种退回,因此IdP发起的登录无法使用。

有关基于角色的搜索集成,请参阅:doc:security-role

前提条件

在配置SAML认证之前,请验证以下前提条件:

  • 已安装Fess 15.8或更高版本

  • 有可用的SAML 2.0兼容IdP(身份提供者)

  • Fess可通过HTTPS访问(生产环境必需)

  • 您有权在IdP侧将Fess注册为SP

支持的IdP示例:

  • Microsoft Entra ID(Azure AD)

  • Okta

  • Google Workspace

  • Keycloak

  • OneLogin

  • 其他SAML 2.0兼容IdP

基本配置

启用SSO

要启用SAML认证,请在app/WEB-INF/conf/system.properties中添加以下设置:

sso.type=saml

Note

sso.type 及基本SAML设置(IdP信息、SP信息、用户属性映射)也可以从管理界面的”系统 > 全局”页面进行配置和更改。 在管理界面中更改的设置将保存到 system.properties 中,重启后也会保留。 但是,签名/加密等安全设置以及SP证书/私钥无法在管理界面中配置,因此请直接写入 system.properties

Note

saml.开头的设置仅从system.properties中读取。 通过JVM系统属性(如-Dsaml.security....-Dfess.saml.security....)指定不会被读取。 特别是saml.security.*saml.strictsaml.debug在管理界面中也没有对应项, 因此只能直接写入system.properties

SP(服务提供者)配置

要将Fess配置为SP,请指定SP基础URL。

属性 描述 默认值
saml.sp.base.url SP基础URL http://localhost:8080

Note

saml.sp.base.url 的默认值为 http://localhost:8080。 在测试环境以外,请务必设置从外部访问 Fess 时使用的URL(生产环境中使用HTTPS)。

此设置会自动配置以下端点:

  • Entity ID{saml.sp.base.url}/sso/metadata

  • ACS URL{saml.sp.base.url}/sso/

  • SLO URL{saml.sp.base.url}/sso/logout

示例:

saml.sp.base.url=https://fess.example.com

单独URL配置

通常情况下,设置 saml.sp.base.url 即可自动配置各端点URL,但如有需要,也可以使用以下属性明确指定各URL并进行覆盖。

属性 描述 默认值
saml.sp.entityid SP Entity ID {saml.sp.base.url}/sso/metadata
saml.sp.assertion_consumer_service.url 断言消费者服务URL {saml.sp.base.url}/sso/
saml.sp.single_logout_service.url 单点登出服务URL {saml.sp.base.url}/sso/logout

IdP(身份提供者)配置

配置从您的IdP获取的信息。

属性 描述 默认值
saml.idp.entityid IdP Entity ID (必需)
saml.idp.single_sign_on_service.url IdP SSO服务URL (必需)
saml.idp.x509cert IdP签名X.509证书(Base64编码,无换行) (必需)
saml.idp.single_logout_service.url IdP SLO服务URL (可选)

Note

对于saml.idp.x509cert,仅指定证书的Base64编码内容,单行无换行。 不要包含-----BEGIN CERTIFICATE----------END CERTIFICATE-----行。

获取SP元数据

启动Fess后,您可以从/sso/metadata端点获取XML格式的SP元数据。

https://fess.example.com/sso/metadata

将此元数据导入到您的IdP,或使用元数据内容在IdP侧手动注册SP。

Note

要获取元数据,您必须先完成基本SAML配置(sso.type=samlsaml.sp.base.url)并启动Fess。

IdP侧配置

在IdP侧将Fess注册为SP时,配置以下信息:

设置
ACS URL / Reply URL https://<Fess主机>/sso/
Entity ID / Audience URI https://<Fess主机>/sso/metadata
Name ID Format urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress(推荐)

从IdP获取的信息

从您的IdP配置界面或元数据获取以下信息,用于Fess配置:

  • IdP Entity ID:标识IdP的URI

  • SSO URL(HTTP-Redirect):单点登录端点URL

  • X.509证书:用于SAML断言签名验证的公钥证书

用户属性映射

您可以将从SAML断言获取的用户属性映射到Fess的组和角色。

组属性配置

属性 描述 默认值
saml.attribute.group.name 包含组信息的属性名 memberOf
saml.default.groups 默认组(逗号分隔) (无)

示例:

saml.attribute.group.name=groups
saml.default.groups=user

Note

Fess 直接使用断言中的组值,不会查询目录,也不会展开嵌套组(父组)。 因此,是否包含父组完全取决于IdP侧的声明配置。 这与通过Microsoft Graph API解析父组的 Microsoft Entra ID SSO配置 不同。

角色属性配置

属性 描述 默认值
saml.attribute.role.name 包含角色信息的属性名 (无)
saml.default.roles 默认角色(逗号分隔) (无)

示例:

saml.attribute.role.name=roles
saml.default.roles=viewer

Note

如果无法从IdP获取属性,将使用默认值。 使用基于角色的搜索时,请配置适当的组或角色。

Warning

设置saml.attribute.role.name后,IdP发送的属性值将直接成为 Fess 的角色。 由于fess_config.propertiesauthentication.admin.roles的默认值为admin, 角色属性中包含admin的用户将获得 Fess 的管理员权限。 请确认IdP侧可以控制角色属性的范围,必要时将authentication.admin.roles更改为其他名称。

属性名重复的 IdP

如果 IdP 将同一个属性名拆分到多个 <Attribute> 元素中发送,Fess会拒绝该断言,登录本身 随之失败。

Keycloak 默认发送这种形式的断言:除非启用其角色映射器和组映射器的 single 选项,否则每个值 都会输出为独立的 <Attribute> 元素,而每个 Keycloak 账户默认都带有多个领域角色。

有以下两种处理方式:

  • 在 IdP 侧将属性合并为单个元素(在 Keycloak 中启用映射器的 single 选项)

  • 在 Fess侧允许重复并合并其值

属性 描述 默认值
saml.security.allow_duplicated_attribute_name 允许同一属性名出现在多个元素中并合并其值 false

示例:

saml.security.allow_duplicated_attribute_name=true

安全配置

对于生产环境,建议启用以下安全设置。

Note

如果保留了不推荐的设置,在加载SAML设置时会向日志输出Insecure SAML settings: ...警告。

签名设置

属性 描述 默认值
saml.security.authnrequest_signed 对认证请求签名 false
saml.security.want_messages_signed 要求消息签名 false
saml.security.want_assertions_signed 要求断言签名 false
saml.security.logoutrequest_signed 对登出请求签名 false
saml.security.logoutresponse_signed 对登出响应签名 false
saml.security.reject_deprecated_alg 拒绝SHA-1等已弃用的签名算法 false

Warning

安全功能默认是禁用的。 对于生产环境,强烈建议至少设置saml.security.want_assertions_signed=true

Note

saml.security.reject_deprecated_algfalse时,使用SHA-1(rsa-sha1dsa-sha1) 签名的断言和消息同样会被接受。之所以默认不启用,是因为启用后会拒绝仍使用SHA-1签名的IdP。 请先确认IdP使用SHA-256或更强的算法签名,然后再设置saml.security.reject_deprecated_alg=true

Warning

配置单点登出(saml.idp.single_logout_service.url)时,请务必同时设置saml.security.want_messages_signed=true。 若保持为false,则会接受未签名的LogoutRequest,攻击者可诱导用户访问构造的URL,从而终止其已认证会话。 其影响是强制登出(拒绝服务),而不是账户接管。

加密设置

属性 描述 默认值
saml.security.want_assertions_encrypted 要求断言加密 false
saml.security.want_nameid_encrypted 要求NameID加密 false
saml.security.allowed_key_transport_algorithms 解密断言时接受的密钥传输算法(以逗号分隔的 URI) (空:接受所有算法)

Note

Fess 可以验证使用 XML Encryption 1.1 加密的响应。例如当前的 Keycloak 使用 http://www.w3.org/2009/xmlenc11#rsa-oaep 并在响应中包含 <xenc11:MGF> 元素, 在启用架构验证的情况下也能接受此类响应。早期版本会以 Invalid SAML Response. Not match the saml-schema-protocol-2.0.xsd 拒绝。 如果为此设置过 saml.security.want_xml_validation=false,请将其删除。

Note

配置 SP 私钥时,请同时设置 saml.security.allowed_key_transport_algorithms。 未设置时会接受所有密钥传输算法,包括旧的 http://www.w3.org/2001/04/xmlenc#rsa-1_5。 断言消费端点无需认证,且解密在响应验证之前执行,因此未经认证的调用方可以让 SP 私钥 解密其选择的密文。处于这种状态时,Fess 会在启动时的 Insecure SAML settings 一行中输出 key_transport_algorithms_not_restricted。请将其限制为 IdP 实际使用的算法:

saml.security.allowed_key_transport_algorithms=http://www.w3.org/2009/xmlenc11#rsa-oaep

SP证书与私钥配置

当SP对认证请求或登出消息进行签名时(例如 saml.security.authnrequest_signed),或请求对断言或NameID进行加密时(例如 saml.security.want_assertions_encrypted),需要配置SP的私钥和X.509证书。

属性 描述 默认值
saml.sp.x509cert SP的X.509证书(Base64编码,无换行) (空)
saml.sp.privatekey SP的私钥(Base64编码,无换行) (空)

Note

对于 saml.sp.x509certsaml.sp.privatekey,与 saml.idp.x509cert 相同,请将Base64编码的内容以单行无换行的形式指定(不包含 -----BEGIN ...----------END ...----- 行)。 启用签名/加密时,还需要在IdP侧注册SP证书。SP证书将包含在 /sso/metadata 的SP元数据中进行公开。

其他安全设置

属性 描述 默认值
saml.strict 严格模式(执行严格验证) true
saml.security.want_xml_validation 验证消息的XML模式 true
saml.security.signature_algorithm 签名算法 http://www.w3.org/2001/04/xmldsig-more#rsa-sha256
saml.security.requested_authncontext 请求的认证上下文 urn:oasis:names:tc:SAML:2.0:ac:classes:Password
saml.sp.nameidformat NameID格式 urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress

Note

Fess 内部使用SAML库(java-saml),以 saml. 开头的属性将映射到该库对应的设置(onelogin.saml2. 前缀)。 因此,除此处列出的设置外,还可以在 system.properties 中指定绑定(例如 saml.sp.assertion_consumer_service.binding)、组织信息(saml.organization.*)、联系人信息(saml.contacts.*)等详细设置。

AuthnRequest有效期

Fess每次访问/sso/都会向IdP发送一个AuthnRequest,并将其ID记录在会话中。 IdP返回的SAML响应会根据记录的ID进行校验。

属性 描述 默认值
saml.request.id.ttl 未收到响应的AuthnRequest的ID保留时长(秒) 3600

记录的ID在超过该时长后会被丢弃。 如果超出有效期(例如IdP登录页面一直处于打开状态未处理),返回的断言将无法匹配,登录会当场失败一次。

配置示例

最小配置(用于测试)

以下是在测试环境中进行验证的最小配置示例。

# 启用SSO
sso.type=saml

# SP配置
saml.sp.base.url=https://fess.example.com

# IdP配置(设置从IdP管理控制台获取的值)
saml.idp.entityid=https://idp.example.com/saml/metadata
saml.idp.single_sign_on_service.url=https://idp.example.com/saml/sso
saml.idp.x509cert=MIIDpDCCAoygAwIBAgI...(Base64编码的证书)

# 默认组
saml.default.groups=user

推荐配置(用于生产)

以下是生产环境的推荐配置示例。

# 启用SSO
sso.type=saml

# SP配置
saml.sp.base.url=https://fess.example.com

# IdP配置
saml.idp.entityid=https://idp.example.com/saml/metadata
saml.idp.single_sign_on_service.url=https://idp.example.com/saml/sso
saml.idp.single_logout_service.url=https://idp.example.com/saml/logout
saml.idp.x509cert=MIIDpDCCAoygAwIBAgI...(Base64编码的证书)

# 用户属性映射
saml.attribute.group.name=groups
saml.attribute.role.name=roles
saml.default.groups=user

# 安全设置(生产环境推荐)
saml.security.want_assertions_signed=true
saml.security.want_messages_signed=true

# 确认IdP使用SHA-256或更强的算法签名后再启用
saml.security.reject_deprecated_alg=true

故障排除

常见问题和解决方案

认证后无法返回Fess

  • 验证ACS URL是否在IdP侧正确配置

  • 确保saml.sp.base.url的值与IdP配置匹配

  • SAML断言以来自IdP的跨站POST方式发送。 当tomcat_config.properties中的tomcat.sameSiteCookieslax(默认值)时, 浏览器不会随该请求发送会话Cookie,登录会当场只失败一次。 此时请设置tomcat.sameSiteCookies = noneSameSite=None需要HTTPS)

  • 如果在IdP上的登录耗时过长,断言返回时AuthnRequest ID已经不存在,登录会当场只失败一次,需要重新开始登录

  • Fess 未在app/WEB-INF/web.xml中设置session-timeout,因此采用Servlet容器的默认值30分钟。 该值短于saml.request.id.ttl的3600秒,会话会先被丢弃, 因此仅调大saml.request.id.ttl并不能延长用户在IdP完成登录的时间,还需要同时延长会话超时时间

通过反向代理时Destination验证失败

当Fess运行在终结TLS的反向代理或负载均衡器之后时, 即使saml.sp.base.url设置正确,断言验证也可能失败。

断言的Destination属性会与请求到达Fess时的URL进行比较。 在终结TLS的代理之后,该URL是内部的http://地址,而不是IdP发送断言时使用的外部地址。 saml.sp.base.url不参与该比较,因此仅设置它无法解决问题。

设置saml.debug=true后,日志中会输出如下原因:

The response was received at http://... instead of https://fess.example.com/sso/

此时请将tomcat_config.properties中的连接器设置调整为对外可见的协议和端口。 以下设置默认处于注释状态:

tomcat.secure=true
tomcat.scheme=https
tomcat.proxyPort=443

同时请配置反向代理,将原始的Host请求头透传给Fess, 因为请求URL中的主机名部分是根据该请求头构建的。 修改tomcat_config.properties后需要重启Fess。

同样的验证也适用于单点登出消息,因此使用SLO时请一并配置。

签名验证错误

  • 验证IdP证书是否正确配置

  • 确保证书未过期

  • 证书应仅指定为Base64编码的内容,无换行

因属性名重复而无法登录

  • 如果日志中出现以 The IdP repeated an attribute name in the SAML assertion 开头的警告, 说明 IdP 将同一个属性名拆分到了多个 <Attribute> 元素中

  • 断言本身已通过校验,因此证书和时间偏差都不是原因

  • 请在 IdP 侧合并属性,或设置 saml.security.allow_duplicated_attribute_name=true

用户组/角色未生效

  • 验证属性是否在IdP侧正确配置

  • 确保saml.attribute.group.name的值与IdP发送的属性名匹配

  • 使用Microsoft Entra ID时,除非选择了其他源属性,否则组声明的值为组的ObjectId(GUID),与组名不一致

  • 当用户所属的组超过150个时,Microsoft Entra ID将完全省略组声明(嵌套组也计入此上限), 此时 Fess 将回退到saml.default.groups

  • 启用调试模式以检查SAML断言内容

调试设置

要调查问题,您可以使用以下设置启用调试模式:

saml.debug=true

设置 saml.debug=true 后,当SAML认证失败时,详细原因将输出到日志中。

此外,通过在 app/WEB-INF/classes/log4j2.xml 中添加以下logger,可以输出详细的SAML相关日志:

<Logger name="org.codelibs.fess.sso.saml" level="DEBUG"/>

参考