microsoft / azure-spring-boot

Spring Boot Starters for Azure services
MIT License
374 stars 460 forks source link

Microsoft Entra ID configuration issues with tokens and spring 5 #964

Closed Seifeldin-Sabry closed 11 months ago

Seifeldin-Sabry commented 11 months ago

The problem(s): I want to make a simple resource server that is protected and some users need to have some higher authorities. There is no clear way to do anything. with different docs that are outdated or with UI changes or something else.

I can't make the server verify a simple token.

I also can't create different users with different granted scopes or groups.

here is my setup top to bottom:

first, I made a tenant, registered an app, got a secret, and an app_uri. Added scopes and added groups (just to try out which one i want to use). I found tons of starter code and ultimately landed on this one with these configurations:

build.gradle

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter'
    implementation 'org.springframework.boot:spring-boot-starter-web'
    implementation 'org.springframework.boot:spring-boot-starter-security'
    implementation 'org.springframework.security:spring-security-oauth2-resource-server'
    implementation("com.azure.spring:spring-cloud-azure-autoconfigure:5.7.0")
    implementation("com.azure.spring:spring-cloud-azure-dependencies:5.7.0")
    implementation("org.springframework.security:spring-security-oauth2-jose:6.2.0")
    compileOnly 'org.projectlombok:lombok'
    annotationProcessor 'org.springframework.boot:spring-boot-configuration-processor'
    annotationProcessor 'org.projectlombok:lombok'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
}

application.yaml

spring:
  cloud:
    azure:
      active-directory:
        enabled: true
        credential:
          client-id: ${AZURE_CLIENT_ID}
        session-stateless: true
        app-id-uri: ${AZURE_APP_ID_URI}

SecurityConfiguration.java

@Configuration
@EnableWebSecurity
@EnableMethodSecurity
public class SecurityConfiguration {

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http.cors(Customizer.withDefaults())
                .authorizeHttpRequests((authorize) -> authorize
                        .anyRequest().authenticated()
                )
                .sessionManagement(mgmt ->
                        mgmt.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
            .apply(AadResourceServerHttpSecurityConfigurer.aadResourceServer());
        return http.build();
    }

    @Bean
    CorsConfigurationSource corsConfigurationSource() {
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        CorsConfiguration corsConfiguration = new CorsConfiguration();
        corsConfiguration.setAllowedMethods(List.of("GET", "POST", "PUT", "DELETE", "OPTIONS", "HEAD"));
        corsConfiguration.setAllowedOrigins(List.of("*"));
        source.registerCorsConfiguration("/**", corsConfiguration);
        return source;
    }
}

had to adapt some things because of deprecated stuff but the starter code used the AAdResourceServer..

I made a test controller to test it out

TestController.java

@RestController
public class TestController {

    // for regular users
    @GetMapping ("/test")
    public String test() {
        return "test";
    }

    // for datascientists
    @PreAuthorize("hasAuthority('SCOPE_App.Datascientist')")
    @GetMapping ("/test2")
    public String test2() {
        return "test2";
    }
}

and I was testing it on jetbrains so i made a HTTP file

POST https://login.microsoftonline.com/{{tenant_id}}/oauth2/v2.0/token
Content-Type: application/x-www-form-urlencoded

client_secret = {{client_secret}} &
client_id = {{client_id}} &
grant_type = client_credentials &
scope = {{application_id_uri}}/.default

> {%
    if (response.status === 200) {
        client.global.set("access_token", response.body.access_token);
    }
%}

###
GET http://localhost:8080/test
Authorization: Bearer {{access_token}}

Things I hope you can help me with:

Thank you so much in advance

moarychan commented 11 months ago

Hi @Seifeldin-Sabry thanks for using the starter!

I am sorry there's no latest sample doc for using Spring Cloud Azure 5.x.

For a quick check, you should register two apps in your tenant, the first one is used to expose the scopes for your resource server, and the second app is used to access the API permissions of the first app. Use the second app's credentials to acquire a valid token with authorization code flow, and then access your resource server with the token. You can check the similar version (4.x) with this sample aad-resource-server.

Seifeldin-Sabry commented 11 months ago

Hi! thanks a lot for reaching out. I think I'm certain I have it working but do you have any tips or resources on how to assign users to certain group on signup? like say the user is registering to my app id like to assign them to user group or another group. so that I can use the group claims in the jwt token

moarychan commented 11 months ago

Hi @Seifeldin-Sabry , please check this quickstart Create a group with members and view all groups and members