I have a small Rest-Service App (Java 8, Spring 4.1.6, Spring Security 5.0.1, Jetty 9.3) and i'am accessing some services by JSON using Spring RestTemplate. Until now csfr was disabled, now i want to enable it.
As is understood csfr there is a common token (the client sends it with each request, the server stores it in the session) which is compared on server side. Access is denied if there is no token available or the token is different.
So i thought it would be a good idea to do this token-adding by using an interceptor. I also read, that in json i have to send the token as a header-parameter... but i did something wrong, already the login fails.
Here is the login-source:
MultiValueMap form = new LinkedMultiValueMap<>();
form.add("username", username);
form.add("password", password);
return restTemplate.postForLocation(serverUri + "login", form);
Here the source of the interceptor:
import java.io.IOException;
import java.util.UUID;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpRequest;
import org.springframework.http.client.ClientHttpRequestExecution;
import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.http.client.ClientHttpResponse;
public class MyCsfrInterceptor implements ClientHttpRequestInterceptor{
public static final String CSRF_TOKEN_HEADER_NAME = "X-CSRF-TOKEN";
public static final String csrfSessionToken = UUID.randomUUID().toString();
private static Logger LOG = LoggerFactory.getLogger(MyCsfrInterceptor.class);
@Override
public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
LOG.info("My interceptor called!");
if (request.getMethod() == HttpMethod.DELETE ||
request.getMethod() == HttpMethod.POST ||
request.getMethod() == HttpMethod.PATCH ||
request.getMethod() == HttpMethod.PUT){
LOG.info("Setting csrf token...");
request.getHeaders().add(CSRF_TOKEN_HEADER_NAME, csrfSessionToken);
}
return execution.execute(request, body);
}
}
Here is the log output on client side:
23:24:40.605 [main] DEBUG c.m.l.w.client.StatefulRestTemplate - Created POST request for "http://localhost:8080/login"
23:24:40.610 [main] DEBUG c.m.l.w.client.StatefulRestTemplate - Writing [{username=[user], password=[user]}] using [org.springframework.http.converter.support.AllEncompassingFormHttpMessageConverter@618b19ad]
23:24:40.615 [main] INFO c.m.l.w.client.MyCsfrInterceptor - My interceptor called!
23:24:40.615 [main] INFO c.m.l.w.client.MyCsfrInterceptor - Setting csrf token...
23:24:40.650 [main] DEBUG o.a.h.c.protocol.RequestAddCookies - CookieSpec selected: best-match
23:24:40.670 [main] DEBUG o.a.h.c.protocol.RequestAuthCache - Auth cache not set in the context
23:24:40.675 [main] DEBUG o.a.h.i.c.PoolingHttpClientConnectionManager - Connection request: [route: {}->http://localhost:8080][total kept alive: 0; route allocated: 0 of 2; total allocated: 0 of 20]
23:24:40.705 [main] DEBUG o.a.h.i.c.PoolingHttpClientConnectionManager - Connection leased: [id: 0][route: {}->http://localhost:8080][total kept alive: 0; route allocated: 1 of 2; total allocated: 1 of 20]
23:24:40.710 [main] DEBUG o.a.h.impl.execchain.MainClientExec - Opening connection {}->http://localhost:8080
23:24:40.715 [main] DEBUG o.a.h.i.c.HttpClientConnectionOperator - Connecting to localhost/127.0.0.1:8080
23:24:40.715 [main] DEBUG o.a.h.i.c.HttpClientConnectionOperator - Connection established 127.0.0.1:54712127.0.0.1:8080
23:24:40.715 [main] DEBUG o.a.h.impl.execchain.MainClientExec - Executing request POST /login HTTP/1.1
23:24:40.715 [main] DEBUG o.a.h.impl.execchain.MainClientExec - Target auth state: UNCHALLENGED
23:24:40.720 [main] DEBUG o.a.h.impl.execchain.MainClientExec - Proxy auth state: UNCHALLENGED
23:24:40.720 [main] DEBUG org.apache.http.headers - http-outgoing-0 >> POST /login HTTP/1.1
23:24:40.720 [main] DEBUG org.apache.http.headers - http-outgoing-0 >> Content-Type: application/x-www-form-urlencoded
23:24:40.720 [main] DEBUG org.apache.http.headers - http-outgoing-0 >> X-CSRF-TOKEN: 99ca8171-b8e0-4b95-8d06-3759a874c64b
23:24:40.720 [main] DEBUG org.apache.http.headers - http-outgoing-0 >> Content-Length: 27
23:24:40.720 [main] DEBUG org.apache.http.headers - http-outgoing-0 >> Host: localhost:8080
23:24:40.720 [main] DEBUG org.apache.http.headers - http-outgoing-0 >> Connection: Keep-Alive
23:24:40.720 [main] DEBUG org.apache.http.headers - http-outgoing-0 >> User-Agent: Apache-HttpClient/4.3.4 (java 1.5)
23:24:40.720 [main] DEBUG org.apache.http.headers - http-outgoing-0 >> Accept-Encoding: gzip,deflate
23:24:40.720 [main] DEBUG org.apache.http.wire - http-outgoing-0 >> "POST /login HTTP/1.1[\r][\n]"
23:24:40.720 [main] DEBUG org.apache.http.wire - http-outgoing-0 >> "Content-Type: application/x-www-form-urlencoded[\r][\n]"
23:24:40.720 [main] DEBUG org.apache.http.wire - http-outgoing-0 >> "X-CSRF-TOKEN: 99ca8171-b8e0-4b95-8d06-3759a874c64b[\r][\n]"
23:24:40.720 [main] DEBUG org.apache.http.wire - http-outgoing-0 >> "Content-Length: 27[\r][\n]"
23:24:40.720 [main] DEBUG org.apache.http.wire - http-outgoing-0 >> "Host: localhost:8080[\r][\n]"
23:24:40.720 [main] DEBUG org.apache.http.wire - http-outgoing-0 >> "Connection: Keep-Alive[\r][\n]"
23:24:40.720 [main] DEBUG org.apache.http.wire - http-outgoing-0 >> "User-Agent: Apache-HttpClient/4.3.4 (java 1.5)[\r][\n]"
23:24:40.720 [main] DEBUG org.apache.http.wire - http-outgoing-0 >> "Accept-Encoding: gzip,deflate[\r][\n]"
23:24:40.720 [main] DEBUG org.apache.http.wire - http-outgoing-0 >> "[\r][\n]"
23:24:40.720 [main] DEBUG org.apache.http.wire - http-outgoing-0 >> "username=user&password=user"
23:24:40.831 [main] DEBUG org.apache.http.wire - http-outgoing-0 << "HTTP/1.1 403 Expected CSRF token not found. Has your session expired?[\r][\n]"
23:24:40.831 [main] DEBUG org.apache.http.wire - http-outgoing-0 << "Date: Sat, 15 Aug 2015 21:24:40 GMT[\r][\n]"
23:24:40.831 [main] DEBUG org.apache.http.wire - http-outgoing-0 << "Pragma: no-cache[\r][\n]"
23:24:40.831 [main] DEBUG org.apache.http.wire - http-outgoing-0 << "X-XSS-Protection: 1; mode=block[\r][\n]"
23:24:40.831 [main] DEBUG org.apache.http.wire - http-outgoing-0 << "X-Frame-Options: DENY[\r][\n]"
23:24:40.831 [main] DEBUG org.apache.http.wire - http-outgoing-0 << "X-Content-Type-Options: nosniff[\r][\n]"
23:24:40.831 [main] DEBUG org.apache.http.wire - http-outgoing-0 << "Set-Cookie: JSESSIONID=1bvmexep1lv9h1qja44hflx0wg;Path=/[\r][\n]"
23:24:40.831 [main] DEBUG org.apache.http.wire - http-outgoing-0 << "Content-Type: text/html;charset=iso-8859-1[\r][\n]"
23:24:40.831 [main] DEBUG org.apache.http.wire - http-outgoing-0 << "Cache-Control: must-revalidate,no-cache,no-store[\r][\n]"
23:24:40.831 [main] DEBUG org.apache.http.wire - http-outgoing-0 << "Content-Length: 409[\r][\n]"
23:24:40.831 [main] DEBUG org.apache.http.wire - http-outgoing-0 << "Server: Jetty(9.3.0.RC1)[\r][\n]"
23:24:40.831 [main] DEBUG org.apache.http.wire - http-outgoing-0 << "[\r][\n]"
23:24:40.831 [main] DEBUG org.apache.http.wire - http-outgoing-0 << "[\n]"
23:24:40.831 [main] DEBUG org.apache.http.wire - http-outgoing-0 << "
[\n]"23:24:40.831 [main] DEBUG org.apache.http.wire - http-outgoing-0 << "[\n]"
23:24:40.831 [main] DEBUG org.apache.http.wire - http-outgoing-0 << "
Error 403 Expected CSRF token not found. Has your session expired?[\n]"23:24:40.831 [main] DEBUG org.apache.http.wire - http-outgoing-0 << "[\n]"
23:24:40.831 [main] DEBUG org.apache.http.wire - http-outgoing-0 << "
HTTP ERROR 403
[\n]"23:24:40.831 [main] DEBUG org.apache.http.wire - http-outgoing-0 << "
Problem accessing /login. Reason:[\n]"
23:24:40.831 [main] DEBUG org.apache.http.wire - http-outgoing-0 << "
Expected CSRF token not found. Has your session expired?
Powered by Jetty:// 9.3.0.RC1
[\n]"
23:24:40.831 [main] DEBUG org.apache.http.wire - http-outgoing-0 << "[\n]"
23:24:40.831 [main] DEBUG org.apache.http.wire - http-outgoing-0 << "[\n]"
23:24:40.831 [main] DEBUG org.apache.http.wire - http-outgoing-0 << "[\n]"
23:24:40.836 [main] DEBUG org.apache.http.headers - http-outgoing-0 << HTTP/1.1 403 Expected CSRF token not found. Has your session expired?
23:24:40.836 [main] DEBUG org.apache.http.headers - http-outgoing-0 << Date: Sat, 15 Aug 2015 21:24:40 GMT
23:24:40.836 [main] DEBUG org.apache.http.headers - http-outgoing-0 << Pragma: no-cache
23:24:40.836 [main] DEBUG org.apache.http.headers - http-outgoing-0 << X-XSS-Protection: 1; mode=block
23:24:40.836 [main] DEBUG org.apache.http.headers - http-outgoing-0 << X-Frame-Options: DENY
23:24:40.836 [main] DEBUG org.apache.http.headers - http-outgoing-0 << X-Content-Type-Options: nosniff
23:24:40.836 [main] DEBUG org.apache.http.headers - http-outgoing-0 << Set-Cookie: JSESSIONID=1bvmexep1lv9h1qja44hflx0wg;Path=/
23:24:40.836 [main] DEBUG org.apache.http.headers - http-outgoing-0 << Content-Type: text/html;charset=iso-8859-1
23:24:40.836 [main] DEBUG org.apache.http.headers - http-outgoing-0 << Cache-Control: must-revalidate,no-cache,no-store
23:24:40.836 [main] DEBUG org.apache.http.headers - http-outgoing-0 << Content-Length: 409
23:24:40.836 [main] DEBUG org.apache.http.headers - http-outgoing-0 << Server: Jetty(9.3.0.RC1)
23:24:40.846 [main] DEBUG o.a.h.impl.execchain.MainClientExec - Connection can be kept alive indefinitely
23:24:40.861 [main] DEBUG o.a.h.c.p.ResponseProcessCookies - Cookie accepted [JSESSIONID="1bvmexep1lv9h1qja44hflx0wg", version:0, domain:localhost, path:/, expiry:null]
23:24:40.861 [main] DEBUG c.m.l.w.client.StatefulRestTemplate - POST request for "http://localhost:8080/login" resulted in 403 (Expected CSRF token not found. Has your session expired?); invoking error handler
23:24:40.866 [main] DEBUG o.a.h.i.c.PoolingHttpClientConnectionManager - Connection [id: 0][route: {}->http://localhost:8080] can be kept alive indefinitely
In spring security config i didn't do any csrf configuration.
So what's wrong? Did i set the header wrong? Any config missing?
Best regards and thank you for your time.