Skip to content
This repository has been archived by the owner on Aug 28, 2024. It is now read-only.

Commit

Permalink
Add demo project for AAD stateless app-role filter (PR #512) (#689)
Browse files Browse the repository at this point in the history
* Add demo project for AAD stateless app-role filter.
* Add introduction to the README.md
  • Loading branch information
wmitzel-airplus authored and Incarnation-p-lee committed Jul 9, 2019
1 parent ca45e4e commit 4831169
Show file tree
Hide file tree
Showing 9 changed files with 410 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
## About this sample

### Overview
This demo project explains the usage of the stateless authentication filter `AADAppRoleStatelessAuthenticationFilter`.
This project is composed of a vue.js frontend and a simple backend with three endpoints
* `/public` (accessible by anyone)
* `/authorized` (role "user" required)
* `/admin/demo` (role "admin" required).

### Get started
The sample is composed of two layers: vue.js client and Spring Boot RESTful Web Service. You need to make some changes
to get it working with your Azure AD tenant on both sides.

### How to configure

#### Register your application with your Azure Active Directory Tenant

Follow the guide [here](https://docs.microsoft.com/en-us/azure/active-directory/develop/v1-protocols-openid-connect-code#register-your-application-with-your-ad-tenant).

#### Configure appRoles

In order to use only the `id_token` for our authentication and authorization purposes we will use the
`appRoles` feature which AAD provides. Follow the guide
[Add app roles in your application](https://docs.microsoft.com/en-us/azure/active-directory/develop/howto-add-app-roles-in-azure-ad-apps)

For the test SPA provided with this example you should create the following roles in your manifest:

```
"appRoles": [
{
"allowedMemberTypes": [
"User"
],
"displayName": "Admin",
"id": "2fa848d0-8054-4e11-8c73-7af5f1171001",
"isEnabled": true,
"description": "Full admin access",
"value": "Admin"
},
{
"allowedMemberTypes": [
"User"
],
"displayName": "User",
"id": "f8ed78b5-fabc-488e-968b-baa48a570001",
"isEnabled": true,
"description": "Normal user access",
"value": "User"
}
],
```

After you've created the roles go to your Enterprise Application in Azure Portal, select "Users and groups" and
assign the new roles to your Users (assignment of roles to groups is not available in the free tier of AAD).

Furthermore enable the implicit flow in the manifest for the demo application
(or if you have SPAs calling you):

```
"oauth2AllowImplicitFlow": "true",
```

#### Configure application.properties

You have to activate the stateless app-role auth filter and configure the `client-id`of your application registration:

```properties
azure.activedirectory.session-stateless=true
azure.aad.app-role.client-id=xxxxxx-your-client-id-xxxxxx
```

#### Configure Webapp

Add your `tenant-id` and `client-id` in `src/main/resources/static/index.html`:

```
data: {
clientId: 'xxxxxxxx-your-client-id-xxxxxxxxxxxx',
tenantId: 'xxxxxxxx-your-tenant-id-xxxxxxxxxxxx',
tokenType: 'id_token',
token: null,
log: null
},
```

### How to run

- Use Maven

```
mvn clean package spring-boot:run
```
### Check the authentication and authorization
1. Access http://localhost:8080
2. Without logging in try the three endpoints (public, authorized and admin). While the public
endpoint should work without a token the other two will return a 403.
3. Insert your `client-id` and `tenant-id` and perform a log in. If successfull the token textarea
should get populated. Also the token header and token payload field will be populated.
4. Again access the three endpoints. Depending on your user and the assigned `appRoles` you should
be able to call the authorized and admin endpoints.
#### Demo
![demoonstration video](docs/demo.webp "Demo Video")
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
<?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>com.microsoft.azure</groupId>
<artifactId>azure-spring-boot-samples</artifactId>
<version>0.0.1-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>


<artifactId>azure-active-directory-spring-boot-stateless-sample</artifactId>

<name>Azure AD Stateless Spring Security Integration Spring Boot Sample</name>
<description>Sample project using the AAD stateless app-role filter for AAD integration in Spring Security
</description>
<url>https://github.com/Microsoft/azure-spring-boot</url>

<properties>
<project.rootdir>${project.basedir}/../..</project.rootdir>
</properties>

<dependencies>
<dependency>
<groupId>com.microsoft.azure</groupId>
<artifactId>azure-active-directory-spring-boot-starter</artifactId>
</dependency>

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

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

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

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

</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/**
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for
* license information.
*/
package sample.aad;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class AzureADStatelessBackendSampleApplication {

public static void main(String[] args) {
SpringApplication.run(AzureADStatelessBackendSampleApplication.class, args);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/**
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for
* license information.
*/
package sample.aad.controller;

import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class MainController {

@GetMapping("/public")
@ResponseBody
public String publicMethod() {
return "public endpoint response";
}

@GetMapping("/authorized")
@ResponseBody
@PreAuthorize("hasRole('ROLE_User')")
public String onlyAuthorizedUsers() {
return "authorized endpoint response";
}

@GetMapping("/admin/demo")
@ResponseBody
// For demo purposes for this endpoint we configure the required role in the AADWebSecurityConfig class.
// However, it is advisable to use method level security with @PreAuthorize("hasRole('xxx')")
public String onlyForAdmins() {
return "admin endpoint";
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/**
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for
* license information.
*/
package sample.aad.security;

import com.microsoft.azure.spring.autoconfigure.aad.AADAppRoleStatelessAuthenticationFilter;
import org.springframework.beans.factory.annotation.Autowired;
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.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class AADWebSecurityConfig extends WebSecurityConfigurerAdapter {

@Autowired
private AADAppRoleStatelessAuthenticationFilter aadAuthFilter;

@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable();

http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.NEVER);

http.authorizeRequests()
.antMatchers("/admin/**").hasRole("Admin")
.antMatchers("/", "/index.html", "/public").permitAll()
.anyRequest().authenticated();

http.addFilterBefore(aadAuthFilter, UsernamePasswordAuthenticationFilter.class);

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# By default, azure.activedirectory.environment property has value `global`,
# supported value is global, cn. Please refer to the README for details.
# azure.activedirectory.environment=global
azure.activedirectory.session-stateless=true
azure.activedirectory.client-id=xxxxxxxx-your-client-id-xxxxxxxxxxxx

Loading

0 comments on commit 4831169

Please sign in to comment.