.antMatchers(). permitAll() does not seem to work

Asked

Viewed 3,143 times

3

Edit02

Habilitei spring-security in my project, and now every API needs authentication, perfect was what I needed.

But I want only one API not to need authentication. I tried to use .authorizeRequests() .antMatchers(HttpMethod.GET, "/usuario/informacoes/**") .permitAll()

but it doesn’t work and I keep getting:

This XML file does not appear to have any style information associated with it. The document tree is shown below.
<oauth>
<error_description>
Full authentication is required to access this resource
</error_description>
<error>unauthorized</error>
</oauth>

Researching found many articles, and the vast majority suggest in this way:

https://www.baeldung.com/spring-security-expressions

https://www.baeldung.com/security-none-filters-none-access-permitAll

https://docs.spring.io/spring-security/site/docs/current/reference/html/jc.html

I have the following code:

Websecurityconfigureradapter


import org.springframework.context.annotation.Bean;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;



@EnableWebSecurity
@EnableAuthorizationServer
@EnableResourceServer
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Bean
    @Override
    protected AuthenticationManager authenticationManager() throws Exception {
        return super.authenticationManager();
    }

    protected void configure(HttpSecurity http, WebSecurity web) throws Exception {
        protected void configure(HttpSecurity http) throws Exception {

        System.out.println("Chamou HttpSecurity");

          http.csrf().disable()
            .authorizeRequests()
                .antMatchers(HttpMethod.GET, "/usuario/informacoes/*")
                .permitAll()
            .anyRequest()
                .authenticated();
    }
}

    @Override
    public void configure(WebSecurity web) throws Exception {
        web
            .ignoring().antMatchers("/favicon.ico");
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

}

API

@RestController
@RequestMapping("/usuario")

@RequestMapping(value = "/informacoes/{id}", method = RequestMethod.GET)
    public ResponseEntity<Object[]> informacoesUsuario(@Valid @PathVariable("id") Long id) throws Exception {

        Object[] response = usuarioServices.informacoesUsuario(id);

        return ResponseEntity.status(HttpStatus.OK).body(response);
    }

Securitycorsfilter

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;

import org.springframework.stereotype.Component;

@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class SecurityCORSFilter implements Filter {

    public void init(FilterConfig fc) throws ServletException {
    }

    public void doFilter(ServletRequest req, ServletResponse resp,
                         FilterChain chain) throws IOException, ServletException {

        System.out.println("Chamou SecurityCORSFilter");
        HttpServletResponse response = (HttpServletResponse) resp;
        HttpServletRequest request = (HttpServletRequest) req;
        response.setHeader("Access-Control-Allow-Origin", "*");
        response.setHeader("Access-Control-Allow-Headers", "authorization, Content-Type");

        if ("OPTIONS".equalsIgnoreCase(request.getMethod())) {
            response.setStatus(HttpServletResponse.SC_OK);
        } else {
            chain.doFilter(req, resp);
        }
    }
}

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.5.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.mfac</groupId>
    <artifactId>mfac</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>mfac</name>
    <description>mfac - rest</description>

    <properties>
        <java.version>12</java.version>
    </properties>

    <dependencies>

        <!-- Segurança | Início -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-oauth2-client</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.security.oauth.boot</groupId>
            <artifactId>spring-security-oauth2-autoconfigure</artifactId>
            <version>2.1.4.RELEASE</version>
        </dependency>       

        <!-- Segurança | Fim -->




        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>


        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

The interesting thing is that if I do a Request, for any API, the console does not print Chamou HttpSecurity it seems that the settings of WebSecurityConfigurerAdapter are not being applied.

Console output, after a Request: inserir a descrição da imagem aqui

2 answers

3


You need to disable CSRF before authorizing requests, try this way:

@Override
protected void configure(HttpSecurity http) throws Exception {
    http.csrf().disable()
        .authorizeRequests()
            .antMatchers(HttpMethod.GET, "/usuario/informacoes/*")
            .permitAll()
        .anyRequest()
            .authenticated()
    ;
}

Includes in the comments a gist containing a functional configuration of the WebSecurityConfigurerAdapter

As the configurer is not even called, I believe it is actually a problem in the configuration of @EnableResourceServer


As I mentioned in the comments, to properly configure CORS you don’t need a filter, the class CorsConfigurationSource will do the work as described in documentation:

@Bean
public CorsConfigurationSource corsConfigurationSource() {
    final CorsConfiguration config = new CorsConfiguration();
    config.setAllowedOrigins(Arrays.asList("*"));
    config.setAllowedMethods(Arrays.asList("*"));
    config.setAllowCredentials(true);
    config.setAllowedHeaders(Arrays.asList("Authorization", "Cache-Control", "Content-Type"));

    final UrlBasedCorsConfigurationSource configSource = new UrlBasedCorsConfigurationSource();
    configSource.registerCorsConfiguration("/**", config);

    return configSource;
}

