I'm trying to call a service which has CSRF enabled and all it's endpoints are configured to request authentication header from the user.
I'm using Spring RestTemplate as follows:
ResponseEntity<String> responseEntity = getRestTemplate().exchange(
"localhost:9090/",
"HEAD",
entity,
String.class);
return responseEntity.getBody();
However, I'm not able to read the Headers from the response as I'm getting HTTP 401 error.
My workaround is to read the token from the exception that RestTemplate throws HttpClientErrorException. Like this:
exception.getResponseHeaders().get("Set-Cookie");
for (String header : headers) {
if (header.startsWith("XSRF-TOKEN")) {
token = header.split("=")[1];
break;
}
}
Is there any way to get XSRF-TOKEN token with out relying on reading it from the exception?
You are not getting an exception when accessing with GET method. Hence, I would create a get endpoint for retrieving the token and then use it for next POST calls.
Hope that approach makes sense.
the csrf only blocks requests of type post, put, delete ... that is, the get is free, therefore in order to obtain the token, first you have to make a request to a get method and extract the token from there that you would use to the next requests.
in case the token is not generated, add this to the configure of your security configuration:
http.csrf (). csrfTokenRepository (CookieCrsfTokenRepository.withHttpOnlyFalse) .any () ........
XSRF-TOKEN following spring specification is marker for header by default. So you should try get it in this way:
List tokenList = responseEntity.getHeaders().get("XSRF-TOKEN");
This collection consist of single element as usual, so first element should be your token.
Related
I am making service to service requests using Spring's WebClient that require an OAuth2 bearer token to be added as a header to the request. I Can do this relatively easily by creating an ExchangeFilterFunction that intercepts the request, retrieves an access token, adds it to the header, and continues on. Since this is not a user request, the SecurityContextHolder does not contain an Authentication that would hold an access token for me, so instead of retrieving from that, I would like to get an access token based on my Spring security configuration (currently defined in the spring.security.oauth2.client.registration and provider properties).
The way I'm doing this now is by Autowiring an OAuth2ClientContext and then getting the AccessToken from it. Reducing the code only to what I care about for this question, I have:
#Component
public class OAuth2WebClientFilter implements ExchangeFilterFunction {
#Autowired
private OAuth2ClientContext oAuth2ClientContext;
public Mono<ClientResponse> filter(ClientRequest request, ExchangeFunction next) {
// simple retrieval of the token
String oAuth2Token = oAuth2ClientContext.getAccessToken().getValue();
// adding the token to the header of the request
request = ClientRequest.from(request).header(HttpHeaders.AUTHORIZATION, "Bearer " + oAuth2Token).build();
return next.exchange(request);
}
}
This does exactly what I want it to. However, I have recently upgraded spring-security-oauth2 to 2.5.0.RELEASE, and it is saying the OAuth2ClientContext is deprecated, but I haven't found a simple replacement for this process. So is there still a way to get an access token in a relatively simple fashion like above, and if so, how?
Also note: this concept is used elsewhere in the project and not just for the WebClient, so I'm looking to see how to properly replace an injected OAuth2ClientContext. Thanks!
Spring Security provides an exchange filter function called ServletOAuth2AuthorizedClientExchangeFilterFunction.
The ServletOAuth2AuthorizedClientExchangeFilterFunction provides a
simple mechanism for requesting protected resources by using an
OAuth2AuthorizedClient and including the associated OAuth2AccessToken
as a Bearer Token. It directly uses an OAuth2AuthorizedClientManager
and therefore inherits the following capabilities:
An OAuth2AccessToken will be requested if the client has not yet been
authorized.
authorization_code - triggers the Authorization Request redirect to
initiate the flow
client_credentials - the access token is obtained directly from the
Token Endpoint
password - the access token is obtained directly from the Token
Endpoint
If the OAuth2AccessToken is expired, it will be refreshed (or renewed)
if an OAuth2AuthorizedClientProvider is available to perform the
authorization
See https://docs.spring.io/spring-security/reference/servlet/oauth2/client/authorized-clients.html#oauth2Client-webclient-servlet for details.
I understand that there is always a token that basically glued to the request, now i would like to get retrieve a token and stuck, would appreciate some thoughts. Thank you
#GetMapping("/current")
public ResponseEntity<UserDto> getCurrent() {
return ResponseEntity.ok(something);
}
in the method body i would probably implement another service where constructor is taking token as an argument for example then does some equality checks.
In your controller accept HttpServletRequest. then you can extract any header from it.
#GetMapping("/current")
public ResponseEntity<UserDto> getCurrent(HttpServletRequest request) {
String token = request.getHeader("Authorization");
return ResponseEntity.ok(something);
}
If you don't want to take HttpServletRequest from controller you can Autowire it like this
#Autowired
private HttpServletRequest request;
or do the following
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
Your question is quite hard to understand. Your "token" could be anything.
I'll try to answer your question in general:
For example, you have some option which is available only for registered users. If you are using jwt security, you generate tokens for users and "glue" them to request/response headers
For example (that's my current jUnit test):
protected MockHttpServletRequestBuilder getAuth(String url) {
return MockMvcRequestBuilders.get(url).header("Authorization", this.token);
}
And token is generated using jwt security, and after it's generated I can "glue" it to the headers. And I can just check what's in header and get token value.
So to check or get this token, you have to check what's in your header, just that simple :)
That's very general example. But the main idea is:
If you add something - you can get something. But if you haven't generated a token - you wouldn't get one "by default", because there is none, java do not generate tokens to any request. It's something you must first create first.
If you are uncommon with what I am talking about - please start from here:
https://jwt.io/introduction/
We have 8 java microservices talking to each other in kubeneters cluster. Each microservice is bundled with auth library which intercepts and validates/renews JWT token for each REST request to controllers.
Scenario:
From Frontend, we get access token for the first time, Authentication gets successful. Lets say
Frontend hit 'Microservice A' with access token - Successful
'Microservice A' internally hits 'Microservice B' via restTemplate.
My 'Microservice B' also needs logged in user details.
Issue: I have to pass same access token from 'A' to 'B' but I am not able to get access token in Controller/Service logic but can get only in filters where token is being validated. I can get token in Rest Controllers by adding following argument in all rest methods in controller:
#RequestHeader (name="Authorization") String token
But I dont want to go with this approach as I have to pass this token to everywhere till end and have to declare this argument in all APIS.
I want to get token from TokenStore by passing authentication object. We are using Oauth2 and I checked the code in library, There are many tokenStore providers.
In DefaultTokenServices.java class, I am calling
Authentication auth = SecurityContextHolder.getContext().getAuthentication() // Passed this auth to tokenStore
String token = tokenStore.getAccessToken(auth).getValue(); // NullPointerException
My code is going through JWTTokenStore provider which is returning null. I checked, there is a provider called InMemoryTokenStore.class which actually extrActs token from store. But my flow is not going into in memory implementation.
Is there any way I can get token afterwards without grabbing it in controller via arguments? or how can I enable/use inMemoryTokenStore?
Also recommend something better for kubernetes intercommunication authentication?
TIA
It looks like you're using Spring (and Spring Security), so I believe the relevant part of the docs is the part on Bearer Token Propagation.
Its recommendation is to use a WebClient (the recommended replacement for RestTemplate as of Spring 5) that uses the provided ServletBearerExchangeFilterFunction to automagically propagate the JWT token from the incoming request into the outgoing request:
#Bean
public WebClient rest() {
return WebClient.builder()
.filter(new ServletBearerExchangeFilterFunction())
.build();
}
On RestTemplate, the docs say:
"There is no dedicated support for RestTemplate at the moment, but you can achieve propagation quite simply with your own interceptor"
and the following example is provided:
#Bean
RestTemplate rest() {
RestTemplate rest = new RestTemplate();
rest.getInterceptors().add((request, body, execution) -> {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication == null) {
return execution.execute(request, body);
}
if (!(authentication.getCredentials() instanceof AbstractOAuth2Token)) {
return execution.execute(request, body);
}
AbstractOAuth2Token token = (AbstractOAuth2Token) authentication.getCredentials();
request.getHeaders().setBearerAuth(token.getTokenValue());
return execution.execute(request, body);
});
return rest;
}
I don't believe you need to be looking at TokenStores if all you're trying to do is propagate the token. Remember everything relevant about a JWT should be inside the token itself. (Which is why the doc for the JwtTokenStore explains that it doesn't actually store anything, but just pulls info out of the token, and will return null for some methods, including the getAccessToken() method you're calling.)
I'm working on integrating a third party API in my spring boot application.
How the third party API authentication works:
After initial authorisation, I'm provided with refresh token and
access token that expires after a given time
After the access token expires I use the refresh token to get a new access token AND a new refresh token
With the current access token I can make calls to the API.
Is there a way to seamlessly handle such case using RestTemplate?
I've tried handling this case manually, so if I got 401 back from the API I sent a refresh token request, rewrote the keys I got back and retried the request, not really sure how to handle storing the api keys in case I need to restart the server.
This is easily done with a ClientHttpRequestInterceptor in which you can replace a requests header if e.g. a 401 occured:
#Override
public ClientHttpResponse intercept(
HttpRequest request,
byte[] body,
ClientHttpRequestExecution execution) throws IOException {
ClientHttpResponse response = execution.execute(request, body);
if(response.getStatusCode() == HttpStatus.UNAUTHORIZED) {
request.getHeaders().replace("Auth-Header", getNewToken());
return execution.execute(request, body);
}
return response;
}
See here for further guidance.
Here is my Java code that uses the Spring Framework:
#RequestMapping(method = RequestMethod.POST)
public #ResponseBody String SampleFunction(#RequestHeader("Authorization") String details)
{
System.out.println("Authorization details recieved");
}
I am trying to access Authorization header. I want to handle the missing Authorization header by redirecting it to a 400 Bad Request page. How can I do this?
By default the header is required. So if it is missing, you will get an exception.
However, see code below. Now, if it is missing, the details string will be null.
#RequestHeader(required = false, value = "Authorization") String details
If the header value is missing by default the response is 400 Bad Request. You just need to configure redirecting.