Altaf
Altaf

Reputation: 429

Request Matcher not working to permit allowed path

I am following an older tutorial to implement Spring Security. Unfortunately, antMatchers is not recogzied as a method in my configuration class, so after doing some research, I believe requestMatchers method is its equivalent. However, the path (/) remains blocked without authentication. I would like to permit this.

Here is my controller:

package com.quadri.springsecurity.controllers;

import java.util.Arrays;
import java.util.List;

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

import com.quadri.springsecurity.models.Student;

@RestController
@RequestMapping("api/v1/students")
public class StudentController {

    private static final List<Student> STUDENTS = Arrays.asList(
        new Student(1, "James Bond"),
        new Student(2, "Maria Jones"),
        new Student(3, "Anna Smith")
    );

    @GetMapping(path = "{studentId}")
    public Student getStudent(@PathVariable("studentId") Integer studentId) {
        return STUDENTS.stream()
        .filter(student -> studentId.equals(student.getStudentId()))
        .findFirst()
        .orElseThrow(() -> new IllegalStateException("Student " + studentId + " does not exist!"));
    }
}

Here is my config file:

package com.quadri.springsecurity.security;

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.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.web.SecurityFilterChain;

@Configuration
@EnableWebSecurity
public class ApplicationSecurityConfig {

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
            .authorizeHttpRequests()
                .requestMatchers( "resources/**", "/").permitAll()
                .anyRequest().authenticated()
                .and()
            .httpBasic();
        
        return http.build();
    }
}

In my resources/static folder I have created a simple html page (index.html) displaying hello world. In the tutorial the RequestMapping wasn't changed, however they used .antMatcher in the config file which is not a recognized method in Spring Security at least the version I am using. Here is my POM for reference:

<?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 https://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>3.0.1</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.quadri</groupId>
    <artifactId>spring-security</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>spring-security</name>
    <description>Demo project for Spring Boot</description>
    <properties>
        <java.version>17</java.version>
    </properties>
    <dependencies>
        <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>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

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

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

What is the proper way to make sure the home or "/" URL is permitted?

Upvotes: 2

Views: 11658

Answers (3)

Adel Balbisi
Adel Balbisi

Reputation: 116

This could help someone else specially those new to jhipster + spring-security:

In case you using a webfilter like for example OncePerRequestFilter or any other, ensure that is not filtering out your api/endpoints

Here an example:

public class MyWebFilter extends OncePerRequestFilter {

        @Override
        protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
            throws ServletException, IOException {
            // Request URI includes the contextPath if any, removed it.
            String path = request.getRequestURI().substring(request.getContextPath().length());
            if (
                !path.startsWith("/my_api") &&
                !path.contains(".") &&
                path.matches("/(.*)")
            ) {
                request.getRequestDispatcher("/index.html").forward(request, response);
                return;
            }
    
            filterChain.doFilter(request, response);
        }
    }

by excluding our api from the filter we keeping it accessible

Upvotes: 0

zzpzaf
zzpzaf

Reputation: 158

As you suspected, issues can come out from the Spring Boot newest version you use, which as it is in the pom is 3.0.1. As you can see here,versions 3.0 and afterward, are based on the Spring framework 6.0. The Spring framework 6.0 also uses the Spring Security 6.0,, where, antMatchers() (as well as other Matcher methods) are deprecated for Spring security configurations. [See here and here].

Moreover, I suggest leaving out any URL path you wish to be accessible, such as "/** " or "/resources/** " and protect just the other path(s) of your api, which in your case should be the one defined in your controller "/api/v1/students/** ". You can do that in a similar way as the snippet below:

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    
    // http
    //     .securityMatchers( (matchers) -> matchers
    //     .requestMatchers("/resources/**", "/"))
    //     .authorizeHttpRequests((authorize) -> authorize
    //     .anyRequest().permitAll());

        
    http 
        .securityMatchers( (matchers) -> matchers
        .requestMatchers("/api/v1/students/**"))
        .authorizeHttpRequests((authorize) -> authorize
        .anyRequest().authenticated())
        .httpBasic();
    
    return http.build();
}

Upvotes: 1

Neeraj
Neeraj

Reputation: 316

You should allow index.html in the HttpSecurity request matchers as going to / is doing an auto-redirect to index.html and there is no permit rule defined for index.html giving an auth prompt. Below setting should work:

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {

    http
        .authorizeHttpRequests()
            .requestMatchers( "/resources/**", "/", "/index.html").permitAll()
            .anyRequest().authenticated()
            .and()
        .httpBasic();

    return http.build();
}

Upvotes: 6

Related Questions