Remember to enable also in the authorization configuration:

@Override
protected void configure(HttpSecurity http) throws Exception {
    http.cors().and().csrf().disable()
        .authorizeRequests()
            .antMatchers(HttpMethod.GET, "/usuario/informacoes/*")
            .permitAll()
        .anyRequest()
            .authenticated()
    ;
}

I haven’t forgotten you my friend, I just haven’t had time to make your example myself :)

Below I put an example with comments on the Authorization and Resource Server configuration:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.InMemoryTokenStore;

@Configuration
public class OAuth2ServerConfig {

    // Id da aplicação, este ID deve ser utilizado no Resource Server, isso indica que o Authorization Server está emitindo um token para ser utilizar por este Resource
    private static final String APPLICATION_RESOURCE_ID = "my-application-id";

    // Token store compartilhado entre o Authorization Server e o Resource Server
    @Bean
    public TokenStore tokenStore() {
        return new InMemoryTokenStore();
    }

    @Configuration
    @EnableAuthorizationServer
    protected static class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {

        @Autowired
        private TokenStore tokenStore;

        @Override
        public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
            endpoints.tokenStore(tokenStore);
        }

        @Override
        public void configure(ClientDetailsServiceConfigurer clients) throws Exception {

            // Configuração em memória de usuários para teste
            clients.inMemory()
                        .withClient("nullptr")
                        .secret(passwordEncoder().encode("secret"))
                        .authorizedGrantTypes("client_credentials", "refresh_token")
                        .authorities("ROLE_ADMIN")
                        .scopes("read", "write")
                        .resourceIds(APPLICATION_RESOURCE_ID);
        }

        @Bean
        public PasswordEncoder passwordEncoder() {
            return new BCryptPasswordEncoder();
        }
    }

    @Configuration
    @EnableResourceServer
    protected static class ResourceServerConfig extends ResourceServerConfigurerAdapter {

        @Autowired
        private TokenStore tokenStore;

        // Configurações de token store e Resource Id
        @Override
        public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
            resources.tokenStore(tokenStore).resourceId(APPLICATION_RESOURCE_ID);
        }

        // Configurações de autorização para a controladora
        @Override
        public void configure(HttpSecurity http) throws Exception {
            http.requestMatchers().antMatchers("/simple").and().authorizeRequests().antMatchers("/simple").access("#oauth2.hasScope('read')");
        }
    }

}

Includes this simple controller to run the tests:

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/simple")
public class SimpleController {

    @GetMapping
    public String test() {
        return "Hi there :)";
    }
}

So let’s go to the calls:

In the server configuration I configured the client nullptr password-protected secret, then we will authenticate to get the token through Authorization Server (I performed through Postman):

POST /oauth/token HTTP/1.1
Host: localhost:8080
Content-Type: application/x-www-form-urlencoded
Authorization: Basic bnVsbHB0cjpzZWNyZXQ=
User-Agent: PostmanRuntime/7.15.0
Accept: */*
Cache-Control: no-cache
Postman-Token: 2de597db-640f-46b2-acbd-4e5293ffe4c3,fc03c3f6-f2ce-4c15-bbbc-750102f9801d
Host: localhost:8080
cookie: JSESSIONID=2325944BF8FC184676D2C56F43193BD4
accept-encoding: gzip, deflate
content-length: 29
Connection: keep-alive
cache-control: no-cache

grant_type=client_credentials

With this POST, I obtained the authorization token as expected:

{
    "access_token": "6ffdf3e5-cf71-4426-911f-5655cddcf679",
    "token_type": "bearer",
    "expires_in": 43199,
    "scope": "read write"
}

Now that I have obtained the token I will make the request to the controller, passing the authorization token in the header:

GET /simple HTTP/1.1
Host: localhost:8080
Authorization: Bearer 6ffdf3e5-cf71-4426-911f-5655cddcf679
User-Agent: PostmanRuntime/7.15.0
Accept: */*
Cache-Control: no-cache
Postman-Token: f1bbcf6b-5c97-41e8-bac2-e1cb2bcb89e7,451b27ce-2ff3-4659-b675-357b405581ad
Host: localhost:8080
cookie: JSESSIONID=2325944BF8FC184676D2C56F43193BD4
accept-encoding: gzip, deflate
Connection: keep-alive
cache-control: no-cache

And there’s the answer:

Hi there :)

We have the cases where we send the request without token, and we have the return:

{
    "error": "unauthorized",
    "error_description": "Full authentication is required to access this resource"
}

And when we ship with invalid token:

{
    "error": "invalid_token",
    "error_description": "Invalid access token: meutokenerrado"
}

