9.Spring Security SAML 单点登录配置

9.单点登录配置

9.1 IDP选择和发现

发现可帮助您的服务提供商确定应使用哪个身份提供商来验证当前用户。它在scheme:// server:port / contextPath / saml / login的单点登录端点调用期间自动初始化。SAML Extension支持多种发现模式,包括身份提供商发现服务协议和配置文件

通过使用所需IDP的entityId 指定HTTP请求参数idp,例如scheme:// server:port / contextPath / saml / login?idp = mySelectedIDP,可以在SSO初始化期间始终跳过IDP发现模式。

本地SP期望发现响应的URL可以作为扩展之一包含在SP元数据中。该功能可以通过属性设置来启用includeDiscoveryExtension 上豆真MetadataGenerator内MetadataGeneratorFilter,如:

<bean id="metadataGeneratorFilter" class="org.springframework.security.saml.metadata.MetadataGeneratorFilter">
	<constructor-arg>
		<bean class="org.springframework.security.saml.metadata.MetadataGenerator">
			<property name="includeDiscoveryExtension" value="true"/>
		</bean>
	</constructor-arg>
</bean>

没有发现的默认IDP

默认情况下启用该模式,并自动选择默认IDP而不执行发现。

可以使用Spring Security配置中的bean 元数据上的属性defaultIDP配置默认IDP 。如果未设置该属性,系统将自动使用第一个可用的IDP。

本地发现服务

SAML扩展包括本地IDP发现服务,该服务向用户呈现IDP选择页面。可以通过将本地SP扩展元数据中的 属性includeDiscovery设置为true来启用此模式。

可以使用bean samlIDPDiscovery上的属性idpSelectionPath自定义选择页面。系统使用包含以下请求属性的发现请求转发到此页面:

  • idpDiscoReturnURL - 将IDP选择结果发送到使用GET操作的URL
  • idpDiscoReturnParam - 要包含所选IDP的实体ID的GET参数的名称

有关示例,请参阅sample / src / main / webapp / WEB-INF / security / idpSelection.jsp中的默认实现。

远程发现服务

为了启用外部IDP发现服务,请将本地SP扩展元数据中的属性idpDiscoveryURL配置为外部发现URL。确保属性idpDiscoveryEnabled设置为true。远程发现服务需要支持身份提供商发现服务协议和配置文件。

9.2单点登录过程

Spring SAML Extension支持SP初始化和IDP初始化单点登录。

9.2.1服务提供商初始化SSO

SP初始化的SSO过程可以通过两种方式启动:

  • 用户访问受Spring Security保护的资源,初始化SAMLEntryPoint
  • 用户被重定向到SSO端点,例如https://www.server.com/context/saml/login

在识别用于身份验证的IDP后(有关详细信息,请参见第9.1节“IDP选择和发现”),SAML Extension会创建一个AuthnRequest SAML消息并将其发送到选定的IDP。用于发送它的AuthnRequest和绑定的构造都可以使用WebSSOProfileOptions 对象进行自定义。SAMLEntryPoint 通过调用方法getProfileOptions确定要使用的WebSSOProfileOptions配置。默认实现返回属性defaultOptions中指定的值。可以重写该方法以为SSO初始化提供自定义逻辑。

为默认设置WebSSOProfileOptions可以在Bean指定samlEntryPoint您的securityContext.xml,如:

<bean id="samlEntryPoint" class="org.springframework.security.saml.SAMLEntryPoint">
	<property name="defaultProfileOptions">
		<bean class="org.springframework.security.saml.websso.WebSSOProfileOptions">
			<property name="binding" value="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"/>
			<property name="includeScoping" value="false"/>
		</bean>
	</property>
</bean>

WebSSOProfileOptions支持以下设置:

表9.1。 org.springframework.security.saml.websso.WebSSOProfileOptions参数

