Summary
When http basic auth is used and the request has an 'X-Requested-With: XMLHttpRequest' header set the server still responds with www-authenticate when credentials are wrong
Actual Behavior
- http basic auth is configured and working
- Javascript client calls
/api/userwith http basic auth credentials that are wrong - server responds with 401 and www-authenticate header set
- browser opens basic auth popup
Expected Behavior
The Server should not add the 'www-authenticate' header
Configuration
@EnableWebFluxSecurity
public class SecurityConfig {
@Bean
SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) {
return http
.csrf().disable()
.authorizeExchange()
.pathMatchers("/*").permitAll()
.pathMatchers("/api/*").authenticated()
.and().httpBasic()
.and()
.build();
}
@Bean
ReactiveUserDetailsService userDetailService(PasswordEncoder encoder) {
User.UserBuilder user = User.withUsername("username")
.roles(USER)
.password(encoder.encode("password"));
return new MapReactiveUserDetailsService(user.build());
}
@Bean
PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
Version
./gradlew dI --dependency spring-boot-starter-security
:dependencyInsight
org.springframework.boot:spring-boot-starter-security:2.0.0.RELEASE (selected by rule)
org.springframework.boot:spring-boot-starter-security: -> 2.0.0.RELEASE
\--- compileClasspath
Sample
curl 'http://localhost:8080/api/user' -u user:wrong_pass -H 'X-Requested-With: XMLHttpRequest' -v
* Trying ::1...
* TCP_NODELAY set
* Connected to localhost (::1) port 8080 (#0)
* Server auth using Basic with user 'user'
> GET /api/user HTTP/1.1
> Host: localhost:8080
> Authorization: Basic dXNlcjp3cm9uZ19wYXNz
> User-Agent: curl/7.59.0
> Accept: */*
> X-Requested-With: XMLHttpRequest
>
< HTTP/1.1 401 Unauthorized
* Authentication problem. Ignoring this.
< WWW-Authenticate: Basic realm="Realm"
< Cache-Control: no-cache, no-store, max-age=0, must-revalidate
< Pragma: no-cache
< Expires: 0
< X-Content-Type-Options: nosniff
< X-Frame-Options: DENY
< X-XSS-Protection: 1 ; mode=block
< content-length: 0
<
* Connection #0 to host localhost left intact
Comment From: zpf7879
I am facing the same issue. Any workaround?
Comment From: rwinch
A workaround is that you can provide a custom ServerAuthenticationEntryPoint via:
http
.exceptionHandling()
.authenticationEntryPoint(customEntryPoint);
Comment From: zpf7879
Exactly, I found out the same solution but thanks anyway:
.exceptionHandling()
.authenticationEntryPoint((exchange, denied) -> {
ServerHttpResponse response = exchange.getResponse();
response.setStatusCode(HttpStatus.UNAUTHORIZED);
List<String> requestedWith = exchange.getRequest().getHeaders().get("X-Requested-With");
if (requestedWith == null || !requestedWith.contains("XMLHttpRequest")) {
response.getHeaders().set(WWW_AUTHENTICATE,
String.format(WWW_AUTHENTICATE_FORMAT, DEFAULT_REALM));
}
exchange.mutate().response(response);
return Mono.empty();
})
`
**Comment From: vnobo**
I am facing the same issue. Any workaround?
@zpf7879 I still get it when I make a mistake
**Comment From: vnobo**
@rwinch hi, Now when I don't certify it, it's normal.
But when I add certification "Authorization: Basic YWRtaW46MzIxMzIxMzE=" wrong password ,It reappeared
return response :
`HTTP/1.1 401 Unauthorized
X-Powered-By: Express
www-authenticate: Basic realm="Realm"
cache-control: no-cache, no-store, max-age=0, must-revalidate
pragma: no-cache
expires: 0
x-content-type-options: nosniff
x-frame-options: DENY
x-xss-protection: 1 ; mode=block
referrer-policy: no-referrer
content-length: 0
connection: close
Date: Tue, 03 Sep 2019 08:57:15 GMT`
Now I don't know what to do. Could you help me? Thank you very much
**Comment From: rwinch**
@vnobo Since 5.2.0.M1 (see gh-6270) you can configure an entry point for the failures.
```java
http
.httpBasic()
.authenticationEntryPoint(custom)
Comment From: gdadon
I faced this same issue, except I've disabled the basic auth in the filters via
httpBasic().disable()
in my case, I've removed this header during Nginx response with hide header.
Comment From: meredrica
We gave up on Spring and switched to Micronaut.