How to make spring webclient follow redirect with access token/authorization header? - spring-boot

We are using spring boot 2.4.5 with webflux and calling a service with client credentials grant type. What we noticed is that webclient is not following redirects.
How can we enable webclient to follow redirects where it can continue passing access token until it get the http 200?
Adding following code snippet does not pass the access token to redirected url and it is returning 401.
WebClient.builder()
.clientConnector(new ReactorClientHttpConnector(
HttpClient.create().followRedirect(true)
))

The sensitive headers like the Authorization are removed from the initialized request when redirecting to a different domain.
You can use the following variant of followRedirect(boolean):
followRedirect(boolean followRedirect, Consumer<HttpClientRequest> redirectRequestConsumer)
In order to re-add the Authorization header using redirectRequestConsumer.
For more details see the Javadoc here and Reactor Netty documentation here.

Related

Intercept spring RefreshTokenReactiveOAuth2AuthorizedClientProvider for webclient

I am looking for the solution to intercept
AbstractWebClientReactiveOAuth2AccessTokenResponseClient while using spring reactive Oauth2 with authorization grant type client_credentials? I am using hmac-auth-webclient provided here but this example only intercept the ClientRequest sent by webclient created in the configuration. While
ServerOAuth2AuthorizedClientExchangeFilterFunction using its own webclient instance to send the token request which doesnt get intercepted with the filters specified in the configuration. How can I force every webclient initiated in the application should use certain headers in the request such as Digest & signature headers?
I am expecting way to intercept webclient instance used AbstractWebClientReactiveOAuth2AccessTokenResponseClient to send some more custom headers with /token request.

Client Registration with Spring-boot Oauth2 - tokenUri vs issuerUri

Sorry folks, this may be a newb question. I'm a little lost.
My Spring-boot environment provides me with keycloak for client authorization, it gives me these.
spring.security.oauth2.resourceserver.jwt.issuer-uri
spring.security.oauth2.client.provider.keycloak.issuer-uri
spring.security.oauth2.client.registration.keycloak.* # client-id, secret, provider, grant-type
I noticed on the ClientRegistration that .issuerUri(String uri) is not avaialbe until Spring-Security v5.4.x. I am using 5.3.5, although I could bump up. I am confused what the difference is. As I would expect, I get an error when I do .tokenUri(issuerUri). I believe they are different modes/API, but I am at a loss as to what I should set in the 5.3.5 API.
Caused by: org.springframework.security.oauth2.client.ClientAuthorizationException: [invalid_token_response] An error occurred while attempting to retrieve the OAuth 2.0 Access Token Response: 405 Method Not Allowed: [{"error":"RESTEASY003650: No resource method found for POST, return 405 with Allow header"}]
So as a newb, I don't get why I have 4 choices of URI and what they do. Google and javadoc haven't been much help, so I figure I just don't know the right place to look to learn it. The only way I know how to fix this is to manual make my own HTTP call to the URI and get my Authentication token, but that would defeat the purpose of the Oauth2 library.
tokenUri represents the URI for the token endpoint. For example:
https://authz.example.org/auth/realms/myrealms/protocol/openid-connect/token
Whereas issuerUri is the URI that identifies the Authorization Server:
https://authz.example.org/auth
It's quite common for the issuer URI to be the root for more specific URIs like the token URI.
Regarding your specific error, I'd imagine that Keycloak is stating that you cannot POST to https://authz.example.org/auth, which is true. You should be POSTing to the token endpoint.
The issuer-uri Spring Boot property should cause Spring Security to look up the other endpoints and add them to a default ClientRegistration. Because of that, I'm not sure why you are also trying to programmatically configure ClientRegistration. That said, if you do need to programmatically create a ClientRegistration, you can use the issuer URI like so, and Spring Security will do the rest:
#Bean
ClientRegistrationRepository registrations() {
ClientRegistration registration = ClientRegistrations
.forIssuerLocation("https://authz.example.org/auth")
.build();
return new InMemoryClientRegistrationRepository(registration);
}

RestTemplate: Only one auth mechanism allowed; only the X-Amz-Algorithm query parameter

I am using RestTemplate with custom HttpClient. My request is getting redirected to S3 but somehow it is carrying Authorization header along with it after redirection.
Httpclient is configured to use LaxRedirectStrategy, cookies are ignored.
Is there a way how to fix this issue or any insight?

Implementing JWT, JWE and JWS (signed JWT) with Keycloak in Spring Boot

