產生 <saml2:AuthnRequest>
如先前所述,Spring Security 的 SAML 2.0 支援會產生 <saml2:AuthnRequest>
以啟動與斷言方的身份驗證。
Spring Security 部分透過在篩選器鏈中註冊 Saml2WebSsoAuthenticationRequestFilter
來達成此目的。此篩選器預設回應端點 /saml2/authenticate/{registrationId}
。
例如,如果您部署到 rp.example.com
,並且您給您的註冊 ID 為 okta
,您可以導航到
結果將會是一個重新導向,其中包含一個 SAMLRequest
參數,該參數包含已簽署、已壓縮和已編碼的 <saml2:AuthnRequest>
。
變更 <saml2:AuthnRequest>
的儲存方式
Saml2WebSsoAuthenticationRequestFilter
使用 Saml2AuthenticationRequestRepository
在將 <saml2:AuthnRequest>
傳送至斷言方之前,持久化 AbstractSaml2AuthenticationRequest
實例。
此外,Saml2WebSsoAuthenticationFilter
和 Saml2AuthenticationTokenConverter
使用 Saml2AuthenticationRequestRepository
來載入任何 AbstractSaml2AuthenticationRequest
,作為驗證 <saml2:Response>
的一部分。
預設情況下,Spring Security 使用 HttpSessionSaml2AuthenticationRequestRepository
,它將 AbstractSaml2AuthenticationRequest
儲存在 HttpSession
中。
如果您有 Saml2AuthenticationRequestRepository
的自訂實作,您可以透過將其公開為 @Bean
來組態它,如下列範例所示
-
Java
-
Kotlin
@Bean
Saml2AuthenticationRequestRepository<AbstractSaml2AuthenticationRequest> authenticationRequestRepository() {
return new CustomSaml2AuthenticationRequestRepository();
}
@Bean
open fun authenticationRequestRepository(): Saml2AuthenticationRequestRepository<AbstractSaml2AuthenticationRequest> {
return CustomSaml2AuthenticationRequestRepository()
}
變更 <saml2:AuthnRequest>
的傳送方式
預設情況下,Spring Security 會簽署每個 <saml2:AuthnRequest>
,並以 GET 方式傳送至斷言方。
許多斷言方不要求簽署的 <saml2:AuthnRequest>
。這可以透過 RelyingPartyRegistrations
自動組態,或者您可以手動提供,如下所示
-
Boot
-
Java
-
Kotlin
spring:
security:
saml2:
relyingparty:
okta:
identityprovider:
entity-id: ...
singlesignon.sign-request: false
RelyingPartyRegistration relyingPartyRegistration = RelyingPartyRegistration.withRegistrationId("okta")
// ...
.assertingPartyDetails(party -> party
// ...
.wantAuthnRequestsSigned(false)
)
.build();
var relyingPartyRegistration: RelyingPartyRegistration =
RelyingPartyRegistration.withRegistrationId("okta")
// ...
.assertingPartyDetails { party: AssertingPartyDetails.Builder -> party
// ...
.wantAuthnRequestsSigned(false)
}
.build()
否則,您需要指定一個私鑰給 RelyingPartyRegistration#signingX509Credentials
,以便 Spring Security 可以在傳送之前簽署 <saml2:AuthnRequest>
。
預設情況下,Spring Security 將使用 rsa-sha256
簽署 <saml2:AuthnRequest>
,但某些斷言方會要求不同的演算法,如其 metadata 中所示。
您可以根據斷言方的metadata 使用 RelyingPartyRegistrations
來組態演算法。
或者,您可以手動提供它
-
Java
-
Kotlin
String metadataLocation = "classpath:asserting-party-metadata.xml";
RelyingPartyRegistration relyingPartyRegistration = RelyingPartyRegistrations.fromMetadataLocation(metadataLocation)
// ...
.assertingPartyDetails((party) -> party
// ...
.signingAlgorithms((sign) -> sign.add(SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA512))
)
.build();
var metadataLocation = "classpath:asserting-party-metadata.xml"
var relyingPartyRegistration: RelyingPartyRegistration =
RelyingPartyRegistrations.fromMetadataLocation(metadataLocation)
// ...
.assertingPartyDetails { party: AssertingPartyDetails.Builder -> party
// ...
.signingAlgorithms { sign: MutableList<String?> ->
sign.add(
SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA512
)
}
}
.build()
上面的程式碼片段使用 OpenSAML SignatureConstants 類別來提供演算法名稱。但是,這只是為了方便起見。由於資料類型是 String ,您可以直接提供演算法的名稱。 |
某些斷言方要求 <saml2:AuthnRequest>
以 POST 方式傳送。這可以透過 RelyingPartyRegistrations
自動組態,或者您可以手動提供,如下所示
-
Java
-
Kotlin
RelyingPartyRegistration relyingPartyRegistration = RelyingPartyRegistration.withRegistrationId("okta")
// ...
.assertingPartyDetails(party -> party
// ...
.singleSignOnServiceBinding(Saml2MessageBinding.POST)
)
.build();
var relyingPartyRegistration: RelyingPartyRegistration? =
RelyingPartyRegistration.withRegistrationId("okta")
// ...
.assertingPartyDetails { party: AssertingPartyDetails.Builder -> party
// ...
.singleSignOnServiceBinding(Saml2MessageBinding.POST)
}
.build()
自訂 OpenSAML 的 AuthnRequest
實例
您可能想要調整 AuthnRequest
的原因有很多。例如,您可能希望將 ForceAuthN
設定為 true
,而 Spring Security 預設將其設定為 false
。
您可以透過發布 OpenSaml4AuthenticationRequestResolver
作為 @Bean
來客製化 OpenSAML 的 AuthnRequest
元素,如下所示
-
Java
-
Kotlin
@Bean
Saml2AuthenticationRequestResolver authenticationRequestResolver(RelyingPartyRegistrationRepository registrations) {
RelyingPartyRegistrationResolver registrationResolver =
new DefaultRelyingPartyRegistrationResolver(registrations);
OpenSaml4AuthenticationRequestResolver authenticationRequestResolver =
new OpenSaml4AuthenticationRequestResolver(registrationResolver);
authenticationRequestResolver.setAuthnRequestCustomizer((context) -> context
.getAuthnRequest().setForceAuthn(true));
return authenticationRequestResolver;
}
@Bean
fun authenticationRequestResolver(registrations : RelyingPartyRegistrationRepository) : Saml2AuthenticationRequestResolver {
val registrationResolver : RelyingPartyRegistrationResolver =
new DefaultRelyingPartyRegistrationResolver(registrations)
val authenticationRequestResolver : OpenSaml4AuthenticationRequestResolver =
new OpenSaml4AuthenticationRequestResolver(registrationResolver)
authenticationRequestResolver.setAuthnRequestCustomizer((context) -> context
.getAuthnRequest().setForceAuthn(true))
return authenticationRequestResolver
}