diff --git a/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/config/ApiClientConfiguration.java b/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/config/ApiClientConfiguration.java index 650960e79abaad1ee18de412e30d6ff0e4fa54e1..d8671c16c8bb355a4997ee1e33db445801f66881 100644 --- a/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/config/ApiClientConfiguration.java +++ b/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/config/ApiClientConfiguration.java @@ -1,6 +1,5 @@ package de.ozgcloud.nachrichten.postfach.osiv2.config; -import jakarta.annotation.PostConstruct; import org.apache.hc.client5.http.auth.AuthScope; import org.apache.hc.client5.http.auth.UsernamePasswordCredentials; import org.apache.hc.client5.http.impl.auth.BasicCredentialsProvider; @@ -10,21 +9,15 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.http.client.ClientHttpRequestFactory; -import org.springframework.http.client.ClientHttpRequestInterceptor; import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; -import org.springframework.http.converter.FormHttpMessageConverter; -import org.springframework.http.converter.json.JsonbHttpMessageConverter; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; -import org.springframework.security.oauth2.client.*; -import org.springframework.security.oauth2.client.endpoint.*; -import org.springframework.security.oauth2.client.http.OAuth2ErrorResponseErrorHandler; +import org.springframework.security.oauth2.client.AuthorizedClientServiceOAuth2AuthorizedClientManager; +import org.springframework.security.oauth2.client.InMemoryOAuth2AuthorizedClientService; +import org.springframework.security.oauth2.client.OAuth2AuthorizedClientProvider; +import org.springframework.security.oauth2.client.OAuth2AuthorizedClientProviderBuilder; +import org.springframework.security.oauth2.client.endpoint.RestClientClientCredentialsTokenResponseClient; import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository; -import org.springframework.security.oauth2.client.registration.ClientRegistrations; -import org.springframework.security.oauth2.client.registration.InMemoryClientRegistrationRepository; -import org.springframework.security.oauth2.client.web.DefaultOAuth2AuthorizedClientManager; -import org.springframework.security.oauth2.client.web.OAuth2AuthorizedClientRepository; import org.springframework.security.oauth2.client.web.client.OAuth2ClientHttpRequestInterceptor; -import org.springframework.security.oauth2.core.http.converter.OAuth2AccessTokenResponseHttpMessageConverter; import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.MultiValueMap; import org.springframework.web.client.RestClient; @@ -41,7 +34,6 @@ public class ApiClientConfiguration { private final OsiPostfachProperties.ApiConfiguration apiConfiguration; private final OsiPostfachProperties.ProxyConfiguration proxyConfiguration; - private static final String RESOURCE_HEADER = "resource"; @Bean MessageExchangeApi messageExchangeApi(ApiClient apiClient) { @@ -49,126 +41,31 @@ public class ApiClientConfiguration { } @Bean - ApiClient apiClient(OAuth2AuthorizedClientManager authorizedClientManager){ - var apiClient = new ApiClient(restClient(authorizedClientManager)); + ApiClient apiClient(RestClient restClient) { + var apiClient = new ApiClient(restClient); apiClient.setBasePath(apiConfiguration.getUrl()); return apiClient; } - @Bean - public RestClient restClient(OAuth2AuthorizedClientManager authorizedClientManager) { + public RestClient restClient(ClientRegistrationRepository clientRegistrations) { OAuth2ClientHttpRequestInterceptor requestInterceptor = - new OAuth2ClientHttpRequestInterceptor(authorizedClientManager); + new OAuth2ClientHttpRequestInterceptor(authorizedClientManager(clientRegistrations)); + requestInterceptor.setClientRegistrationIdResolver(request -> "osi2"); return RestClient.builder() .requestInterceptor(requestInterceptor) - . - .build(); } - - - private RestClient restClient; - - @PostConstruct - void initialize() { - - this.restClient = RestClient.builder() - .messageConverters((messageConverters) -> { - messageConverters.clear(); - messageConverters.add(new FormHttpMessageConverter()); -// messageConverters.add(new JsonbHttpMessageConverter()); - messageConverters.add(new OAuth2AccessTokenResponseHttpMessageConverter()); - }) - .defaultStatusHandler(new OAuth2ErrorResponseErrorHandler()) - // TODO: Customize the instance of RestClient as needed... - .build(); - } - - @Bean - public OAuth2AccessTokenResponseClient<OAuth2AuthorizationCodeGrantRequest> authorizationCodeAccessTokenResponseClient() { - RestClientAuthorizationCodeTokenResponseClient accessTokenResponseClient = - new RestClientAuthorizationCodeTokenResponseClient(); - accessTokenResponseClient.setRestClient(this.restClient); - - return accessTokenResponseClient; - } - - @Bean - public OAuth2AccessTokenResponseClient<OAuth2RefreshTokenGrantRequest> refreshTokenAccessTokenResponseClient() { - RestClientRefreshTokenTokenResponseClient accessTokenResponseClient = - new RestClientRefreshTokenTokenResponseClient(); - accessTokenResponseClient.setRestClient(this.restClient); - - return accessTokenResponseClient; - } - - @Bean - public OAuth2AccessTokenResponseClient<OAuth2ClientCredentialsGrantRequest> clientCredentialsAccessTokenResponseClient() { - RestClientClientCredentialsTokenResponseClient accessTokenResponseClient = - new RestClientClientCredentialsTokenResponseClient(); - accessTokenResponseClient.setRestClient(this.restClient); - - return accessTokenResponseClient; - } - - @Bean - public OAuth2AccessTokenResponseClient<OAuth2PasswordGrantRequest> passwordAccessTokenResponseClient() { - return (grantRequest) -> { - throw new UnsupportedOperationException("The `password` grant type is not supported."); - }; - } - - @Bean - public OAuth2AccessTokenResponseClient<JwtBearerGrantRequest> jwtBearerAccessTokenResponseClient() { - RestClientJwtBearerTokenResponseClient accessTokenResponseClient = - new RestClientJwtBearerTokenResponseClient(); - accessTokenResponseClient.setRestClient(this.restClient); - - return accessTokenResponseClient; - } - - @Bean - public OAuth2AccessTokenResponseClient<TokenExchangeGrantRequest> tokenExchangeAccessTokenResponseClient() { - RestClientTokenExchangeTokenResponseClient accessTokenResponseClient = - new RestClientTokenExchangeTokenResponseClient(); - accessTokenResponseClient.setRestClient(this.restClient); - - return accessTokenResponseClient; - } - -// @Bean -// RestClient restClient(OAuth2AuthorizedClientManager authorizedClientManager) { -// -// RestClient restClient = RestClient.builder() -// .requestFactory(createProxyRequestFactory()) -// .requestInterceptor(createOAuth2Interceptor(authorizedClientManager)) -// .baseUrl(apiConfiguration.getUrl()) -//// .defaultHeader(RESOURCE_HEADER, apiConfiguration.getResource()) -// .build(); -// return restClient; -// } - -// @Bean -// public OAuth2AccessTokenResponseClient<OAuth2ClientCredentialsGrantRequest> clientCredentialsAccessTokenResponseClient(RestClient restClient) { -// RestClientClientCredentialsTokenResponseClient accessTokenResponseClient = -// new RestClientClientCredentialsTokenResponseClient(); -// accessTokenResponseClient.setRestClient(restClient); -// -// return accessTokenResponseClient; -// } - - - private ClientHttpRequestFactory createProxyRequestFactory(){ + private ClientHttpRequestFactory createProxyRequestFactory() { var requestFactory = new HttpComponentsClientHttpRequestFactory(); - if(proxyConfiguration.isEnabled()){ + if (proxyConfiguration.isEnabled()) { var credsProvider = new BasicCredentialsProvider(); credsProvider.setCredentials( new AuthScope(proxyConfiguration.getHost(), proxyConfiguration.getPort()), -//TODO: hier brauchen wir noch eine Ordentliche Lösung -// new UsernamePasswordCredentials(proxyConfiguration.getUsername(), proxyConfiguration.getPassword().toCharArray()) + //TODO: hier brauchen wir noch eine Ordentliche Lösung + // new UsernamePasswordCredentials(proxyConfiguration.getUsername(), proxyConfiguration.getPassword().toCharArray()) new UsernamePasswordCredentials("", "".toCharArray()) ); var httpClient = HttpClientBuilder.create() @@ -180,8 +77,39 @@ public class ApiClientConfiguration { return requestFactory; } - private ClientHttpRequestInterceptor createOAuth2Interceptor(OAuth2AuthorizedClientManager authorizedClientManager) { - var interceptor = new OAuth2ClientHttpRequestInterceptor(authorizedClientManager); - return interceptor; + private AuthorizedClientServiceOAuth2AuthorizedClientManager authorizedClientManager( + ClientRegistrationRepository clientRegistrations) { + var clientService = new InMemoryOAuth2AuthorizedClientService( + clientRegistrations); + var authorizedClientManager = new AuthorizedClientServiceOAuth2AuthorizedClientManager( + clientRegistrations, clientService); + + authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider()); + + return authorizedClientManager; + } + + private OAuth2AuthorizedClientProvider authorizedClientProvider() { + return OAuth2AuthorizedClientProviderBuilder.builder() + .clientCredentials(builder -> + builder.accessTokenResponseClient(clientCredentialsTokenResponseClient()) + ) + .build(); } + + private RestClientClientCredentialsTokenResponseClient clientCredentialsTokenResponseClient() { + var client = new RestClientClientCredentialsTokenResponseClient(); + configureParametersForTokenRequests(client); + return client; + } + + private void configureParametersForTokenRequests(RestClientClientCredentialsTokenResponseClient client) { + client.addParametersConverter(source -> { + MultiValueMap<String, String> parameters = new LinkedMultiValueMap<>(); + // Pass a resource indicator parameter https://datatracker.ietf.org/doc/html/rfc8707 + parameters.add("resource", apiConfiguration.getResource()); + return parameters; + }); + } + } diff --git a/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/extension/OsiMockServerExtension.java b/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/extension/OsiMockServerExtension.java index 5ce2169b26b87ac81589556b0a6f5469d89f68fb..9d59d950c805922702d0a18bf38cbdb30e6c3a5c 100644 --- a/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/extension/OsiMockServerExtension.java +++ b/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/extension/OsiMockServerExtension.java @@ -105,7 +105,7 @@ public class OsiMockServerExtension implements BeforeAllCallback, AfterAllCallba .withMethod("POST") .withPath("/access-token") .withHeaders( - header("Content-Type", "application/x-www-form-urlencoded;charset=UTF-8") + header("Content-Type", "application/x-www-form-urlencoded") ) .withBody( params(