Spring Security, Powered by MSAL Part 2 (Resource Server)
In the Part 1 of this series, we discussed the most common mode of integrating MSAL; the Client Auth Mode.
In this article, we will look at another common use case; the Resource Server Mode.
Use Case
Let’s say you have an application with and API endpoint you would like to expose to another application in your organization. We can achieve this with Spring Security and MSAL in resource_server mode.
For this use case, we will use two App Registrations, One for the Resource Server and another for the API Client/ API Consumer.
App Registrations Setup
Resource Server App Registration Setup
After creating the App Registration, we will need to set the Application ID URI, as shown below
After setting the Application ID URI, we can create some App Roles for Authorization, to limit the route Api Consumers are allowed to access based on what roles we assign to them.
Api Consumer App Registration Setup
After we’ve created the App Roles, We can switch over to the Api Consumer App Registration. There all we need to do is to Add the Api permission. The App Roles created in the previous step will appear as Api Permissions to the Api Consumer App Registration.
Api Permissions — -> Add a permission — ->My APIs — ->Application Permissions
This should be all that is required to be done in Azure Portal.
Resource Server Code Implementation
Dependencies
<properties>
<java.version>11</java.version>
<azure.version>3.11.0</azure.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.azure.spring</groupId>
<artifactId>azure-spring-boot-starter-active-directory</artifactId>
<version>${azure.version}</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>31.0.1-jre</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
application.yml
azure:
activedirectory:
application-type: resource_server
app-id-uri: ${APP_ID_URI}
tenant-id: ${AZURE_TENANT_ID}
client-id: ${AZURE_CLIENT_ID}
client-secret: ${AZURE_CLIENT_SECRET}
user-group:
allowed-group-names: group_name_1, group_name_2
SecurityAdapter
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class OAuth2Config extends AADResourceServerWebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
super.configure(http);
http.antMatcher("/api/**").authorizeRequests().anyRequest().authenticated();
}
}
RestController
@RestController
public class DemoController {
@GetMapping(value = "/api/demo")
public String demo() {
return "demo";
}
}
Authenticating the API Consumer
curl -X POST -H 'Content-Type: application/x-www-form-urlencoded' \
https://login.microsoftonline.com/<tenant-id>/oauth2/v2.0/token \
-d 'client_id=<client-id>' \
-d 'grant_type=client_credentials' \
-d 'scope=#API_ID_URI#.default' \
-d 'client_secret=<client-secret>'
This would return an access_token. To make a request to the Resource Server
curl --location --request GET 'http://localhost:8080/api/demo/' \
--header 'Authorization: Bearer access_token'
The source code for this article can be found on Github.