Reputation: 1217
Good day.
I am using Spring security in context of Spring boot auto-configured application. My goal is to set up basic auth in such way that standard browser's basic auth form is not shown on 401. From the Google I found out that to achieve it I need to change the default "WWW-Authenticate" header to something different than "Basic xxxxx".
To do that, I declared a filter:
@Bean
@Order(Integer.MAX_VALUE)
public Filter customAuthFilter() {
return new Filter() {
@Override
public void init(FilterConfig fc) throws ServletException {
}
@Override
public void doFilter(ServletRequest sreq, ServletResponse sresp, FilterChain fc) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) sreq;
HttpServletResponse resp = (HttpServletResponse) sresp;
fc.doFilter(req, resp);
log.info("filter");
log.info("status " + resp.getStatus());
if(resp.getStatus() == 401) {
resp.setHeader("WWW-Authenticate", "Client-driven");
}
}
@Override
public void destroy() {
}
};
From the logs I see that my filter successfully recognized by the application and takes participation in processing responses (I see the log messages from doFilter). But the actual response, received by browser, still contains the standard 'WWW-Authenticate' header. It seems that someone overrides my header, by I don't have a clue who it is exactly.
Could someone give an advice please?
Upvotes: 6
Views: 6535
Reputation: 419
Just add "X-Requested-With: XMLHttpRequest" in request header(Tested in Spring Security 4.2.2.RELEASE).
For details, HttpBasicConfigurer worth to be looking up.
Below is my test result using CURL:
hanxideMacBook-Pro:~ hanxi$ curl -u "13980547109:xxx" -v -d "" -H "X-Requested-With: XMLHttpRequest" http://sales.huoxingy.com/api/v1/sales/login
* Trying 101.37.135.20...
* TCP_NODELAY set
* Connected to sales.huoxingy.com (101.37.135.20) port 80 (#0)
* Server auth using Basic with user '13980547109'
> POST /api/v1/sales/login HTTP/1.1
> Host: sales.huoxingy.com
> Authorization: Basic MTM5ODA1NDcxMDk6MTIzNDU2
> User-Agent: curl/7.54.0
> Accept: */*
> X-Requested-With: XMLHttpRequest
> Content-Length: 0
> Content-Type: application/x-www-form-urlencoded
>
< HTTP/1.1 200
< Server: nginx/1.12.1
< Date: Thu, 21 Sep 2017 01:43:13 GMT
< Content-Length: 0
< X-Content-Type-Options: nosniff
< X-XSS-Protection: 1
< Cache-Control: no-cache, no-store, max-age=0, must-revalidate
< Pragma: no-cache
< Expires: 0
< X-Frame-Options: DENY
< X-XSS-Protection: ; mode=block
< x-auth-token: 2f595113-cdba-4394-8ca0-bcd72239bea5
< Set-Cookie: CONTAINERID=efc390abdb189a10c55e0672b07cfe1c7d665be4db9ad40e122475e5cdff605d; path=/
Upvotes: 0
Reputation: 1217
Solved the problem by using custom EntryPoint:
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/rest/**").authenticated()
.and().httpBasic().authenticationEntryPoint(new AuthenticationEntryPoint() {
@Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
String requestedBy = request.getHeader("X-Requested-By");
log.info("X-Requested-By: " + requestedBy);
if(requestedBy == null || requestedBy.isEmpty()) {
HttpServletResponse httpResponse = (HttpServletResponse) response;
httpResponse.addHeader("WWW-Authenticate", "Basic realm=Cascade Realm");
httpResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED, authException.getMessage());
} else {
HttpServletResponse httpResponse = (HttpServletResponse) response;
httpResponse.addHeader("WWW-Authenticate", "Application driven");
httpResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED, authException.getMessage());
}
}
});
}
Upvotes: 8
Reputation: 58114
The Spring Security filter will be added with lowest priority as well, so probably it's upstream of yours. You could try a lower order. The conventional way to handle 401 responses is with an AuthenticationFailureHandler
but I suppose I can see why you might do it this way, given that the basic auth is already there.
Upvotes: 2