version org.springframework.boot:spring-boot-starter-security:3.0.3-SNAPSHOT which comes with spring-security 6.0.1

Describe the bug

when using authorizeHttpRequests instead of the deprecated authorizeRequests the AuthenticationProvider is not used / basically ignored.

To Reproduce Download linked repository and switch the commented code with the uncommented in SecurityConfig then call http://localhost:8080/secure

                // using this works 200
            .authorizeRequests {
                it.requestMatchers("/unsecure").permitAll()
                it.anyRequest().authenticated()
            }

                // this block causes 403
//            .authorizeHttpRequests {
//                it.requestMatchers("/unsecure").permitAll()
//                it.anyRequest().authenticated()
//            }

Expected behavior authorizeHttpRequests and authorizeRequests should behave the same.

Sample

A link to a GitHub repository

Comment From: elFarto

I've also just encountered this issue. As authorizeHttpRequests is denoted as the replacement for authorizeRequests I would have expected the same behaviour between them.

Comment From: marcusdacoregio

Hi @zotornit, thanks for the report.

The reason that it is happening is that the FilterSecurityInterceptor (authorizeRequests()) authenticates the request if not authenticated yet before checking the authorization rules, while the AuthorizationFilter (authorizeHttpRequests()) doesn't do that, the responsibility to authenticate the request is delegated to the authentication mechanisms.

One thing that I don't understand completely is that if you do not have any authentication mechanism configured how do you want the requests to be authenticated? The EverybodyAuthenticationFilter does not use the AuthenticationProvider or the AuthenticationManager, in the same note, the EverybodyAuthenticationFilter creates an unauthenticated Authentication object.

I don't think this can be considered as a bug with the scenario provided, therefore I'm closing this for the time being. Feel free to the conversation going.

Comment From: elFarto

We are doing API Key authentication using a filter to extract out the relevant header, something like this:

          .authenticationProvider(apiKeyAuthenticationProvider)
          .authorizeRequests() 
          .anyRequest().fullyAuthenticated()
          .and()
          .addFilterBefore(apiKeyFilter, BasicAuthenticationFilter.class);

This has worked fine up until now.

My question is, how would I tell Spring Security that I need my request authenticated when not using the normal formLogin or httpBasic login method? I don't see any obvious alternative method to use.

Comment From: marcusdacoregio

Your apiKeyFilter could extract the Authentication from the request and pass that Authentication to the an AuthenticationProvider.

I believe your use case is something like:

  1. Extract the API Key from the request
  2. Compare it against what you have stored somewhere, it can be an AuthenticationProvider or it can be any other component
  3. If valid, create an authenticated Authentication and set it in the SecurityContextHolder.
  4. If not valid, throws an exception.

The bolded item is what I think you don't have but should.

Comment From: zotornit

One thing that I don't understand completely is that if you do not have any authentication mechanism configured how do you want the requests to be authenticated? The EverybodyAuthenticationFilter does not use the AuthenticationProvider or the AuthenticationManager, in the same note, the EverybodyAuthenticationFilter creates an unauthenticated Authentication object.

ok thanks, but this kinda confuses me now.

Till now, I thought the AuthenticationProvider is triggered when the SecurityContext contains an Authentication object which would return false when isAuthenticated() is called. In this case all available AuthenticationProvider will be called depending on whether supports() returns true. If so, the AuthenticationProvider checks the unauthorized Authentication and creates a new one which is authenticated. (For example Authentication.getCredentials returns JWT token, AuthenticationProvider validates token, returns Authentication with authorities and stuff.)

This is how it worked for me so far for years. A lot of videos/articles do basically explain it that way. Are they mistaken?

Like here: https://youtu.be/iJ2muJniikY?t=5437 (4 minutes to watch from timestamp)

In my real world case the app has two custome! AuthenticationFilter: 1) BearerTokenFilter 2) QueryParamTokenFilter both create an unauthenticated Authentication with token as getCredentials and the AuthenticationProvider handles the verification.

the responsibility to authenticate the request is delegated to the authentication mechanisms.

