skapral
skapral

Reputation: 1217

Spring boot + Spring Security: how to suppress the basic auth form

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

Answers (3)

freeman
freeman

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

skapral
skapral

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

Dave Syer
Dave Syer

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

Related Questions