Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

RestTemplate not passing Origin header

I'm trying to make a cross-origin request using Spring's RestTemplate. The communication is done between two Spring-boot webapps, both running on localhost but different port. What I do is:

HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.setOrigin("http://localhost:8083");
httpHeaders.add("Authorization", token);

HttpEntity<Void> httpEntity = new HttpEntity<>(httpHeaders);

ParameterizedTypeReference<List<MyObj>> beanType = new ParameterizedTypeReference<List<MyObj>>() {};
ResponseEntity<List<MyObj>> list = restTemplate.exchange(serviceURL, HttpMethod.GET, httpEntity, beanType);

The call is executed, the "Authorization" header is passed just fine, but no matter what I try, there is no "Origin" header on the receiving side. When I create a simillar request using some other tool (SoapUI, RestClient Chrome plugin, etc.) the header is passed just as I provide it.

To print all headers on the receiving side I'm using a implementation of javax.servlet.Filter with:

public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
        throws IOException, ServletException {
    HttpServletRequest request = (HttpServletRequest) req;
    HttpServletResponse response = (HttpServletResponse) res;
    Enumeration<String> headerNames = request.getHeaderNames();
    while (headerNames.hasMoreElements()) {
        String headerName = headerNames.nextElement();
        log.info(headerName + ": " + request.getHeader(headerName));
    }
}

Why is the origin header not passed when using RestTemplate?

like image 268
Krzysztof Ś Avatar asked Jan 17 '17 14:01

Krzysztof Ś


1 Answers

Had the same problem which I spent a century to fix.

The root cause is this line from the RestTemplate documentation

Note: by default the RestTemplate relies on standard JDK facilities to establish HTTP connections.

If you check source code of HttpUrlConnection class in Java, you'll find below block of code, and header Origin is one of the restricted headers that forbid changes:

/*
 * Restrict setting of request headers through the public api
 * consistent with JavaScript XMLHttpRequest2 with a few
 * exceptions. Disallowed headers are silently ignored for
 * backwards compatibility reasons rather than throwing a
 * SecurityException. For example, some applets set the
 * Host header since old JREs did not implement HTTP 1.1.
 * Additionally, any header starting with Sec- is
 * disallowed.
 *
 * The following headers are allowed for historical reasons:
 *
 * Accept-Charset, Accept-Encoding, Cookie, Cookie2, Date,
 * Referer, TE, User-Agent, headers beginning with Proxy-.
 *
 * The following headers are allowed in a limited form:
 *
 * Connection: close
 *
 * See http://www.w3.org/TR/XMLHttpRequest2.
 */
 private static final boolean allowRestrictedHeaders;
 private static final Set<String> restrictedHeaderSet;
 private static final String[] restrictedHeaders = {
    /* Restricted by XMLHttpRequest2 */
    //"Accept-Charset",
    //"Accept-Encoding",
    "Access-Control-Request-Headers",
    "Access-Control-Request-Method",
    "Connection", /* close is allowed */
    "Content-Length",
    //"Cookie",
    //"Cookie2",
    "Content-Transfer-Encoding",
    //"Date",
    //"Expect",
    "Host",
    "Keep-Alive",
    "Origin",
    // "Referer",
    // "TE",
    "Trailer",
    "Transfer-Encoding",
    "Upgrade",
    //"User-Agent",
    "Via"
};

There is a easy fix to this problem, just to set a JVM argument

-Dsun.net.http.allowRestrictedHeaders=true 

or add a line in your code

System.setProperty("sun.net.http.allowRestrictedHeaders", "true");

which suppress the restriction.

like image 117
Cady Avatar answered Sep 24 '22 13:09

Cady