Well, how would I add such an authentication mechanism?

Comment From: zotornit

  1. Compare it against what you have stored somewhere, it can be an AuthenticationProvider or it can be any other component

The bolded item is what I think you don't have but should.

Well this is probably the way I will go. Call the CustomAuthenticationVerifier (which currently is a AuthenticationProvider manually from the AuthenticationFilter

Comment From: marcusdacoregio

Well, how would I add such an authentication mechanism?

You have your custom mechanism, it's an API Key authentication AFAICT, the way that you do that is totally up to the use case.

Till now, I thought the AuthenticationProvider is triggered when the SecurityContext contains an Authentication object ...

Not really, the authentication mechanisms, like BasicAuthenticationFilter, BearerTokenAuthenticationFilter, UsernamePasswordAuthenticationFilter, etc, all of them call the AuthenticationManager, which often is ProviderManager, that iterates through a list of AuthenticationProvider and checks if any of them returns a non-null Authentication. The link that you have explains exactly what I'm saying.

In my real world case the app has two AuthenticationFilter:

In that case, each of your filters should call the AuthenticationManager instead of relying on the FilterSecurityInterceptor.

Some background that @jzheaux gave me:

In the past, the FilterSecurityInterceptor used to run without authentication filters, that's why it has the authenticateIfRequired method but that is no longer the case. Apps should not be combining authentication and authorization in this way any longer. Authentication should happen earlier in the filter chain.

Comment From: zotornit

@marcusdacoregio Thanks, this helps.

Comment From: ctonsing

Till now, I thought the AuthenticationProvider is triggered when the SecurityContext contains an Authentication object which would return false when isAuthenticated() is called. In this case all available AuthenticationProvider will be called depending on whether supports() returns true. If so, the AuthenticationProvider checks the unauthorized Authentication and creates a new one which is authenticated. (For example Authentication.getCredentials returns JWT token, AuthenticationProvider validates token, returns Authentication with authorities and stuff.)

@zotornit that is exactly what I also understood from previous research...

@marcusdacoregio thank you for clarifying.

Comment From: GameScripting

I am also working on migrating to Spring Boot 3 / Spring Security 6. I also find this very confusing.

Well this is probably the way I will go. Call the CustomAuthenticationVerifier (which currently is a AuthenticationProvider manually from the AuthenticationFilter

@zotornit so based on your example repo, is this the way that you ended up implementing it? (Please also see my comment for more context) https://github.com/GameScripting/spring-security-3-issue/commit/5bbf673ccacf317f17a4a90f2e149bdb0f6130ba#r121615297

--

@marcusdacoregio Is there any example code available for spring security 6 where an AuthenticationProvider is used?

If AuthenticationProvider should not be used anymore (?) and instead everything should be handled in the RequestFilter directly, why does HttpSecurity.authenticationProvider() even allow me to register an AuthenticationProvider (example), if AuthenticationProvider.authenticate() will not be called anyway?

Is there a code example with a valid use-case for using HttpSecurity.authenticationProvider() ?

--

For anyone else reading this, also see this "Migrating from authorizeRequests" guide. Even though it did not help me fully understand the problem/solution, I feel like its highly relevant. https://docs.spring.io/spring-security/reference/servlet/authorization/authorize-http-requests.html grafik

Comment From: GameScripting

If AuthenticationProvider should not be used anymore (?) and instead everything should be handled in the RequestFilter directly, why does HttpSecurity.authenticationProvider() even allow me to register an AuthenticationProvider (example), if AuthenticationProvider.authenticate() will not be called anyway?

Maybe it's for cases, where the deprecated HttpSecurity.authorizeRequests() is used instead of the new HttpSecurity.authorizeHttpRequests().

Comment From: marcusdacoregio

Hi @GameScripting, the HttpSecurity#authenticationProvider is used to add more AuthenticationProviders to be used within the built-in authentication mechanisms, like formLogin() and httpBasic().

If you are creating a custom mechanism, it's up to you if you want to use the AuthenticationManager, and, if so, you have to construct it yourself.