The Kotlin DSL should allow setting a custom AuthenticationDetailsSource when using OAuth2 Login
http {
oauth2Login {
authenticationDetailsSource = AUTHENTICATION_DETAILS_SOURCE
}
}
Comment From: nmck257
Hey @eleftherias -- I'm looking at this, and I see that most of the existing fields on Oauth2LoginDsl
don't have explicit test coverage. Would we want to add test coverage for this new item, or are we comfortable calling it trivial if the implementation follows the same pattern as all the other fields?
Comment From: eleftherias
Thanks for looking into this @nmck257!
We should add test coverage for the authenticationDetailsSource
. We have a similar test in HttpBasicDslTests
called http basic when custom authentication details source then used
.
Comment From: nmck257
Okay -- I think I'm in good shape for #9837 (which I was working in parallel), but, I'm seeing some complexity in the test case for OAuth2.
The existing test cases in OAuth2LoginDslTests
don't actually perform a login; they just fetch the login page(s). To do a login for the new test, I tried something like this:
@Test
fun `oauth2Login when custom authentication details source then used`() {
this.spring
.register(CustomAuthenticationDetailsSourceConfig::class.java, ClientConfig::class.java)
.autowire()
mockkObject(CustomAuthenticationDetailsSourceConfig.AUTHENTICATION_DETAILS_SOURCE)
every {
CustomAuthenticationDetailsSourceConfig.AUTHENTICATION_DETAILS_SOURCE.buildDetails(any())
} returns Any()
this.mockMvc.get("/") {
with(oauth2Login()) // *********************** the difficult bit, discussed below
}
verify(exactly = 1) { CustomAuthenticationDetailsSourceConfig.AUTHENTICATION_DETAILS_SOURCE.buildDetails(any()) }
}
@EnableWebSecurity
open class CustomAuthenticationDetailsSourceConfig : WebSecurityConfigurerAdapter() {
companion object {
val AUTHENTICATION_DETAILS_SOURCE: AuthenticationDetailsSource<HttpServletRequest, *> =
AuthenticationDetailsSource<HttpServletRequest, Any> { Any() }
}
override fun configure(http: HttpSecurity) {
http {
oauth2Login {
authenticationDetailsSource = AUTHENTICATION_DETAILS_SOURCE
}
authorizeRequests {
authorize(anyRequest, authenticated)
}
}
}
}
...using a method from SecurityMockMvcRequestPostProcessors
, like in HttpBasicDslTests
. But, as I understand it, that oauth2Login
method circumvents the code which would call our authenticationDetailsSource
by directly adding an AuthorizedClient
to the repository before executing the request.
I think I would instead need to supply a "fresh" token on the request and use the actual oauth2 mechanism to authenticate it, but, I'm not sure how to cleanly orchestrate that in the test. Some kind of MockClientRegistration
which auto-accepts tokens?
Am I off-track? @eleftherias
Comment From: eleftherias
@nmck257 The easiest way is probably to mock the authorizationRequestRepository
. You can provide a mock in the AuthorizationEndpointDsl
.
oauth2Login {
authenticationDetailsSource = AUTHENTICATION_DETAILS_SOURCE
authorizationEndpoint {
authorizationRequestRepository = AUTHORIZATION_REQUEST_REPOSITORY
}
}
You can then mock the removeAuthorizationRequest
method to return an OAuth2AuthorizationRequest
.
The test should call the endpoint "/login/oauth2/code/{registration-id}" in order to reach the OAuth2LoginAuthenticationFilter
which calls AUTHENTICATION_DETAILS_SOURCE.buildDetails
.
Let me know if you have any questions.
Comment From: nmck257
@eleftherias Thanks for the direction -- it helped a bunch!
I've opened a PR #10071 (and I do have a question in there).