spring-projects / spring-security

Spring Security
http://spring.io/projects/spring-security
Apache License 2.0
8.82k stars 5.9k forks source link

Should return www-authenticate even for "X-Requested-With: XMLHttpRequest" requests #16103

Open MartinEmrich opened 4 hours ago

MartinEmrich commented 4 hours ago

Describe the bug Since migrating to Spring Security 6, Calling APIs using simple jQuery/XHR with basic auth results in final 401 errors, despite being logged in through the browser basic auth dialog.

Analyzing the responses, they are missing the mandatory WWW-Authenticate header. Thus the browser will not attempt the (already present) basic auth credentials.

IMHO this is a bug, as that header is mandatory: https://datatracker.ietf.org/doc/html/rfc9110#name-www-authenticate

To Reproduce Implement a simple app with

    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        return http
                .csrf(AbstractHttpConfigurer::disable)
                .cors(cors -> cors.disable())
                .authorizeHttpRequests(
                        matchers -> matchers
                                .requestMatchers("/some/**", "/some/more/**", "/error/**")
                                .permitAll()
                                .requestMatchers("/api/**", "/app/**")
                                .authenticated()
                                .anyRequest().authenticated())

                .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
                .httpBasic(basic -> basic.realmName("my-realm"))
                .build();
    }
        // a valid AuthenticationProvider, too...

Expected behavior have a (valid) www-authenticate response header in all 401 responses.

Additional Info

The behaviour was first implemented here: https://github.com/spring-projects/spring-security/commit/4ef0460ef66b4417efc7999d17ebd4cd3ebce3a6#diff-0f2a9f7a8a020191e00efb336582d7d71dd46130bc4b5cbc86eba681c498751fR92

Current state: https://github.com/spring-projects/spring-security/blob/6e495b8ba9b3e5ef397fc6852ab0bc7737ec38b9/config/src/main/java/org/springframework/security/config/annotation/web/configurers/HttpBasicConfigurer.java#L106

I guess this line of code just does not explicitly put the www-authenticate header.

Workaround

My workaround is to provide a simple BasicAuthenticationEntryPoint without that special treatment for XMLHttpRequest:

        BasicAuthenticationEntryPoint basicAuthEntryPoint = new BasicAuthenticationEntryPoint();
        basicAuthEntryPoint.setRealmName(BASIC_AUTH_REALM);

and setting it in the SecurityFilterChain

                .httpBasic(basic -> basic.realmName(BASIC_AUTH_REALM).authenticationEntryPoint(basicAuthEntryPoint))
MartinEmrich commented 4 hours ago

To be precise: I do not imply it is a regression from Spring Security 5, most probaby my old WebSecurityConfigurerAdapter code did just not trigger that piece of code.