Julien Dubois
Posted on September 9, 2019
Why use Active Directory?
Let's be honnest, Active Directory isn't "cool" today. People see it has very complex, which is true - but security is a complex matter! And it doesn't have the hype of new products like Red Hat's Keycloak, even if both are often used for the same goal, at least with Spring Boot: securing a business application using OpenID Connect.
However, there's one really nice feature of Active Directory: your company has probably it already installed, and probably already pays for it (hint: for a security product, you'd better pay if you want support and the latest patches - that's why I always recommend to pay for Keycloak!). Officially, 85% of Fortune 500 companies are using Active Directory, which is in fact (unofficially!) confirmed by this clever hacker.
So securing a Spring Boot application with Active Directory makes a lot of sense :
- It's probably already installed, validated and secured in your company
- You'll have access to the official employee list of your company: no need to create new users, handle lost passwords, invalidate old employees...
- It's highly secured: you'll have 2 factor authentication, etc, everything is included
But there's a last reason: it's free! Well, not totally free, but if you look at the pricing model, there's a very generous free tier. So you can use it for development or for your start-up idea, without paying anything.
The Azure Spring Boot Starter for Active Directory
Thankfully, the Azure engineering team is providing a Spring Boot Starter for Azure Active Directory, which is available at https://github.com/microsoft/azure-spring-boot/tree/master/azure-spring-boot-starters/azure-active-directory-spring-boot-starter. There are two official tutorials available:
- The official tutorial is available here.
- There's also a tutorial in the project GitHub repository, which is updated along with the code: this one works with the latest version of the code, and is less detailed than the official one.
Both of them are a bit outdated at the time of this writing, and as it's my work to update them, I'm first doing this blog post to gather feedback:
- We'll be using the latest and greatest version of both Spring Boot (2.1.8, released a few hours ago at the time of this writing) and the Azure Spring Boot starters (2.1.7)
- We'll be using the new Active Directory user interface: this is a huge case of problem here, as all the screenshots currently available are from the older user interface, so you can't find anything easily
Please, don't hesitate to add comments to this blog post, so I can clean up everything, and create an awesome official tutorial!
The sample project
The sample project we do here is available at https://github.com/jdubois/spring-active-directory, so if you want to see the real code and test it, it's all there.
This is a Spring Boot project generated with Spring Initializr as I wanted to have something extremely simple. It uses the following important components:
- Spring Web
- OAuth2 Client, which transitively includes Spring Security
- Azure Support
- Spring Data JPA and MySQL, so we can build a "real" application in the future
Configuring Active Directory
Now is the tricky part of this post! Configuring Active Directory is complicated, so we'll go step-by-step and provide screenshots.
Create your own tenant
Active Directory provides tenants, which are basically instances that you can use. There are two types of instances: work and school (the one I will use here), and social accounts (called "Azure Active Directory B2C").
As discussed earlier, there's a generous free tier, so you can create your own tenant without paying anything:
- Go to the the Azure portal
- Select "All resources", and look for "Azure Active Directory" and click "create"
- Fill in your organization's name, domain and country, and you're done!
Accessing your Active Directory tenant
You can now switch to your Active Directory tenant by clicking on the "Directory + Subscription" icon on the top menu:
Configuring your tenant
Once you have switched to your tenant, select "Active Directory", and you can now configure it with full admin rights. Here's what's important to do.
Click on "App registrations" and create a new registration:
Please note that:
- The account type must be "multitenant". The current Spring Boot starter does not work with single tenants, which is an issue being currently addressed.
- The redirect URI must be "http://localhost:8080/login/oauth2/code/azure". Of course you can replace "localhost:8080" by your own domain, but the suffix is the default one that will be configured by the Spring Boot starter, and if those URI do not match, you will not be able to log in.
Select the registered application
- In the "overview", note the "Application (client) ID", this is what will be used in Spring Security as "client-id", as well as the "Directory (tenant) ID", which will be Spring Security's "tenant-id".
Select "Authentication", and in the Web "Platform configuration", check both options under "Implicit grant" ("Access tokens" and "ID tokens")
Click on "Certificates & secrets", and create a new client secret, which will be Spring Security's "client-secret"
- Click on "API permissions", and under "Microsoft Graph", give your application the "Directory.AccessAsUser.All" and "User.Read" permissions
- Click on the "Grant admin consent" button at the bottom of the page
Go back to your Active Directory tenant and click on "User settings"
Under "Manage how end users launch and view their applications", validate the "Users can consent to apps accessing company data on their behalf" is set to "Yes" (this should be good by default).
Create users and groups
Still in your Active Directory tenant, select "Groups" and create a new group, for example "group1".
Now select "Users", create a new user, and give that user the "group1" group that we just created.
Configure the Spring Boot application
Now let's use that configured tenant, with this new user, in our Spring Boot application.
In the pom.xml
file, add the azure-active-directory-spring-boot-starter
:
<dependency>
<groupId>com.microsoft.azure</groupId>
<artifactId>azure-active-directory-spring-boot-starter</artifactId>
</dependency>
In your application.yml
file (or application.properties
file if you don't like YAML), configure the following properties. Please note that we got the 3 required values when we registered our application in our Active Directory tenant.
azure:
activedirectory:
tenant-id: <tenant-id>
active-directory-groups: group1, group2
spring:
security:
oauth2:
client:
registration:
azure:
client-id: <client-id>
client-secret: <client-secret>
We now need to configure our Spring Boot application to use Active Directory. Create a new SecurityConfiguration
class:
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
private final OAuth2UserService<OidcUserRequest, OidcUser> oidcUserService;
public SecurityConfiguration(OAuth2UserService<OidcUserRequest, OidcUser> oidcUserService) {
this.oidcUserService = oidcUserService;
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().authenticated()
.and()
.oauth2Login()
.userInfoEndpoint()
.oidcUserService(oidcUserService);
}
}
This configuration will require that each request is secured, and will therefore redirect any user to Active Directory when he tries to connect.
Running everything
When running the Spring Boot application, we recommend you add a src/main/resources/logback-spring.xmllogback-spring.xml
file with the following configuration, in order to better understand the issues you might encounter:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration>
<configuration scan="true">
<include resource="org/springframework/boot/logging/logback/base.xml"/>
<logger name="org.springframework.security" level="DEBUG"/>
<logger name="com.microsoft" level="DEBUG"/>
<logger name="com.example" level="DEBUG"/>
</configuration>
Now if you run the application, accessing it on http://localhost:8080 should point you to Active Directory, where you can sign it using the user we just created earlier:
Testing the security
In order to know if everything is correct, including if our user really receive the "group1" role that we configured earlier, let's add a specific Spring MVC controller called AccountRessource
:
package com.example.demo;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class AccountResource {
@GetMapping("/account")
public Authentication getAccount() {
return SecurityContextHolder.getContext().getAuthentication();
}
}
Accessing http://localhost:8080/account should now give you all the user's security information, including his roles! Congratulations, you have secured your Spring Boot application using Active Directory!
Posted on September 9, 2019
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.