spring-projects / spring-security

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

Oauth2 jwt not work if no Authorization attribute in http header or Authorization not start with 'Bearer ' #15844

Closed tongshushan closed 1 month ago

tongshushan commented 1 month ago

Hello, I use Oauth2 jwt connected to the keycloak server to verify the user's jwt token, but I find if there's no Authorization attribute in the http header or the no the keyword Bearer in token, the jwt validation is not working(even the token is expired), did I misconfig anything?

Below are the 3 methods to call my api , I use the expired token to test:

method 1:
curl --location 'http://localhost:8080/api/xxxx' --header 'Authorization: Bearer expiredToken' returns 401 (works as expected)

method 2, no Authorization attribute in header:
curl --location 'http://localhost:8080/api/xxxx' expected to return 401 but returns 200

method 3, the token has no Bearer : curl --location 'http://localhost:8080/api/xxxx' --header 'Authorization: expiredToken' expected to return 401 but returns 200

To Reproduce oauth2 jwt config as below(issuer-uri is the keycloak server)

spring:
  security:
    oauth2:
      resourceserver:
        jwt:
          issuer-uri: https://abcd.com/auth/realms/athena-dev
          jwk-set-uri: https://abcd.com/auth/realms/athena-dev/protocol/openid-connect/certs

oauth2 version org.springframework.security:spring-security-oauth2-resource-server:jar:5.1.2.RELEASE and org.springframework.security:spring-security-oauth2-resource-server:jar:6.2.4

rohitsirohi85 commented 1 month ago

hey i read your issue and according to your problem there is must be a wrong logic error , you have to check Security and authorization of your endpoints. Maybe you did not set the secure endpoint for api that's why is you provide no Auth it is still running , Maybe you make that api publicly accessible.

tongshushan commented 1 month ago

Hi @rohitsirohi85 , I think I have not make the api as public, because if I call the api as below,got 401, that means oauth2 works, right?

curl --location 'http://localhost:8080/api/xxxx' --header 'Authorization: Bearer expiredToken'

tongshushan commented 1 month ago

I find the root cause is this line:

httpSecurity.addFilterAfter(getMyAuthenticationRequestFilterBean(), BearerTokenAuthenticationFilter.class);

if I remove this line, will get 401 if no Authorization or Bearer .

But this line will parse and get some info from jwt token and do some bussiness logic in the Filter. So if I remove it, is there any way to do the same logic but not impact the Authorization vaidation?

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Value("${spring.mvc.servlet.path}")
    private String BASE_URL;

    @Override
    protected void configure(HttpSecurity httpSecurity) throws Exception {
        httpSecurity.csrf().ignoringAntMatchers("/**");
        // validate jwt token at first
        httpSecurity.cors().and().oauth2ResourceServer().jwt();
        httpSecurity          
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
                .authorizeRequests()
                .antMatchers(BASE_URL + "/api/xxxx").hasAnyAuthority(ADMIN)
                .anyRequest().authenticated()
                .and()
                .exceptionHandling().accessDeniedPage(BASE_URL + "/access");
        httpSecurity.addFilterAfter(getMyAuthenticationRequestFilterBean(), BearerTokenAuthenticationFilter.class);
        httpSecurity.headers().cacheControl();
    }
....
}
sjohnr commented 1 month ago

Thanks for getting in touch @tongshushan, but it feels like this is a question that would be better suited to Stack Overflow. We prefer to use GitHub issues only for bugs and enhancements. Feel free to update this issue with a link to the re-posted question (so that other people can find it) or add a minimal sample that reproduces this issue if you feel this is a genuine bug.

Having said that, please review the documentation for OAuth2 Resource Server with JWT which has many examples for how to customize without using a custom filter.

rohitsirohi85 commented 1 month ago

So sorry for so much late reply bro , have you got the answer for your error ?

On Tue, 15 Oct 2024, 10:11 pm Steve Riesenberg, @.***> wrote:

Thanks for getting in touch @tongshushan https://github.com/tongshushan, but it feels like this is a question that would be better suited to Stack Overflow https://stackoverflow.com/questions/tagged/spring-security. We prefer to use GitHub issues only for bugs and enhancements. Feel free to update this issue with a link to the re-posted question (so that other people can find it) or add a minimal sample https://stackoverflow.com/help/minimal-reproducible-example that reproduces this issue if you feel this is a genuine bug.

Having said that, please review the documentation for OAuth2 Resource Server https://docs.spring.io/spring-security/reference/servlet/oauth2/resource-server/index.html with JWT https://docs.spring.io/spring-security/reference/servlet/oauth2/resource-server/jwt.html which has many examples for how to customize without using a custom filter.

— Reply to this email directly, view it on GitHub https://github.com/spring-projects/spring-security/issues/15844#issuecomment-2414511999, or unsubscribe https://github.com/notifications/unsubscribe-auth/BICV4EIARXWBN2ANTI6TD2DZ3VAS7AVCNFSM6AAAAABOYGWKM2VHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDIMJUGUYTCOJZHE . You are receiving this because you were mentioned.Message ID: @.***>

tongshushan commented 1 month ago

Hello, I have found that if the Authorization in header is not started with 'Bearer', then the oauth2 BearerTokenAuthenticationFilter will skip the keycloak validation and pass the request to the next filter: https://github.com/spring-projects/spring-security/blob/5.1.x/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/web/DefaultBearerTokenResolver.java#L90

https://github.com/spring-projects/spring-security/blob/5.1.x/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/web/BearerTokenAuthenticationFilter.java#L97

We have to validate the token again in our customized filter, if no Authorization or the token not started with 'Bearer' then return 401.

It's resolved now, thank you.