Collision between RestTemplate with basic authentication and exchange method - java

I am using Spring 4.3 and SpringBoot 1.5 to create a component that has to call an external REST service. This external service requests HTTP Basic Authentication.
I found that SpringBoot provides a very useful builder to set up RestTemplate properties, such as basic authentication, RestTemplateBuilder.
To call the external REST service I have to use the method RestTemplate.exchange, because of the List<T> return type.
new RestTemplateBuilder().basicAuthorization(username, password)
.build()
.exchange("/some/path/with/variables",
HttpMethod.GET,
new HttpEntity<>(new HttpHeaders()),
new ParameterizedTypeReference<List<Integer>>() {},
some, params)
The problem here is that the signature of the exchange method requests an object of type HttpEntity, that is basically a container of HttpHeaders.
The question is, will the HttpEntity object, passed as input parameter to the exchange method, subscribe the Basic Auth header set using the RestTemplateBuilder.basicAuthorization method?
Thanks a lot.

I have done some experiments during the past couple of days. The instance of HttpEntity passed to the exchange method does not subscribe the information relative to the Basic Authentication set by the RestTemplateBuilder. The two sets of headers are merged into one.
Nice shot, Spring ;)

Related

Accessing StreamListener headers from RequestContext or similar

I have a service which calls a dozen other services. This reads from a Kafka topic using a #StreamListener in a controller class. For traceability purposes, the same headers(original request ID) from the Kafka message need to be forwarded to all the other services as well
Traditionally, with a #PostMapping("/path") or GetMapping, a request context is generated, and one can access the headers from anywhere using RequestContextHolder.currentRequestAttributes() and I would just pass the HttpHeaders object into a RequestEntity whenever I need to make an external call
However in a StreamListener, no request context is generated and trying to access the RequestContextHolder results in an exception
Here's an example of what I tried to do, which resulted in an exception:
public class Controller {
#Autowired Service1 service1
#Autowired Service2 service2
#StreamListener("stream")
public void processMessage(Model model) {
service1.execute(model);
service2.execute(model);
}
}
public class Service {
RestTemplate restTemplate;
public void execute(Model model){
// Do some stuff
HttpHeaders httpHeaders = RequestContextHolder.currentRequestAttributes().someCodeToGetHttpHeaders();
HttpEntity<Model> request = new HttpEntity(model, httpHeaders);
restTemplate.exchange(url, HttpMethod.POST, request, String.class);
}
}
My current workaround is to change the StreamListener to a PostMapping and have another PostMapping which calls that so a request context can be generated. Another option was to use a ThreadLocal but it seems just as janky
I'm aware of the #Headers MessageHeaders annotation to access the stream headers, however, this isn't accessible easily without passing the headers down to each and every service and would affect many unit tests
Ideally, I need a way to create my own request context (or whatever the proper terminology is) to have a place to store request scoped objects (the HttpHeader) or another thread safe way to have request headers passed down the stack without adding a request argument to service.execute
I've found a solution and am leaving it here for anyone else trying to achieve something similar
If your goal is to forward a bunch of headers end-to-end through REST controllers and Stream listeners, you might want to consider using Spring Cloud Sleuth
Add it to your project through your maven or gradle configuration:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-sleuth</artifactId>
</dependency>
Specifically, in Spring Cloud Sleuth there is a feature to forward headers or "baggage" by setting the property spring.sleuth.propagation-keys in your application.properties. These key-value pairs are persisted through the entire trace, including any downstream http or stream calls which also implement the same propagation keys
If these fields need to be accessed on a code level, you can get and set them using the ExtraFieldPropagation static functions:
ExtraFieldPropagation.set("country-code", "FO"); // Set
String countryCode = ExtraFieldPropagation.get("country-code"); // Get
Note that the ExtraFieldPropagation setter cannot set a property not present in the defined spring.sleuth.propagation-keys so arbitrary keys won't be accepted
You can read up on the documentation for more information

Can I access request parameters in a custom Google Cloud Endpoints Authenticator?

Is there a way to get access to the request parameters in a custom com.google.api.server.spi.config.Autenticator?
I would like to authenticate my users using a token, sent as a request parameter according to https://<mydomain>/_ah/api/v1/myapi/endpoint?token=<mytoken>. Unfortunately, in this case, it is not possible to send it as a request header. Currently, I manage authentication in each endpoint (where I do have access to the request parameters, either through the HttpServletRequest object or through a named parameter) but it would be nice to decouple auth from implementation.
As I understand, Cloud Endpoints will wrap the original request in a new POST request to /_ah/spi/... but only the request headers will be accessible in the Authenticator.
It doesn't matter if the initial request to Cloud Endpoints is GET or POST.
Your understanding is correct--your request is translated such that all query parameters are injected as part of the JSON body as well. I believe the body does have the query parameter, but I'm not 100% sure on that. If you upgrade to the new Endpoints Frameworks beta, you can access it using getParameter or getParameterValues on the servlet request, as you would expect.

Is there a standard way in Spring to pass a body with a DELETE request to a REST endpoint?