I try to implement a simple OAuth2 "Client Authentication with Signed JWT" Demo App using Spring Boot and Keycloak as AuthService.
The idea is:
one secured REST service "The Producer"
offering an endpoint GET /person for all users/principals with the role "read_person"
offering an endpoint POST /person for all users/principals with the role "write_person"
another (unsecured) REST service "The Consumer"
offering an enpoint /api open for everybody
calling internal the "producer" viaFeignclient using an RequestInterceptor to pass the AccessToken (signed JWT / JWS)
I read about the docs:
http://www.keycloak.org/docs/latest/securing_apps/topics/oidc/java/client-authentication.html
saying:
Once the client application is started, it allows to download its public >key in JWKS format using a URL such as http://myhost.com/myapp/k_jwks, >assuming that http://myhost.com/myapp is the base URL of your client >application. This URL can be used by Keycloak (see below).
During authentication, the client generates a JWT token and signs it with >its private key and sends it to Keycloak in the particular backchannel >request (for example, code-to-token request) in the client_assertion >parameter.
I googled a lot to find tutorials/demos or docs about this topic but failed so far.
So here my questions:
How do I implement this "k_jwk" endpoint? Do I simple build a #RestController by myself in "the Producer"? How do I configure Keycloak to get aware of this URL?
How do I implement my "Consumer" to get fresh signed JWT from Keycloak?
Update
Removed irritating PS statement.
You don't need to implement the k_jwk endpoint, this is handled by the adapter. Keycloak will by default look at http:///your.app.com/k_jwk(but if needed you can override that in the console).
Then you need to configure your Spring Boot client, just use the same properties as the keycloak.json but in the application.properties format:
...
keycloak.credentials.jwt.client-keystore-file=classpath:keystore-client.jks
keycloak.credentials.jwt.client-keystore-type=JKS
etc ...
You need a token to call the producerbut as you said the entry point will be an insecured endpoint so you might want to use a Service Account for this.
I hope this will help.
Update
I couldnt solve this issue but learned some things about singned JWT in the mean time:
create a so called "Bearer Token" by creating a Json Structure with all necessary claims (sub, nbf, exp ...) by yourself and sign/certificate it with your JKS/Private Key from Keycloak. There are some nice third party libs beside Keycloak to do this.
To get a real AccessToken (JWE/JWS) from Keycloak: send this static final Bearer Token to Keycloak at /auth/realms/$realm/protocol/openid-connect/token/introspect
with QueryParams:
grant_type=client_credentials&client_assertion_type=urn%3Aietf%3Aparams%3Aoauth%3Aclient-assertion-type%3Ajwt-bearer&client_assertion=$BEARER_TOKEN
Use the received real AccessToken to access the ResourceServer...

404 when do logout in Spring Security Rest Plugin for Grails

I'm setting the security system on my project (Grails - Angularjs) with Spring Security Rest Plugin v1.5.4 (using spring security core 2.0.0) for Grails 2.4.4. Doc about this plugin can be found here.
I'm testing the login and logout with postman chrome rest client and I'm able to do a login OK, but I'm getting a 404 when I do logout.
In the documentation clearly says:
The logout filter exposes an endpoint for deleting tokens. It will
read the token from an HTTP header. If found, will delete it from the
storage, sending a 200 response. Otherwise, it will send a 404
response
You can configure it in Config.groovy using this properties:
Config key...................................................................................Default
value
grails.plugin.springsecurity.rest.logout.endpointUrl....................../api/logout
grails.plugin.springsecurity.rest.token.validation.headerName....X-Auth-Token
So, after doing a login successfully, I tried to do a logout to that url (my_host_url/api/logout) with a GET method and sending a header X-Auth-Token with the token I got previously from login.
But I keep getting a 404. See image below
Edit: I'm setting the chain map like this (in order to get a stateless behavior):
grails.plugin.springsecurity.filterChain.chainMap = [
'/api/**': 'JOINED_FILTERS,-exceptionTranslationFilter,-authenticationProcessingFilter,-securityContextPersistenceFilter,-rememberMeAuthenticationFilter', // Stateless chain
'/**': 'JOINED_FILTERS,-restTokenValidationFilter,-restExceptionTranslationFilter' // Traditional chain
]
So. What am I doing wrong here, or what am I missing?
Thanks in advance!
You missed another excerpt from the docs. It's a warning message literally before the chunk you quoted, and says:
Logout is not possible when using JWT tokens (the default strategy), as no state is kept in the server.
If you still want to have logout, you can provide your own implementation by creating a subclass of JwtTokenStorageService and overriding the methods storeToken and removeToken. Then, register your implementation in resources.groovy as tokenStorageService.

Resources