Expected Behavior
Have an easy mechanism to use .with(oauth2Login()) on a service that uses the ServletOAuth2AuthorizedClientExchangeFilterFunction#setDefaultOAuth2AuthorizedClient(true) feature.
Current Behavior
When I use .with(oauth2Login()) on such service, the call isn't processed correctly, it fails as it can't find a valid AuthorizedClient in the corresponding repositories.
Context
I have this WebClient setup:
@Bean
WebClient webClient(ClientRegistrationRepository clientRegistrationRepository, OAuth2AuthorizedClientRepository authorizedClientRepository) {
ServletOAuth2AuthorizedClientExchangeFilterFunction oauth2 = new ServletOAuth2AuthorizedClientExchangeFilterFunction(clientRegistrationRepository, authorizedClientRepository);
oauth2.setDefaultOAuth2AuthorizedClient(true);
return WebClient.builder()
.apply(oauth2.oauth2Configuration())
.build();
}
Note: I'm aware I should be cautious when using setDefaultOAuth2AuthorizedClient(true), but I guess it's still a valid scenario, correct?
And this simple endpoint:
@GetMapping("/projects")
public String getProjects(Model model) {
List<ProjectModel> projects = this.webClient.get()
.uri(projectApiUrl)
.retrieve()
.bodyToMono(new ParameterizedTypeReference<List<ProjectModel>>() {
})
.block();
model.addAttribute("projects", projects);
return "projects";
}
Note: I'm using block() just because I'm using WebClient in a Servlet stack.
And finally, I have this test:
@Test
void givenMockedUser_whenRequestResources_thenOK() throws Exception {
String mockedResources = "[{\"id\":1,\"name\":\"Project 1\",\"dateCreated\":\"2015-06-01\"}]";
resourceServer.enqueue(new MockResponse().setBody(mockedResources)
.addHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE));
mvc.perform(get("/projects")
.with(oauth2Login())
.accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andExpect(content().string(containsString("Project 1")));
RecordedRequest request = resourceServer.takeRequest();
assertThat(request.getHeader(HttpHeaders.AUTHORIZATION)).startsWith("Bearer");
}
This test fails with the following error message:
org.springframework.web.util.NestedServletException: Request processing failed; nested exception is java.lang.IllegalArgumentException: Could not find ClientRegistration with id 'test'
...
Fair enough, I configure the OAuth2LoginRequestPostProcessor to use my custom ClientRegistration configured in my service:
.with(oauth2Login().clientRegistration(clientRegistrationRepository.findByRegistrationId("custom")))
Now the test fails because the service is returning a 302 response to trigger the OAuth authorization code flow, because it can't find an authorizedClient instance.
For what I understand from this note in the docs:
Further, it also links that OAuth2User to a simple instance of OAuth2AuthorizedClient that it deposits in a mock OAuth2AuthorizedClientRepository
This method does deposit the AuthorizedClient in a repository, but if understand how this works correctly, this will be stored in a HttpSessionOAuth2AuthorizedClientRepository that is not used when the WebClient resolves the AuthorizedClient using the setDefaultOAuth2AuthorizedClient feature; the OAuth2AuthorizeRequestconfigured in the ServletOAuth2AuthorizedClientExchangeFilterFunction simply has a null authorizedClient attribute.
Naturally, if I run this same test but using the @RegisteredOAuth2AuthorizedClient in the Controller endpoint, the test passes ok.
Comment From: sjohnr
@rozagerardo thanks for the report and detailed explanation! Just a note that due to the number of issues currently scheduled for 5.8 and 6.0, I have removed this from those milestones for the time being. If you are interested in submitting a PR for this, please let us know!
Comment From: rozagerardo
Thanks for having a look at this @jzheaux and for the response @sjohnr! Unfortunately, I don't have much availability to work on this right now, I'll let you know if I do at some point :)