1

Docs: https://learn.microsoft.com/en-us/azure/developer/java/spring-framework/spring-boot-starter-for-azure-active-directory-developer-guide?tabs=SpringCloudAzure5x#protect-a-resource-serverapi

I am facing issues providing a self-defined configuration for Azure AD. If no configuration is provided, the application runs, however once I add the example one from the docs, the application breaks.

// AadOAuth2ResourceServerSecurityConfig.java
@Configuration(proxyBeanMethods = false)
@EnableWebSecurity
@EnableMethodSecurity
public class AadOAuth2ResourceServerSecurityConfig {

    @Bean
    public SecurityFilterChain apiFilterChain(HttpSecurity http) throws Exception {
        http.apply(AadResourceServerHttpSecurityConfigurer.aadResourceServer())
                .and()
                .authorizeHttpRequests()
                .anyRequest().authenticated();
        return http.build();
    }
}

Failure (full log on https://pastebin.com/w240HfZK):

Caused by: java.lang.ClassNotFoundException: jakarta.servlet.Filter

I tried adding this to the dependencies, but then another failure occurs:

        <dependency>
            <groupId>jakarta.servlet</groupId>
            <artifactId>jakarta.servlet-api</artifactId>
            <version>5.0.0</version>
            <scope>provided</scope>
        </dependency>

Failure:

***************************
APPLICATION FAILED TO START
***************************

Description:

Parameter 0 of method setFilterChains in org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration required a bean of type 'com.azure.spring.cloud.autoconfigure.implementation.aad.configuration.properties.AadResourceServerProperties' that could not be found.


Action:

Consider defining a bean of type 'com.azure.spring.cloud.autoconfigure.implementation.aad.configuration.properties.AadResourceServerProperties' in your configuration.


Process finished with exit code 1

This is my 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 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.5</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.github.stoyank7</groupId>
    <artifactId>gateway</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>gateway</name>
    <description>gateway</description>
    <properties>
        <java.version>17</java.version>
        <spring-cloud.version>2022.0.2</spring-cloud.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>io.projectreactor</groupId>
            <artifactId>reactor-test</artifactId>
            <scope>test</scope>
        </dependency>

<!--        Azure-->
        <dependency>
            <groupId>com.azure.spring</groupId>
            <artifactId>spring-cloud-azure-starter-active-directory</artifactId>
            <version>5.0.0</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
        </dependency>

        <dependency>
            <groupId>jakarta.servlet</groupId>
            <artifactId>jakarta.servlet-api</artifactId>
            <version>5.0.0</version>
            <scope>provided</scope>
        </dependency>



    </dependencies>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

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

</project>

And my application.yml

spring:
  main:
    allow-bean-definition-overriding: true
  cloud:
    azure:
      active-directory:
        enabled: true
        credential:
          client-id: xxxx
        app-id-uri: xxxx

Optional, this is the route that I want to disable Azure AD from:

    @Bean
    public RouteLocator buildUserRouter(RouteLocatorBuilder builder) {
        return builder
                .routes()
                .route(p -> p
                        .path("/user/**")
                        .filters(f -> f.rewritePath("/user/(?<segment>.*)", "/${segment}"))
                        .uri(userServiceUrl))
                .build();
    }

Am I doing something wrong or is the documentation faulty at this point? I already checked those answers but no progress:

S. Kostadinov
  • 147
  • 3
  • 10

1 Answers1

1

Forget about anything related to servlets when working with spring-cloud-gateway, it is a reactive application. As consequence, it must be configured with SecurityWebFilterChain and not SecurityFilterChain.

Azure AD is just an OIDC authorization server, you can configure your Spring application as a client or a resource server with just Spring Security and Boot starters for OAuth2. Reference documentation there.

You could find those tutorials I wrote useful too. It contains samples for reactive resource servers and clients (BFF tutorial is configuring spring-cloud-gateway as a client with a starter of mine, but there is also another tutorial for a reactive resource server with just "official" starter).

As a side note, I wouldn't configure the gateway as a resource server to implement access control there instead of securing each service (this would introduce too much coupling between the gateway and implementation details of each service, just try to imagine what your access control unit tests will look like as soon as rules will involve the resource itself and not just the user accessing it).

ch4mp
  • 6,622
  • 6
  • 29
  • 49