属性描述
binding
默认值:在IDP元数据中绑定第一个声明的SingleSignOnService。绑定用于向IDP发送消息。支持的值取决于SP配置,通常为
"urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST", "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect", "urn:oasis:names:tc:SAML:2.0:bindings:PAOS" and "urn:oasis:names:tc:SAML:2.0:profiles:holder-of-key:SSO:browser"
providerName
默认值:empty。随身份验证请求一起发送的本地SP的人类可读名称。
assertionConsumerIndex
默认值:empty。设置时确定IDP应在何处发送响应以及使用哪种绑定。否则,系统使用标记为默认的默认断言使用者服务,或首先适用。可在此服务提供商的元数据中找到可用索引。
nameID
默认值:empty。要在NameIDPolicy中从IDP请求的名称ID。未指定时,不发送NameIDPolicy。典型值为
"urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress", "urn:oasis:names:tc:SAML:2.0:nameid-format:transient", "urn:oasis:names:tc:SAML:2.0:nameid-format:persistent", "urn:oasis:names:tc:SAML:2.0:nameid-format:encrypted".
allowCreate
默认值:empty。仅在指定nameID时适用,当true指示IDP允许基于身份验证请求创建新用户时。
passive
默认值:false。设置IdP在身份验证过程中是否应避免与用户交互。
forceAuthn
默认值:false。当需要真正的IDP来重新验证用户身份而不依赖于以前的身份验证事件时。
includeScoping默认值:true。当真正的请求将包括范围元素。
allowedIDPs默认值:empty。将包含在IDP消息顶部的Scoping元素中的值发送到。仅在includeScoping设置为true时适用。
proxyCount默认值:2。确定要在AuthnRequest中的作用域的proxyCount属性中使用的值。使用零来禁用代理或使用值> 0来指定允许的跳数。仅在includeScoping设置为true时适用。
authnContexts默认值:empty。身份验证上下文允许IDP在对用户进行身份验证时使用。有关详细信息,请参阅规范
authnContextComparison默认值:AuthnContextComparisonTypeEnumeration.EXACT。IDP用于确定要使用的身份验证方法的机制。有关详细信息,请参阅规范
的RelayState默认值:empty。值将发送到IDP并作为身份验证响应的一部分提供回SP。

AuthnRequest消息在消息级别上以未加密方式发送。如果需要,应在传输层上通过SSL / TLS提供加密。

9.2.2身份提供者初始化SSO