With this you can already have a Oauth2 configuration base, you can then disable user control inMemory() and use jdbc(), and set up more details on how to search users with a ClientDetailService customized.

Note that I have not configured CORS at any time, if necessary configuration and release of CORS must use the settings I have passed before.

You can find more material below:

Spring Security Oauth Site Sample applications

  • I updated the code, but it still doesn’t work. I put 2 console log (I updated the question) and it seems that the Websecurityconfigureradapter is not being called

  • I believe it is due to Authorization and Resource Server settings, do you really need them at this time? You will keep Authorization and Resource together?

  • I created a gist of a project of mine that is working

  • Sorry I don’t understand, you’re referring to SecurityCORSFilter ? If yes, I had to put because I was returning Cors errors, because of the OPTIONS that the browser sends, only solution I found, was putting the SecurityCORSFilter

  • I’m checking the gist, thank you very much for your attention

  • The Annotations @EnableAuthorizationServer @EnableResourceServer @EnableGlobalMethodSecurity(prePostEnabled = true) only let them if in fact it will provide all the settings of Resource and Authorization server

  • I removed the Annotations @EnableAuthorizationServer @EnableAuthorizationServer ``@EnableGlobalMethodSecurity(prePostEnabled = true), however now it does not recognize the API to grab the token, if I make a request to /oauth/token he return me timestamp:"25/06/2019"&#xA;status:404&#xA;error:"Not Found"&#xA;message:"No message available"&#xA;path:"/oauth/token" As I removed the Annotations, I need to do the API to get the Token manually ?

  • @Dup, so you are using the Authorization server below, as you were passing the token to the server after authorization?

  • There it is, after I took the notes the API from where I picked up the token apparently no longer exists, now I’m trying to create a tokenServices to be called on my API oauth/token but I’m not sure if that’s really what needs to be done.

  • No need, the Annotation @EnableAuthorizationServer that enables this. But you must configure how you validate the token again, by enabling the @EnableResourceServer the server must validate the token through some configuration, you configured the token validation?

  • I did not make any settings, all project settings this in question, I have nothing more than this. Would you have Discord ? I can show more details of the project by there, if you want to add me Dup #1537

  • I will provide a functional example also using Authorization and Resource server settings

  • OK thank you very much

  • I noticed that if you remove the note @Order(Ordered.HIGHEST_PRECEDENCE) class SecurityCORSFilter the WebSecurityConfigurerAdapter is called and printed on the console Chamou HttpSecurity, but instead, this makes me have problems with CORS OPTIONS in Request from different domains, as the class SecurityCORSFilter is no longer called after the annotation is removed. Would there be any way to make the two Classes have effect on the application ? because I need both, one for CORS issues and one to free up access to an API without requiring authentication.

  • @Dup in reality you don’t need a filter to implement the CORS settings, you must use the class Corsconfigurationsource. I also added an example in the reply

  • I added the @Bean CorsConfigurationSource in the WebSecurityConfigurerAdapter but keeps returning me error OPTIONS http://192.168.25.26:8080/oauth/token?grant_type=password&scope=password&username=1&password=1 401 to solve this problem in my old SecurityCORSFilter I had the following code if ("OPTIONS".equalsIgnoreCase(request.getMethod())) {&#xA; response.setStatus(HttpServletResponse.SC_OK);&#xA; } for when you have a request like OPTIONS return with the Status 200 OK. Now how can I get the same result using Corsconfigur.. ?

  • Change the Press config.setAllowedMethods(Arrays.asList("*")); and try again, the configuration is so even to work the CORS, it seems magical :)

  • I changed, continues the same error, the interesting thing is that the Request I do is not printing "Chamou HttpSecurity" on the console, I get the impression that these settings are not being used.

  • Would you have any example, where the question of OPTIONS CORS and the settings ofWebSecurityConfigurerAdapter is working because I believe I’m lost with these Annotations, which ones to use and if I need to configure them separately.

  • I haven’t been able to solve this problem, I haven’t found any article that shows how I can properly configure Spring classes.

  • @Dup, I added more details to you

  • @Dup managed to solve his problem?

  • 1

    I’m still trying to, by converting your example to my use case, I believe it goes well, thank you very much for the help.

Show 18 more comments

1

Try it this way

@Configuration
public class WebSecurity extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication().withUser("user").password(passwordEncoder().encode("pass")).roles("USER");
    }

    @Override
    public void configure(final HttpSecurity http) throws Exception {
        http//
                .cors().and().csrf().disable().headers().frameOptions().disable().and()//
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()//
                .authorizeRequests().antMatchers(HttpMethod.GET, "/usuario/informacoes/**").permitAll()//
                .and().authorizeRequests().anyRequest().authenticated().and().httpBasic();
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
}

Browser other questions tagged

You are not signed in. Login or sign up in order to post.