Maverick Riz Maverick Riz - 18 days ago 9
reST (reStructuredText) Question

Spring RestTemplate authorization header issues

Ok, i am loosing my mind here, i think i looked at the most of SOF questions related to this, but nothing works for me...
We are the consumers of a Rest API. I am calling a rest service, by passing the username, password and private key as URL parameters and the service will return a unique token that is valid for say 2 hrs..
Ex:https://Some-service-url/Authenticate?username=myuser&password=mypassword&privateKey=12345
Posting to the above url, returns me a string say.. abcdefghijkl+JRcQ+a0Q== which is an authorization token

Now, i need to add the above Authorization header for each of my get request..This works fine in postman and using curl but not with my Spring RestTemplate.
What i tried with curl:

curl -H "Authorization: abcdefghijkl+JRcQ+a0Q==” https://some-service-url/users?userid=1234


The above works fine..

With Spring Rest Template:

// The getAuthenticationToken() post to the authenticate service and gets the token correctly.
String authenticationToken = getAuthenticationToken();// say //abcdefghijkl+JRcQ+a0Q==
HttpHeaders headers = new HttpHeaders();
headers.set("Authorization", authenticationToken);
headers.setContentType(MediaType.APPLICATION_JSON);

HttpEntity<String> request = new HttpEntity<String>(headers);

MultiValueMap<String, String> params = new LinkedMultiValueMap<String, String>();
params.add( "userid", "1234" );

String url = "https://some-service-url/users";
restTemplate
.exchange(
url, HttpMethod.GET,
request, User.class, params );


The above codes gives a 401 unauthorized error. I looked at similar Q's here, tried adding Bearer or Basic or OAuth..

headers.set("Authorization", "Basic "+authenticationToken);
headers.set("Authorization", "Bearer "+authenticationToken);


It works on curl or postman withouth Basic or Bearer keyword.
I also read somewhere that space characters is important while setting Authorization . So i also tried,

headers.set("Authorization", " "+authenticationToken);//white space


None of the above work for me..

I always end up getting

org.springframework.web.client.HttpClientErrorException: 401 Unauthorized
at org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:76)
at org.springframework.web.client.RestTemplate.handleResponseError(RestTemplate.java:486)
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:443)
at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:409)
at org.springframework.web.client.RestTemplate.exchange(RestTemplate.java:384)
at


I am really not sure what is wrong. Appreciate your help

EDIT: Adding the restClientContext.xml

<bean name="restTemplate" class="org.springframework.web.client.RestTemplate">
<constructor-arg>
<bean class="org.springframework.http.client.CommonsClientHttpRequestFactory">
<constructor-arg ref="commonsHttpClient"/>
</bean>
</constructor-arg>
<property name="messageConverters">
<list>
<bean class="org.springframework.http.converter.StringHttpMessageConverter"/>
<bean class="org.springframework.http.converter.xml.XmlAwareFormHttpMessageConverter"/>
<bean class="org.springframework.http.converter.ResourceHttpMessageConverter"/>
<bean class="org.springframework.http.converter.ByteArrayHttpMessageConverter"/>
<bean class="org.springframework.http.converter.xml.SourceHttpMessageConverter"/>
<bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter"/>
<bean class="org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter"/>
</list>
</property>




<bean id="commonsHttpClient" class="org.apache.commons.httpclient.HttpClient">
<property name="httpConnectionManager" ref="httpConnectionManager" />














<bean id="httpConnectionManager" class="org.apache.commons.httpclient.MultiThreadedHttpConnectionManager" >
<property name="params">
<bean class="org.apache.commons.httpclient.params.HttpConnectionManagerParams">
<property name="defaultMaxConnectionsPerHost" value="50" />
<property name="maxTotalConnections" value="100" />
<property name="soTimeout" value="300000" />
</bean>
</property>




EDIT: Request object right before calling request.execute();


org.springframework.web.client.RestTemplate@4dfcedc
https://my-service/api/Rest/v1/users
GET
requestCallBack:org.springframework.web.client.RestTemplate$HttpEntityRequestCallback@66328ec4
requestEntity:<{Authorization=["z/HHrxuNRcbNZZ3PyF+EnQ==bDNWeSyzlLBGDlP2DOzzB+unEyLpjMw8N3Ootqw=="]}>
body:null
headers:{Authorization=["z/HHrxuNRcbNZZ3PyF+EnQ==bDNWeSyzlLBGDlP2DOzzB+unEyLpjMw8N3Ootqw=="]}
request:org.springframework.http.client.CommonsClientHttpRequest@15609aa5
executed:false
headers:{Accept=[application/json], Authorization=["z/HHrxuNRcbNZZ3PyF+EnQ==bDNWeSyzlLBGDlP2DOzzB+unEyLpjMw8N3Ootqw=="], Content-Length=[0]}
org.apache.commons.httpclient.HttpClient@23b1293f
org.apache.commons.httpclient.methods.GetMethod@3253b3f0

Answer

I fixed this by writing an Interceptor and passing the token.

Interceptor:

public class RestTemplateInterceptor implements ClientHttpRequestInterceptor {
private final String headerName;
private final String headerValue;
public RestTemplateInterceptor(String headerName, String headerValue)      {
       this.headerName = headerName;
       this.headerValue = headerValue;
   }
@Override
   public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
       HttpRequest wrapper = new HttpRequestWrapper(request);
       wrapper.getHeaders().set(headerName, headerValue);
       return execution.execute(wrapper, body);
   }
}

Rest client:

List<ClientHttpRequestInterceptor> interceptors = new ArrayList<ClientHttpRequestInterceptor>();
  interceptors.add(new RestTemplateInterceptor("Authorization", token));
  restTemplate.setInterceptors(interceptors);