GithubHelp home page GithubHelp logo

spring-webflux-azuread-rbac's Introduction

Spring WebFlux Reactive App RBAC with Azure AD

This demo explains how to get Azure AD JWT token based RBAC implementation for a Spring WebFlux reactive app.

Microsoft provides a maven dependency, azure-active-directory-spring-boot-starter for integrating Azure AD authenticaiton into Spring based applications. However, this dependency expects the servlet dependencies to be present and hence does not work with reactive WebFlux based applications.

This demo leverages the spring native spring-boot-starter-security dependency along with spring-security-oauth2-resource-server and spring-security-oauth2-jose to implement a reactive spring OAuth2.0 resource server backed by Azure AD.

Azure Setup

  • Register an application on Azure AD and capture the client id of your application
  • Keep your tenant ID handy

Spring Setup

Maven Dependencies

Add the below maven dependencies to your project:

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

<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-oauth2-resource-server</artifactId>
</dependency>

<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-oauth2-jose</artifactId>
</dependency>

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

Configure application to use Azure AD provider

In application.yml, initialize spring security resource server to use Azure AD as the authorization server by setting spring.security.oauth2.resourceserver.jwt.issuer-uri to the issuer URI of your app.

To find your issuer URI,

  • Use the iss claim in your JWT token
  • From your application endpoints, hit the open id metadata document URL. Hit it and find the issuer_uri property
  • Build it yourself: https://login.microsoftonline.com/<your-tenant-id>/v2.0

Enable Spring WebFlux Security

  • Use @EnableWebFluxSecurity to enable Spring WebFlux reactive security
  • Optionally, use @EnableReactiveMethodSecurity to enable method level security checks, including pre/post authorize annotations

At this point, your application is fully secured by Azure AD based RBAC. However, this is incomplete. With the above configurations, Spring only checks for the iss claim i.e., the JWT token's issuer and exp claim i.e., the JWT token's expiry.

This is by design, as Spring allows plugging in multiple auth providers and implementations.

Customizing Security Checks

Validate the Token's audience

The aud claim i.e., to which application was the token generated for, is set inside this claim by Azure AD.

We have captured the client id from Azure AD as part of the Azure setups.

So, we can supply a custom JWT token validator which can check this claim.

ReactiveJwtDecoder jwtDecoder() {
    NimbusReactiveJwtDecoder jwtDecoder = (NimbusReactiveJwtDecoder)
            ReactiveJwtDecoders.fromIssuerLocation(issuerUri);

    OAuth2TokenValidator<Jwt> tokenValidator = new DelegatingOAuth2TokenValidator<Jwt>(
            JwtValidators.createDefaultWithIssuer(issuerUri),
            new JwtClaimValidator<List<String>>("aud", (aud) -> {
                return aud != null && aud.contains(clientId);
            }));

    jwtDecoder.setJwtValidator(tokenValidator);

    return jwtDecoder;
}

The clientId parameter can be maintained as an externalized configuration.

Validate the Token based on AppRoles instead of Scope

By default, Spring maps the scp claims into GrantedAuthorities which informs the application code about the list of permissions granted as part of the token.

If the application registered custom application roles in Azure AD, roles claim would be appended specific to each user by Azure AD.

If the application needs these roles and intends to implement method level authorization, typically via @PreAuthorize("hasRole('<your role>')", supply your custom authority extractor like below:

Converter<Jwt, Mono<AbstractAuthenticationToken>> grantedAuthoritiesExtractor() {
    JwtAuthenticationConverter jwtAuthenticationConverter = new JwtAuthenticationConverter();
    jwtAuthenticationConverter.setJwtGrantedAuthoritiesConverter
            ((jwt) -> {
                Collection<?> authorities = (Collection<?>)
                        jwt.getClaims().getOrDefault("roles", Collections.emptyList());

                return authorities.stream()
                        .map(Object::toString)
                        .map(role -> "ROLE_".concat(role))
                        .map(SimpleGrantedAuthority::new)
                        .collect(Collectors.toList());
            });
    return new ReactiveJwtAuthenticationConverterAdapter(jwtAuthenticationConverter);
}

Note: for method level authorization, @EnableReactiveMethodSecurity has to be placed inside application components

Now, for every request, the JWT token would be converted into an AuthenticatedPrincipal and can be used in every layer of your application to perform pre authorization.

Below is a sample method which checks if the incoming request's User has role admin as part of the roles claim.

@PreAuthorize("hasRole('admin')")
public Mono<ServerResponse> handleGreet(ServerRequest request) {

    return ServerResponse.ok()
            .contentType(MediaType.TEXT_PLAIN)
            .body(BodyInserters.fromProducer(adAuthService.greetAdmins(), String.class));
}

spring-webflux-azuread-rbac's People

Contributors

naridnevahgar avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar

spring-webflux-azuread-rbac's Issues

Spring Webflux throws an error "Failed to validate the token", when used with Azure AD

Background (Concise) :
I am working on one of the projects of my firm, which uses Spring Webflux + Kotlin + Azure AD stack. I meticulously tried to understand the steps detailed here, and modified it for my use case, wherein I just set up a WebfluxConfig class, and moved the security filters into it. (annotated the class with all the necessary annotations as mentioned by you). I have my controllers annotated with @PreAuthorize, trying to look for the scope that's there in the auth context.

Issue:
The application starts up well, and I have spring security logging enabled as well. When I do a POST call with Auth headers using Postman, I get 401 unauthorized. On the log, it says:

"logger":"org.springframework.security.web.server.authentication.AuthenticationWebFilter","details":{"message":"Authentication failed: Failed to validate the token"},"level":"DEBUG"

What's done:
I suspected that maybe I am not putting the issuer URI correctly, but I double-checked and its proper. Is it that I will have to set jwk-set-uri and other such properties, to get this working? Does Azure AD not fully work with Spring Webflux?

Kindly help. Thanks :)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.