I am implementing a Spring client for an existing REST API and I need to invoke a DELETE while, at the same time, passing an access token in the request body, like this:
{
"access_token": "..."
}
The problem is that, using the method that works for POST, the transmitted body is empty (I have intercepted the request body and made sure) and I cannot be authorised without this access token. This is what I am doing:
RestTemplate restTemplate = new RestTemplate();
UserRequest ur = new UserRequest(access_token);
HttpEntity<UserRequest> entity = new HttpEntity<>(ur);
restTemplate.delete(url, entity);
I have no control over the API itself, so I don't have the option of passing the token as url parameter.
Is there a way to do this in Spring, or do I have to build my own HttpUrlConnection like described for instance in this SO answer?
In the RestTemplate object in Spring there's an exchange method.
The parameters are :
the url
the method, in your case HttpMethod.DELETE
the entity (with the body you have to transmit)
the response type
some object you could pass
Hope this help

Logging Rest Assured's own headers

I'm trying to get access to the HTTP headers that are injected by Rest Assured. Spring's Mock MVC gives you access to pretty much everything via the MvcResult, and you can use this result to log pretty much anything you would like about the request and response. The only way I can see how to do this is in RestAssured is with a Filter. However, it gives you limited access to the request (you just get the RequestSpecification). I understand that it might be tricky to get access to headers that are added by the HttpClient, but it doesn't look like you can even get access to headers that are added by Rest Assured itself. For example, I can't see any OAuth related headers, nor content-type or content-length. The only headers that appear are those that were manually added using, for example, .contentType(ContentType.XML)
Is there any other way to get access to those headers? I don't need to modify the request, I just want to be able to log all of it and the headers that are injected by Rest Assured.
I found that it's possible to register your own HttpClientFactory with RestAssured:
RestAssured.config().httpClient(
HttpClientConfig.httpClientConfig().httpClientFactory(
new CustomHttpClientFactory())
So I created a new factory that returns an HTTP client into which I inject some request and response interceptors.
public class CustomHttpClientFactory extends HttpClientConfig.HttpClientFactory {
#Override
public HttpClient createHttpClient() {
DefaultHttpClient client = new DefaultHttpClient();
client.addRequestInterceptor((request, ctx) -> {
// do what you will
});
client.addResponseInterceptor((response, ctx) -> {
// do what you will
});
return client;
}
}
This gives you almost full access to manipulate the request and response. One thing to remember is that if you're going to read from the response's entity, you should first wrap it in a BufferedHttpEntity to make it re-readable:
if (response.getEntity() != null && !response.getEntity().isRepeatable()) {
response.setEntity(new BufferedHttpEntity(response.getEntity()));
}
Another problem I ran into is when trying to see the OAuth related information. When using RestAssured's OAuth functionality, it adds its own OAuthSigner interceptor to the HTTP client right before executing the request. This means that it will always be the last interceptor to be called and any interceptor you may have already injected will be called before the request ever gets signed. Because I don't really need to see the signature for now, I didn't investigate this further and I'm leaving it as an exercise for the reader. ;)

GWT RPC security, http header, authentication and requestbuilder

I am presuming that GWT RPC actually uses RequestBuilder.
Is there a way to extract the RequestBuilder instance used by my RPC service async requestor?
Actually, my question is, how do you extract the RequestBuilder instance to insert the authentication token as a http header? Is there a way to insert http headers into an RPC service request?
Even if I could insert a http header into the request, how then would the remote servlet be told to expect that auth token? Therefore, in fact, does GWT RPC provide a framework for secure authentication at all?
I am thinking the answer is NO, or at least not in a convenient way. Am I right?
I am coming from having used RestEasy in combination with RestyGWT over SSL, where we can insert headers anytime we wish. BTW, RestyGWT constructs its request to use RequestBuilder.
My actual motivation is comparing the security effectiveness between GWT RPC and GWT JAX-RS (RestyGWT + RestEasy). So if you, as the answerer, have an alternative detailed discourse comparing the security effectiveness of RPC with direct use of RequestBuilder or REST (rather than answering this question directly) please feel free to elaborate.
Am I right to presume that GWT RPC is not security friendly/effective and I should avoid using GWT RPC for secure authenticated requests?
You can have your async method return a Request or a RequestBuilder instead of void. Request allows you to abort() a pending request, whereas RequestBuilder allows you to modify the request before its sent (if you declare the return-type as RequestBuilder, you're responsible for calling send() to actually make the request).
Alternately, you can use an RpcRequestBuilder to customize the RequestBuilder for each and every call made with a specific async service proxy.
As far as I know there is no built in security solution for gwt rpc.
But If I need such authentication I would make the following steps:
1) To be able to set http headers you can make your custom request builder, as I do myself:
MyServiceAsync myService = GWT.create(MyService.class);
MyRequestBuilder myRequestBuilder = new MyRequestBuilder();
myRequestBuilder.addHeader("header", "value");
((ServiceDefTarget) serviceInstance).setRpcRequestBuilder(myRequestBuilder);
MyRequestBuilder extends RpcRequestBuilder. And inside MyRequestBuilder I override method doFinish(RequestBuilder rb) where I put my headers.
Maybe it is not a super solution, but I haven't yet found anything better.
2) For the server side I would implement the AuthenticationFilter for checking the headers and perform server side auth functions prior calling the Servlet.

Categories