Integrate Azure SSO with Flowable Work
Target audience: Developer
Introduction
For all Flowable products (Work, Design, Control, etc.) Spring Boot Starter dependencies exists to customize them. One typical customization that is often required is to integrate Single-Sign on (SSO).
This How-To describes how you can integrate Azure SSO with Flowable Work. The principles here can also be used to integrate Flowable Engage.
This integration is also available out-of-the-box for the Flowable Work and Engage applications provided by Flowable.
It can be enabled by setting application.security.type
to oauth2
(in addition to the other properties described below).
Additionally, this How-To is an example that is meant as an inspiration when met with similar requirements. Custom code isn't covered by standard Flowable Support.
Azure SSO Setup
The first thing we need to do before starting with the Flowable Project setup is to make sure that we have an Azure Active Directory instance. If you don't have one then we suggest following the Create Azure Active Directory instance guide from Azure.
However, most likely you have one Azure Active Directory for your company. We will head to https://portal.azure.com/ and navigate to it. Next step is going to be to create our Application Registrations. The steps for that are explained here in the Azure documentation. Make sure that you store the generated key somewhere, we will need it for configuring our application.
Note: Granting admin consent for your example might not be possible if you are using your main directory. However, this is not a problem for our configuration.
You can skip the last step (selecting implicit grant and hybrid flows), because we are not going to use the Azure AD Spring Boot Starters.
In addition to the steps explained above we need to add some more configurations in order to simplify our integration with Flowable:
- Configure group claims for Applications with Azure AD.
More details about this can be found here in the Azure documentation.
By doing this we have exposed the user groups in the
groups
claim for the user. - Go back to the "Authentication" section and change the "Redirect URIs" to "http://localhost:8080/login/oauth2/code/azure"
Project Setup
Now that we have our Azure Application we will setup a Flowable Work project. In order to see how to create a Flowable Work project you can follow the steps explained in Create a custom project.
Make sure that the Flowable Frontend and Demo dependencies are also added
<dependency>
<groupId>com.flowable.work</groupId>
<artifactId>flowable-work-frontend</artifactId>
</dependency>
<dependency>
<groupId>com.flowable.platform</groupId>
<artifactId>flowable-platform-default-idm-models</artifactId>
</dependency>
<dependency>
<groupId>com.flowable.platform</groupId>
<artifactId>flowable-platform-example-apps</artifactId>
</dependency>
Required Dependencies
The first step of the configuration is to add the needed Spring Boot OAuth2 Client and OAuth2 Resource Server dependencies:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
</dependency>
The first dependency is the Spring OAuth 2.0 client itself. This allows the redirect to work seamlessly for the users. While the second one is for the Spring OAuth 2.0 resource server. This allows us to use Bearer Authentication with a JWT token e.g. for access through Flowable Control.
OAuth2 Client Configuration Properties
As a next step we need to configure the Spring Security OAuth 2.0 provider.
In the example below the following replacements are needed:
<name>
- This can be any string you want. e.g.azure
<client-id>
- The id of the client which we created at the beginning. This can be seen in the overview of the application.<client-secret>
- The secret of the client which we created at the beginning<tenant-id>
- The tenant id of the Azure AD. This can be seen in the overview of the application.
spring.security.oauth2.client.registration.<name>.client-id=<client-id>
spring.security.oauth2.client.registration.<name>.client-secret=<client-secret>
spring.security.oauth2.client.registration.<name>.scope=openid,profile,email
spring.security.oauth2.client.registration.<name>.authorization-grant-type=authorization_code
spring.security.oauth2.client.provider.<name>.issuer-uri=https://login.microsoftonline.com/<tenant-id>/v2.0
spring.security.oauth2.client.provider.<name>.user-name-attribute=email
flowable.security.oauth2.client.mapper.authorities-attributes=roles
flowable.security.oauth2.client.mapper.groups-attributes=groups
This will hook up Spring with Azure AD as an OpenID Connect provider, and it will configure the Flowable beans to extract the authorities and groups from the User Info.
The roles can also be used to assign users to a group or a tenant.
When a role is prefixed with GROUP_
then the user will be member of the group that comes after the prefix, e.g. when the role is GROUP_myCustomGroup
the user will be member of the group with a key myCustomGroup
.
When a role is prefixed with TENANT_
then the user will be member of the tenant that comes after the prefix, e.g. when the role is TENANT_acme
the user will be member of the acme tenant.
OAuth2 Resource Server Configuration Properties
As a next step we need to configure the Spring Security OAuth 2.0 resource server.
In the example below the following replacements are needed:
<tenant-id>
- The tenant id of the Azure AD. This can be seen in the overview of the application.
spring.security.oauth2.resourceserver.jwt.issuer-uri=https://login.microsoftonline.com/<tenant-id>/v2.0
flowable.security.oauth2.resourceserver.jwt.principal-claim-name=preferred_username
flowable.security.oauth2.resourceserver.mapper.authorities-attributes=roles
flowable.security.oauth2.resourceserver.mapper.groups-attributes=groups
This will make sure that the Flowable REST APIs are available using the Bearer Authentication Token.
Security Configuration
Flowable offers an example SecurityConfiguration
and SecurityActuatorConfiguration
as part of the project setup.
Those configurations are for HTTP Basic authentication.
In order to use OAuth2 we would need to adapt them like this:
import org.springframework.core.annotation.Order;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.oauth2.jwt.JwtDecoder;
import org.springframework.security.web.context.HttpSessionSecurityContextRepository;
@Configuration(proxyBeanMethods = false)
@EnableWebSecurity
public class SecurityOAuth2Configuration {
@Autowired
protected ObjectProvider<OidcClientInitiatedLogoutSuccessHandler> oidcClientInitiatedLogoutSuccessHandlerProvider;
@Bean
@Order(10)
public SecurityFilterChain oauthDefaultSecurity(HttpSecurity http, ObjectProvider<FlowableHttpSecurityCustomizer> httpSecurityCustomizers) throws Exception {
for (FlowableHttpSecurityCustomizer customizer : httpSecurityCustomizers.orderedStream()
.collect(Collectors.toList())) {
customizer.customize(http);
}
http.exceptionHandling()
.defaultAuthenticationEntryPointFor(new HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED),
new RequestHeaderRequestMatcher("X-Requested-With", "XMLHttpRequest"));
// We mark all requests as authenticated in order for the redirect to happen when the application is accessed
http.authorizeRequests().anyRequest().authenticated();
// Currently an HttpSessionSecurityContextRepository is needed for the oauth2 to work
HttpSessionSecurityContextRepository securityContextRepository = new HttpSessionSecurityContextRepository();
securityContextRepository.setDisableUrlRewriting(true);
http.securityContext().securityContextRepository(securityContextRepository);
http.oauth2Login();
http.oauth2Client();
// This line sets the logout endpoint
http.logout().logoutUrl("/app/logout");
// This line sets the logout success handler
// Setting the property `flowable.security.oauth2.post-logout-redirect-url` instantiates this bean
// and configures the return URL after logging out with the SSO provider
oidcClientInitiatedLogoutSuccessHandlerProvider.ifAvailable(http.logout()::logoutSuccessHandler);
// This line is only needed if you want to enable Bearer token authentication
http.oauth2ResourceServer().jwt();
return http.build();
}
}
import org.springframework.core.annotation.Order;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.oauth2.jwt.JwtDecoder;
import org.springframework.security.web.context.HttpSessionSecurityContextRepository;
import org.springframework.security.web.SecurityFilterChain;
@Configuration(proxyBeanMethods = false)
public class SecurityActuatorConfiguration {
@Bean
@Order(6) // Actuator configuration should kick in before the Application Login
public SecurityFilterChain oauthActuatorSecurity(HttpSecurity http) throws Exception {
http
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.csrf()
.disable();
http
.requestMatcher(new ActuatorRequestMatcher())
.authorizeRequests()
.requestMatchers(EndpointRequest.to(InfoEndpoint.class, HealthEndpoint.class)).permitAll()
.requestMatchers(EndpointRequest.toAnyEndpoint()).hasAuthority(SecurityConstants.ACCESS_ACTUATORS)
.anyRequest().denyAll();
http.oauth2Login();
http.oauth2Client();
// This line is only needed if you want to enable Bearer token authentication
http.oauth2ResourceServer().jwt();
return http.build();
}
}
We can now start the application and head to http://localhost:8080. We will be redirected to the Azure SSO login.
We will also get the Permissions Requested pop up.
If you granted admin consent in the application configuration in the Azure portal. The permissions requested pop up will not be there.
Once you have signed in you will be redirected to the Flowable UI. However, you will be greeted by an empty application.
The reason for this is that the user does not have the needed permissions to see the applications. In the next section we are going to explain how you grant the user permissions.
Configuring Flowable Permissions
Flowable uses User Definitions with allowedFeatures to control what a certain user can see and what it can't see. With Azure AD you can use "App roles" to map users to Flowable User Definitions or even do it more granular by creating roles for the Flowable allowedFeatures.
First we are going to add a User Definition role. We already have some user definitions from the default idm models, so we are going to use them.
The value of the role needs to be USER_DEFINITION_KEY_user-default.
Once we have this role created we need to assign it to our user or even groups. To do this we need to go to the "Enterprise Applications" section of our Active Directory.
Once we are there we will head to "All Applications" and search for the application we created at the beginning. We've named it "Flowable Azure SSO Demo".
We now select the application and head to "Assign Users and Groups"
There we select and edit our user
And assign the default user role to the user
Finally, after these steps we can head to http://localhost:8080, and we will see the Flowable UI.
If you still do not see the UI, you should remove the Session Cookie and try again.
Conclusion
The Flowable products are extendable through the default Spring Boot (starter) approach. You can customize security of your application specific to the need of your environment in a really powerful way.
Integrations to standard identity providers are working easily as everything is based on the Spring Security framework.
Additionally, the security between different Flowable applications can be configured easily.