Spring SAML支持接收未经请求的响应消息(所谓的IDP初始化SSO)。在这种情况下,IDP创建一个Response对象的方式与回复从SP发送的AuthnRequest消息的方式相同,但它省略了InResponseTo参数。然后使用其中一个受支持的绑定将消息发送到Spring SAML的AssertionConsumerURL(通常为 scheme:// server:port / contextPath / saml / SSO)。可以在Spring SAML应用程序的元数据中找到所有可用端点和绑定的列表。

收到的未经请求的Respose消息的处理和验证方式与SP-Initialized SSO完全相同。

可以使用属性supportUnsolicitedResponse在远程实体的ExtendedMetadata中禁用对未经请求的消息的支持。

9.3注销过程

Spring SAML Extension支持Local Logout和Single Logout机制。

9.3.1本地注销

本地注销仅终止本地会话,既不会影响IDP上的会话,也不会影响用户使用单点登录登录的其他SP上的会话。可以在scheme:// server:port / contextPath / saml / logout?local = true初始化本地注销。调用被bean samlLogoutFilter拦截,可以使用以下设置进行配置:

  • 接口org.springframework.security.web.authentication.logout.LogoutSuccessHandler(构造函数索引0)的实例,它确定成功注销后要执行的操作(例如,重定向到注销登录页面)。默认情况下,用户被重定向到页面logout.jsp。
  • 接口org.springframework.security.web.authentication.logout.LogoutHandler(构造函数索引1)的实例,负责销毁用户的会话。默认处理程序org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler通过删除Authentication对象来记录用户,但保持HTTP会话打开。

也可以使用<security:http>块内的标准Spring Security元素<security:logout>配置本地注销。例如:

<security:http>
	<security:logout logout-url="/j_logout" logout-success-url="/logout.jsp"/>
</security:http>

9.3.2全局注销

全局注销实现SAML 2.0 Single Logout配置文件,该配置文件终止当前SP上的会话,IDP会话以及连接到同一IDP会话的其他SP上的会话。可以从任何参与的SP或IDP初始化单一注销。

HTTP-Redirect和HTTP-POST绑定目前支持单一注销。SOAP绑定不可用。

可以在scheme:// server:port / contextPath / saml / logout初始化全局注销。系统根据当前已验证的用户自动确定将请求发送到哪个IDP。可以使用bean samlLogoutFilter和samlLogoutProcessingFilter使用以下选项配置单一注销:

  • 可以为Bean samlLogoutFilter提供接口org.springframework.security.web.authentication.logout.LogoutHandler(构造函数索引3)的实例。在从当前SP初始化Single Logout时,在向IDP发送SAML 2.0 LogoutRequest之前调用处理程序。
  • Bean samlLogoutProcessingFilter可以提供接口org.springframework.security.web.authentication.logout.LogoutSuccessHandler(构造函数索引0)的实例。成功完成Single Logout过程(从IDP接收LogoutResponse)后调用处理程序,并确定在注销后执行的操作(例如,重定向到注销登录页面)。默认情况下,用户被重定向到页面logout.jsp。
  • 可以为Bean samlLogoutProcessingFilter提供接口org.springframework.security.web.authentication.logout.LogoutHandler(构造函数索引1)的实例。成功从IDP接收SAML 2.0 LogoutRequest或LogoutResponse后调用处理程序。

Spring SAML正确处理从IDP发送的SAML 2.0 LogoutRequest消息,并在消息有效时执行注销。如果数据无效(签名丢失,发布者无效,发布时间无效,目的地无效,会话索引无效,名称ID无效,无用户登录),系统将使用SAML 2.0 LogoutResponse响应错误状态代码。

9.4认证对象

使用SAML令牌成功进行身份验证会导致SAMLAuthenticationProvider创建Authentication对象。默认情况下, 创建org.springframework.security.providers.ExpiringUsernameAuthenticationToken的实例。生成的对象的内容可以通过设置的属性来定制samlAuthenticationProvider在bean securityContext.xml。可以提供org.springframework.security.saml.userdetails.SAMLUserDetailsS​​ervice的实例,以提供有关经过身份验证的用户的特定于应用程序的信息。

默认情况下,Authentication对象将包含SAML断言中包含的NameID的字符串版本作为其主体。Property forcePrincipalAsString可用于更改此值以包含原始NameID元素。

使用SecurityContextHolder.getContext()。getAuthentication()并使用Spring Security保护的页面中可以使用Authentication对象,并使用以下值填充:

表9.2。ExpiringUsernameAuthenticationToken值。

属性
Principal
当forcePrincipalAsString = true(默认值)时 - SAML断言中包含的NameID的字符串值(credential.getNameID().getValue() of type java.lang.String)
Principal
 forcePrincipalAsString = false AND userDetail = null (默认值)时 - SAML断言中包含的NameID对象(credential.getNameID() of type org.opensaml.saml2.core.NameID)
Principal
当forcePrincipalAsString = false AND userDetail != null 时 - SAMLUserDetailsS​​ervice返回UserDetail对象
Credentials
SAML身份验证对象,包括本地和远程实体的实体ID,名称ID,断言和中继状态(org.springframework.security.saml.SAMLCredential)
Authorities
getAuthorities()结果调用从SAMLUserDetailsS​​ervice返回的UserDetails对象,当没有UserDetail对象可用时调用空列表。
Expiration
可用时SAML断言中SessionNotOnOrAfter的值,否则为null。在到期时间之后,身份验证对象将在isAuthenticated() 上开始返回false 

该定制实现SAMLUserDetailsS​​ervice可以作为财产提供为userDetails的的SAMLAuthenticationProvider。实现可以执行操作,例如解析SAML断言中存在的属性,例如:

package fi.schafer.test.saml;

import org.opensaml.saml2.core.Attribute;
import org.opensaml.xml.XMLObject;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.saml.SAMLCredential;
import org.springframework.security.saml.userdetails.SAMLUserDetailsService;

public class TestUserDetails implements SAMLUserDetailsService {
	@Override
	public Object loadUserBySAML(SAMLCredential cred) throws UsernameNotFoundException {
		return cred.getAttributeAsString("accountID");
	}
}

可以通过覆盖SAMLAuthenticationProvider中的getUserDetails,getPrincipal,getEntitlements和getExpirationDate方法来进一步自定义身份验证对象的填充。

9.5认证断言

用于对用户进行身份验证的断言存储在属性authenticationAssertion下的SAMLCredential对象中。默认情况下,断言的原始内容(DOM)将被丢弃,系统仅保留未编组的版本,该版本可能与原始版本略有不同,例如在空格中。为了指导春SAML财产保持断言在原始形式(保持其DOM)设置releaseDOM以虚假的豆WebSSOProfileConsumerImpl。

可以使用以下调用将断言序列化为String:

XMLHelper.nodeToString(SAMLUtil.marshallMessage(credential.getAuthenticationAssertion()))

9.6认证日志

可以记录关键事件,例如单点登录和单点注销初始化,成功或失败,以创建审计跟踪。可以通过实现org.springframework.security.saml.log.SAMLLogger接口并在securityContext.xml中包含其bean 来创建自定义记录器,例如:

<bean id="samlLogger" class="org.springframework.security.saml.log.SAMLDefaultLogger"/>

默认情况下提供两种基本实现:

  • org.springframework.security.saml.log.SAMLEmptyLogger不执行任何日志记录,只是忽略所有事件。
  • org.springframework.security.saml.log.SAMLDefaultLogger将事件作为INFO级别消息记录到日志名称org.springframework.security.saml.log.SAMLDefaultLogger,可按第6.6节“记录”中所述进行配置。将属性logMessages设置为true将包括SAML消息的内容作为日志的一部分。可以通过将logErrors设置为false来禁用异常日志记录。字段以分号分隔,具有以下值:

  • SAML消息的类型(AuthNRequest,AuthNResponse,LogoutRequest或LogoutResponse)
  • 处理结果(SUCCESS或FAILURE)
  • 向SP发出当前请求的对等体的IP地址
  • 本地SP的实体ID
  • 远程IDP的实体ID
  • 经过身份验证的用户的标识符
  • SAML消息(启用logMessages时)
  • 错误的文本(仅在启用logErrors时失败)

仅对可以正确接收和解析的消息调用记录器。有关在正确解析之前发生的错误,请参见第6.5节“错误处理”


(1)