Spring 安全 SAML 断言到角色转换
Spring Security SAML Assertion to Roles conversion
我一直在使用 SAML 2.0 和 Spring Boot 2.5.6,使用 Okta 作为身份提供者。在大多数情况下,我已经能够创建 Web 应用程序并与 Okta 的身份提供者集成。我面临的问题与角色有关。我在 Okta 中分配的组不会转换为 Spring Security 中的角色,并且不清楚这种转换在 Spring Security for SAML 中应该如何发生。在 SAML 断言中,组属性被命名为“groups”,我可以在作为响应的一部分出现的断言 XML 中看到这一点。但是 Spring 安全性不将“组”属性理解为角色。
身份验证后,SAML2Authentication 对象包含权限 ROLE_USER。如何将 Assertion 中的传入组属性转换为 SAML2Authentication 中的适当权限?否则我无法将应用程序 URL 配置为正确的授权角色。
请帮助或指明方向
有多种方法可以在 Spring Boot 中连接到 SAML2 身份验证过程,但最常见且看似推荐的方法是自定义 OpenSamlAuthenticationProvider
,Spring Security 用于身份验证。
然而,该方法在最近的版本中发生了很多变化。下面的示例是在 Kotlin 中,您必须自己将其翻译成 Java(如果这是您想要的)。还有,哪个Spring安全版本用在哪个Spring引导版本,你也得自己摸索,不过2.5.6版本肯定把你放在下面最后一种情况下。
Spring 安全 < 5.3.0
setAuthoritiesExtractor
使得添加一个从断言中提取权限/角色的方法变得容易。该方法应该 return 类型为 Collection<GrantedAuthority>
的对象。
.saml2Login()
.authenticationManager(
ProviderManager(
OpenSamlAuthenticationProvider().apply {
setAuthoritiesExtractor { a: Assertion? ->
// return a list of authorities based on the assertion
}
}
)
)
Spring 安全 >= 5.3.0 且 < 5.4.0
setAuthoritiesExtractor
已弃用,建议改用 setResponseAuthenticationConverter
。不幸的是,这比以前的方法更复杂。
.saml2Login()
.authenticationManager(
ProviderManager(
OpenSamlAuthenticationProvider().apply {
setResponseAuthenticationConverter {
val defaultAuth = OpenSamlAuthenticationProvider.createDefaultResponseAuthenticationConverter().convert(it);
if (defaultAuth !== null && defaultAuth.isAuthenticated) {
val authoritiesLists = it.response.assertions.map { ass ->
// return a list of authorities based on the assertion
}
val authoritiesList = authoritiesLists.flatten().toSet()
Saml2Authentication(defaultAuth.principal as AuthenticatedPrincipal, defaultAuth.saml2Response, authoritiesList)
}
else
defaultAuth
}
}
)
)
我不知道是否有更简单的方法,但这里我们基本上使用默认行为,但按我们想要的方式修改它。形式上,断言列表可能包含多个断言,因此我们通过使用多个列表来处理这个问题,然后将这些列表展平并变成一个集合(如果你愿意,你可以只使用第一个断言,因为通常只有一个) .
Spring 安全 >= 5.4.0
这次发生的变化是 OpenSamlAuthenticationProvider
已弃用,因为它使用的 OpenSAML3 已达到其生命周期的尽头并已被 OpenSAML4 取代。我们现在必须使用 OpenSaml4AuthenticationProvider
。除此之外,配置部分保持不变
.saml2Login()
.authenticationManager(
ProviderManager(
OpenSaml4AuthenticationProvider().apply {
setResponseAuthenticationConverter {
val defaultAuth = OpenSaml4AuthenticationProvider.createDefaultResponseAuthenticationConverter().convert(it);
if (defaultAuth !== null && defaultAuth.isAuthenticated) {
val authoritiesLists = it.response.assertions.map { ass ->
// return a list of authorities based on the assertion
}
val authoritiesList = authoritiesLists.flatten().toSet()
Saml2Authentication(defaultAuth.principal as AuthenticatedPrincipal, defaultAuth.saml2Response, authoritiesList)
}
else
defaultAuth
}
}
)
)
尽管如此,这不会开箱即用,您必须对项目中的包语句进行一些修改,以强制 Spring 安全性使用 OpenSAML4 而不是 OpenSAML3(这是默认设置向后兼容)。
下面是使用 Gradle
时的样子
dependencies {
constraints {
implementation "org.opensaml:opensaml-core:4.1.1"
implementation "org.opensaml:opensaml-saml-api:4.1.1"
implementation "org.opensaml:opensaml-saml-impl:4.1.1"
}
...
}
大功告成!请记住,Saml2Authentication
的第一个参数是用户主体(继承自 AuthenticatedPrincipal
),它也可以根据您自己的愿望和需要进行自定义。只需实现一个继承自 AuthenticatedPrincipal
的用户 class 并将逻辑添加到响应身份验证转换器即可。
链接
我一直在使用 SAML 2.0 和 Spring Boot 2.5.6,使用 Okta 作为身份提供者。在大多数情况下,我已经能够创建 Web 应用程序并与 Okta 的身份提供者集成。我面临的问题与角色有关。我在 Okta 中分配的组不会转换为 Spring Security 中的角色,并且不清楚这种转换在 Spring Security for SAML 中应该如何发生。在 SAML 断言中,组属性被命名为“groups”,我可以在作为响应的一部分出现的断言 XML 中看到这一点。但是 Spring 安全性不将“组”属性理解为角色。
身份验证后,SAML2Authentication 对象包含权限 ROLE_USER。如何将 Assertion 中的传入组属性转换为 SAML2Authentication 中的适当权限?否则我无法将应用程序 URL 配置为正确的授权角色。
请帮助或指明方向
有多种方法可以在 Spring Boot 中连接到 SAML2 身份验证过程,但最常见且看似推荐的方法是自定义 OpenSamlAuthenticationProvider
,Spring Security 用于身份验证。
然而,该方法在最近的版本中发生了很多变化。下面的示例是在 Kotlin 中,您必须自己将其翻译成 Java(如果这是您想要的)。还有,哪个Spring安全版本用在哪个Spring引导版本,你也得自己摸索,不过2.5.6版本肯定把你放在下面最后一种情况下。
Spring 安全 < 5.3.0
setAuthoritiesExtractor
使得添加一个从断言中提取权限/角色的方法变得容易。该方法应该 return 类型为 Collection<GrantedAuthority>
的对象。
.saml2Login()
.authenticationManager(
ProviderManager(
OpenSamlAuthenticationProvider().apply {
setAuthoritiesExtractor { a: Assertion? ->
// return a list of authorities based on the assertion
}
}
)
)
Spring 安全 >= 5.3.0 且 < 5.4.0
setAuthoritiesExtractor
已弃用,建议改用 setResponseAuthenticationConverter
。不幸的是,这比以前的方法更复杂。
.saml2Login()
.authenticationManager(
ProviderManager(
OpenSamlAuthenticationProvider().apply {
setResponseAuthenticationConverter {
val defaultAuth = OpenSamlAuthenticationProvider.createDefaultResponseAuthenticationConverter().convert(it);
if (defaultAuth !== null && defaultAuth.isAuthenticated) {
val authoritiesLists = it.response.assertions.map { ass ->
// return a list of authorities based on the assertion
}
val authoritiesList = authoritiesLists.flatten().toSet()
Saml2Authentication(defaultAuth.principal as AuthenticatedPrincipal, defaultAuth.saml2Response, authoritiesList)
}
else
defaultAuth
}
}
)
)
我不知道是否有更简单的方法,但这里我们基本上使用默认行为,但按我们想要的方式修改它。形式上,断言列表可能包含多个断言,因此我们通过使用多个列表来处理这个问题,然后将这些列表展平并变成一个集合(如果你愿意,你可以只使用第一个断言,因为通常只有一个) .
Spring 安全 >= 5.4.0
这次发生的变化是 OpenSamlAuthenticationProvider
已弃用,因为它使用的 OpenSAML3 已达到其生命周期的尽头并已被 OpenSAML4 取代。我们现在必须使用 OpenSaml4AuthenticationProvider
。除此之外,配置部分保持不变
.saml2Login()
.authenticationManager(
ProviderManager(
OpenSaml4AuthenticationProvider().apply {
setResponseAuthenticationConverter {
val defaultAuth = OpenSaml4AuthenticationProvider.createDefaultResponseAuthenticationConverter().convert(it);
if (defaultAuth !== null && defaultAuth.isAuthenticated) {
val authoritiesLists = it.response.assertions.map { ass ->
// return a list of authorities based on the assertion
}
val authoritiesList = authoritiesLists.flatten().toSet()
Saml2Authentication(defaultAuth.principal as AuthenticatedPrincipal, defaultAuth.saml2Response, authoritiesList)
}
else
defaultAuth
}
}
)
)
尽管如此,这不会开箱即用,您必须对项目中的包语句进行一些修改,以强制 Spring 安全性使用 OpenSAML4 而不是 OpenSAML3(这是默认设置向后兼容)。
下面是使用 Gradle
时的样子dependencies {
constraints {
implementation "org.opensaml:opensaml-core:4.1.1"
implementation "org.opensaml:opensaml-saml-api:4.1.1"
implementation "org.opensaml:opensaml-saml-impl:4.1.1"
}
...
}
大功告成!请记住,Saml2Authentication
的第一个参数是用户主体(继承自 AuthenticatedPrincipal
),它也可以根据您自己的愿望和需要进行自定义。只需实现一个继承自 AuthenticatedPrincipal
的用户 class 并将逻辑添加到响应身份验证转换器即可。