authentication-requests.adoc 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. [[servlet-saml2login-sp-initiated-factory]]
  2. = Producing ``<saml2:AuthnRequest>``s
  3. As stated earlier, Spring Security's SAML 2.0 support produces a `<saml2:AuthnRequest>` to commence authentication with the asserting party.
  4. Spring Security achieves this in part by registering the `Saml2WebSsoAuthenticationRequestFilter` in the filter chain.
  5. This filter by default responds to endpoint `+/saml2/authenticate/{registrationId}+`.
  6. For example, if you were deployed to `https://rp.example.com` and you gave your registration an ID of `okta`, you could navigate to:
  7. `https://rp.example.org/saml2/authenticate/okta`
  8. and the result would be a redirect that included a `SAMLRequest` parameter containing the signed, deflated, and encoded `<saml2:AuthnRequest>`.
  9. [[servlet-saml2login-store-authn-request]]
  10. == Changing How the `<saml2:AuthnRequest>` Gets Stored
  11. `Saml2WebSsoAuthenticationRequestFilter` uses an `Saml2AuthenticationRequestRepository` to persist an `AbstractSaml2AuthenticationRequest` instance before xref:servlet/saml2/login/authentication-requests.adoc#servlet-saml2login-sp-initiated-factory[sending the `<saml2:AuthnRequest>`] to the asserting party.
  12. Additionally, `Saml2WebSsoAuthenticationFilter` and `Saml2AuthenticationTokenConverter` use an `Saml2AuthenticationRequestRepository` to load any `AbstractSaml2AuthenticationRequest` as part of xref:servlet/saml2/login/authentication.adoc#servlet-saml2login-authenticate-responses[authenticating the `<saml2:Response>`].
  13. By default, Spring Security uses an `HttpSessionSaml2AuthenticationRequestRepository`, which stores the `AbstractSaml2AuthenticationRequest` in the `HttpSession`.
  14. If you have a custom implementation of `Saml2AuthenticationRequestRepository`, you may configure it by exposing it as a `@Bean` as shown in the following example:
  15. [tabs]
  16. ======
  17. Java::
  18. +
  19. [source,java,role="primary"]
  20. ----
  21. @Bean
  22. Saml2AuthenticationRequestRepository<AbstractSaml2AuthenticationRequest> authenticationRequestRepository() {
  23. return new CustomSaml2AuthenticationRequestRepository();
  24. }
  25. ----
  26. Kotlin::
  27. +
  28. [source,kotlin,role="secondary"]
  29. ----
  30. @Bean
  31. open fun authenticationRequestRepository(): Saml2AuthenticationRequestRepository<AbstractSaml2AuthenticationRequest> {
  32. return CustomSaml2AuthenticationRequestRepository()
  33. }
  34. ----
  35. ======
  36. [[servlet-saml2login-sp-initiated-factory-signing]]
  37. == Changing How the `<saml2:AuthnRequest>` Gets Sent
  38. By default, Spring Security signs each `<saml2:AuthnRequest>` and send it as a GET to the asserting party.
  39. Many asserting parties don't require a signed `<saml2:AuthnRequest>`.
  40. This can be configured automatically via `RelyingPartyRegistrations`, or you can supply it manually, like so:
  41. .Not Requiring Signed AuthnRequests
  42. [tabs]
  43. ======
  44. Boot::
  45. +
  46. [source,yaml,role="primary"]
  47. ----
  48. spring:
  49. security:
  50. saml2:
  51. relyingparty:
  52. registration:
  53. okta:
  54. assertingparty:
  55. entity-id: ...
  56. singlesignon.sign-request: false
  57. ----
  58. Java::
  59. +
  60. [source,java,role="secondary"]
  61. ----
  62. RelyingPartyRegistration relyingPartyRegistration = RelyingPartyRegistration.withRegistrationId("okta")
  63. // ...
  64. .assertingPartyDetails(party -> party
  65. // ...
  66. .wantAuthnRequestsSigned(false)
  67. )
  68. .build();
  69. ----
  70. Kotlin::
  71. +
  72. [source,kotlin,role="secondary"]
  73. ----
  74. var relyingPartyRegistration: RelyingPartyRegistration =
  75. RelyingPartyRegistration.withRegistrationId("okta")
  76. // ...
  77. .assertingPartyDetails { party: AssertingPartyDetails.Builder -> party
  78. // ...
  79. .wantAuthnRequestsSigned(false)
  80. }
  81. .build()
  82. ----
  83. ======
  84. Otherwise, you will need to specify a private key to `RelyingPartyRegistration#signingX509Credentials` so that Spring Security can sign the `<saml2:AuthnRequest>` before sending.
  85. [[servlet-saml2login-sp-initiated-factory-algorithm]]
  86. By default, Spring Security will sign the `<saml2:AuthnRequest>` using `rsa-sha256`, though some asserting parties will require a different algorithm, as indicated in their metadata.
  87. You can configure the algorithm based on the asserting party's xref:servlet/saml2/login/overview.adoc#servlet-saml2login-relyingpartyregistrationrepository[metadata using `RelyingPartyRegistrations`].
  88. Or, you can provide it manually:
  89. [tabs]
  90. ======
  91. Java::
  92. +
  93. [source,java,role="primary"]
  94. ----
  95. String metadataLocation = "classpath:asserting-party-metadata.xml";
  96. RelyingPartyRegistration relyingPartyRegistration = RelyingPartyRegistrations.fromMetadataLocation(metadataLocation)
  97. // ...
  98. .assertingPartyDetails((party) -> party
  99. // ...
  100. .signingAlgorithms((sign) -> sign.add(SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA512))
  101. )
  102. .build();
  103. ----
  104. Kotlin::
  105. +
  106. [source,kotlin,role="secondary"]
  107. ----
  108. var metadataLocation = "classpath:asserting-party-metadata.xml"
  109. var relyingPartyRegistration: RelyingPartyRegistration =
  110. RelyingPartyRegistrations.fromMetadataLocation(metadataLocation)
  111. // ...
  112. .assertingPartyDetails { party: AssertingPartyDetails.Builder -> party
  113. // ...
  114. .signingAlgorithms { sign: MutableList<String?> ->
  115. sign.add(
  116. SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA512
  117. )
  118. }
  119. }
  120. .build()
  121. ----
  122. ======
  123. NOTE: The snippet above uses the OpenSAML `SignatureConstants` class to supply the algorithm name.
  124. But, that's just for convenience.
  125. Since the datatype is `String`, you can supply the name of the algorithm directly.
  126. [[servlet-saml2login-sp-initiated-factory-binding]]
  127. Some asserting parties require that the `<saml2:AuthnRequest>` be POSTed.
  128. This can be configured automatically via `RelyingPartyRegistrations`, or you can supply it manually, like so:
  129. [tabs]
  130. ======
  131. Java::
  132. +
  133. [source,java,role="primary"]
  134. ----
  135. RelyingPartyRegistration relyingPartyRegistration = RelyingPartyRegistration.withRegistrationId("okta")
  136. // ...
  137. .assertingPartyDetails(party -> party
  138. // ...
  139. .singleSignOnServiceBinding(Saml2MessageBinding.POST)
  140. )
  141. .build();
  142. ----
  143. Kotlin::
  144. +
  145. [source,kotlin,role="secondary"]
  146. ----
  147. var relyingPartyRegistration: RelyingPartyRegistration? =
  148. RelyingPartyRegistration.withRegistrationId("okta")
  149. // ...
  150. .assertingPartyDetails { party: AssertingPartyDetails.Builder -> party
  151. // ...
  152. .singleSignOnServiceBinding(Saml2MessageBinding.POST)
  153. }
  154. .build()
  155. ----
  156. ======
  157. [[servlet-saml2login-sp-initiated-factory-custom-authnrequest]]
  158. == Customizing OpenSAML's `AuthnRequest` Instance
  159. There are a number of reasons that you may want to adjust an `AuthnRequest`.
  160. For example, you may want `ForceAuthN` to be set to `true`, which Spring Security sets to `false` by default.
  161. You can customize elements of OpenSAML's `AuthnRequest` by publishing an `OpenSaml4AuthenticationRequestResolver` as a `@Bean`, like so:
  162. [tabs]
  163. ======
  164. Java::
  165. +
  166. [source,java,role="primary"]
  167. ----
  168. @Bean
  169. Saml2AuthenticationRequestResolver authenticationRequestResolver(RelyingPartyRegistrationRepository registrations) {
  170. RelyingPartyRegistrationResolver registrationResolver =
  171. new DefaultRelyingPartyRegistrationResolver(registrations);
  172. OpenSaml4AuthenticationRequestResolver authenticationRequestResolver =
  173. new OpenSaml4AuthenticationRequestResolver(registrationResolver);
  174. authenticationRequestResolver.setAuthnRequestCustomizer((context) -> context
  175. .getAuthnRequest().setForceAuthn(true));
  176. return authenticationRequestResolver;
  177. }
  178. ----
  179. Kotlin::
  180. +
  181. [source,kotlin,role="secondary"]
  182. ----
  183. @Bean
  184. fun authenticationRequestResolver(registrations : RelyingPartyRegistrationRepository) : Saml2AuthenticationRequestResolver {
  185. val registrationResolver : RelyingPartyRegistrationResolver =
  186. new DefaultRelyingPartyRegistrationResolver(registrations)
  187. val authenticationRequestResolver : OpenSaml4AuthenticationRequestResolver =
  188. new OpenSaml4AuthenticationRequestResolver(registrationResolver)
  189. authenticationRequestResolver.setAuthnRequestCustomizer((context) -> context
  190. .getAuthnRequest().setForceAuthn(true))
  191. return authenticationRequestResolver
  192. }
  193. ----
  194. ======