DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Related

  • Authentication With Remote LDAP Server in Spring WebFlux
  • Authentication With Remote LDAP Server in Spring Web MVC
  • How to Implement Two-Factor Authentication in A Spring Boot OAuth Server? Part 2: Under the Hood
  • Spring Security With LDAP Authentication

Trending

  • You Are Using Claude Wrong (And So Is Everyone You Know)
  • Building AI-Powered Java Applications With Jakarta EE and LangChain4j
  • Getting Started With Agentic Workflows in Java and Quarkus
  • Multi-Scale Feature Learning in CNN and U-Net Architectures
  1. DZone
  2. Coding
  3. Frameworks
  4. Spring Boot-Embedded Camunda Single Sign-on With SAML IDP Provider

Spring Boot-Embedded Camunda Single Sign-on With SAML IDP Provider

From flow chart to implementation.

By 
Pradeep Poojari user avatar
Pradeep Poojari
·
Dec. 26, 20 · Tutorial
Likes (3)
Comment
Save
Tweet
Share
7.1K Views

Join the DZone community and get the full member experience.

Join For Free

Single sign-on flow

Single sign-on flow:

  • User tries to access Camunda web apps
  • Camunda apps detect that the user has not logged into IDP and creates SAML request redirects the user to IDP 
  • The user enters credentials in IDP. After successful login, IDP sends a SAML response to Camunda
  • The app parses response and sets into the spring security context and passes the control to the Camunda Authentication filter 
  • The Camunda custom authentication provider takes authenticated user details, such as name and group, and passes them on to the Camunda authorization service
  • The Camunda authorization service, based on user roles, opens a welcome page

Implementation 

To achieve SSO, we should use Spring Security so that Spring framework handles the authentication and passes the authenticated user on to Camunda. 

We only need to add the ContainerBasedAuthenticationFilter that ships with the Camunda product and provide a custom authentication provider.  

By implementing a class that implements the org.camunda.bpm.engine.rest.security.auth.AuthenticationProvider interface, one should be able to provide authentication details.  

I have used Onelogin as the IDP provider, created a trial account in https://www.onelogin.com/free-trial, and set up the application. Then, I downloaded metadata.xml and placed the metadata.xml file inside the resource directory.

Application.yaml file:

YAML
 




xxxxxxxxxx
1
28


 
1
onelogin:
2
  metadata-path: classpath:onelogin_metadata_1268214.xml
3
  sp:
4
    protocol: http
5
    host: localhost:8080
6
    path: /
7
    key-store:
8
      file: classpath:keystore.jks
9
      alias: onelogin
10
      password: secret
11
      
12
    
13
spring.datasource.url: jdbc:h2:file:./camunda-h2-database4
14
spring.h2.console.enabled: true
15
camunda.bpm:
16
  filter:
17
    create: All tasks
18
    
19
camunda:
20
  bpm:
21
    authorization:
22
      enabled: true
23
      
24
    admin-user:
25
      id: admin
26
      password: admin
27

          
28

          



Spring security Implementation to connect to IDP:

Java
 




x
92


 
1
package com.prad.samldemo.config;
2

          
3
import static org.springframework.security.extensions.saml2.config.SAMLConfigurer.saml;
4

          
5
import java.util.Collections;
6

          
7
import javax.servlet.Filter;
8

          
9
import org.camunda.bpm.engine.rest.security.auth.ProcessEngineAuthenticationFilter;
10
import org.camunda.bpm.webapp.impl.security.auth.ContainerBasedAuthenticationFilter;
11
import org.springframework.beans.factory.annotation.Autowired;
12
import org.springframework.beans.factory.annotation.Value;
13
import org.springframework.boot.web.servlet.FilterRegistrationBean;
14
import org.springframework.context.annotation.Bean;
15
import org.springframework.context.annotation.Configuration;
16
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
17
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
18
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
19

          
20
@EnableWebSecurity
21
@Configuration
22
public class SecurityConfig extends WebSecurityConfigurerAdapter {
23

          
24
    @Value("${onelogin.metadata-path}")
25
    private String metadataPath;
26

          
27
    @Value("${onelogin.sp.protocol}")
28
    private String spProtocol;
29

          
30
    @Value("${onelogin.sp.host}")
31
    private String spHost;
32

          
33
    @Value("${onelogin.sp.path}")
34
    private String spBashPath;
35

          
36
    @Value("${onelogin.sp.key-store.file}")
37
    private String keyStoreFile;
38

          
39
    @Value("${onelogin.sp.key-store.password}")
40
    private String keyStorePassword;
41

          
42
    @Value("${onelogin.sp.key-store.alias}")
43
    private String keyStoreAlias;
44

          
45
    @Value("${onelogin.sp.protocol}")
46
    private String protocol;
47

          
48
    @Autowired
49
    private SAMLUserService samlUserService;
50

          
51
    @Override
52
    protected void configure(final HttpSecurity http) throws Exception {
53
        // @formatter:off
54
        http.csrf().disable();
55
        http.authorizeRequests().antMatchers("/saml/**").permitAll().anyRequest().authenticated().and().apply(saml())
56
                .userDetailsService(samlUserService).serviceProvider().protocol(spProtocol).hostname(spHost)
57
                .basePath(spBashPath).keyStore().storeFilePath(keyStoreFile).keyPassword(keyStorePassword)
58
                .keyname(keyStoreAlias).and().and().identityProvider().metadataFilePath(metadataPath).and().and();
59
        // @formatter:on
60
    }
61

          
62
    @Bean
63
    public FilterRegistrationBean containerBasedAuthenticationFilter() {
64
        System.out.println("Inside Spring Filter");
65
        FilterRegistrationBean filterRegistration = new FilterRegistrationBean();
66
        filterRegistration.setFilter(new ContainerBasedAuthenticationFilter());
67
        filterRegistration.setInitParameters(Collections.singletonMap("authentication-provider",
68
                "com.prad.samldemo.config.SpringSecurityAuthenticationProvider"));
69
        filterRegistration.setOrder(101); // make sure the filter is registered after the Spring Security Filter Chain
70
        filterRegistration.addUrlPatterns("/camunda/*");
71
        return filterRegistration;
72
    }
73
    
74
    @Bean
75
    public FilterRegistrationBean<Filter> processEngineAuthenticationFilter() {
76
        FilterRegistrationBean<Filter> registration = new FilterRegistrationBean<>();
77
        registration.setName("camunda-auth");
78
        registration.setFilter(getProcessEngineAuthenticationFilter());
79
        registration.setInitParameters(Collections.singletonMap("authentication-provider",
80
                "com.prad.samldemo.config.SpringSecurityAuthenticationProvider"));
81
        registration.addUrlPatterns("/engine-rest/*");
82
        return registration;
83
    }
84

          
85
    @Bean
86
    public Filter getProcessEngineAuthenticationFilter() {
87
        return new ProcessEngineAuthenticationFilter();
88
    }
89

          
90
    
91
}
92

          



Container-based authentication filter implementation:

Java
 




xxxxxxxxxx
1
55


 
1
package com.prad.samldemo.config;
2

          
3
import org.camunda.bpm.engine.ProcessEngine;
4
import org.camunda.bpm.engine.rest.security.auth.AuthenticationResult;
5
import org.camunda.bpm.engine.rest.security.auth.impl.ContainerBasedAuthenticationProvider;
6
import org.springframework.security.core.Authentication;
7
import org.springframework.security.core.context.SecurityContextHolder;
8

          
9
import javax.servlet.http.HttpServletRequest;
10

          
11
import java.security.Principal;
12
import java.util.List;
13
import java.util.stream.Collectors;
14

          
15
public class SpringSecurityAuthenticationProvider extends ContainerBasedAuthenticationProvider {
16

          
17
    @Override
18
    public AuthenticationResult extractAuthenticatedUser(HttpServletRequest request, ProcessEngine engine) {
19

          
20
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
21

          
22
        if (authentication == null) {
23
            return AuthenticationResult.unsuccessful();
24
        }
25

          
26
        String name = ((User)authentication.getPrincipal()).getId();
27
        List<String> roles = ((User)authentication.getPrincipal()).getRoles();
28
        if (name == null || name.isEmpty()) {
29
            return AuthenticationResult.unsuccessful();
30
        }
31

          
32
        AuthenticationResult authenticationResult = new AuthenticationResult(name, true);
33
      //  authenticationResult.setGroups(getUserGroups(authentication));
34
        authenticationResult.setGroups(roles);
35
        
36
        
37

          
38
        return authenticationResult;
39
    }
40

          
41
    private List<String> getUserGroups(Authentication authentication){
42

          
43
        List<String> groupIds;
44

          
45
        groupIds = authentication.getAuthorities().stream()
46
                .map(res -> res.getAuthority())
47
                .map(res -> res.substring(5)) // Strip "ROLE_"
48
                .collect(Collectors.toList());
49

          
50
        return groupIds;
51

          
52
    }
53

          
54
}
55

          



SAML user service:

Java
 




xxxxxxxxxx
1
20


 
1
package com.prad.samldemo.config;
2

          
3
import java.util.Arrays;
4

          
5
import org.springframework.security.core.userdetails.UsernameNotFoundException;
6
import org.springframework.security.saml.SAMLCredential;
7
import org.springframework.security.saml.userdetails.SAMLUserDetailsService;
8
import org.springframework.stereotype.Service;
9

          
10
@Service
11
public class SAMLUserService implements SAMLUserDetailsService {
12

          
13
  
14
  @Override
15
  public Object loadUserBySAML(SAMLCredential credential) throws UsernameNotFoundException {
16
    String[] array = credential.getAttributeAsStringArray("roles");
17
    return new User(credential.getNameID().getValue() , Arrays.asList(array));
18
  }
19
}
20

          



User model:

Java
 




xxxxxxxxxx
1
32


 
1
package com.prad.samldemo.config;
2

          
3
import java.util.List;
4

          
5
public class User {
6

          
7
  private String id;
8
  
9
  private List<String> roles;
10

          
11
  public String getId() {
12
    return id;
13
}
14

          
15
public void setId(String id) {
16
    this.id = id;
17
}
18

          
19
public List<String> getRoles() {
20
    return roles;
21
}
22

          
23
public void setRoles(List<String> roles) {
24
    this.roles = roles;
25
}
26

          
27
public User(String id, List<String> roles) {
28
    this.id = id;
29
    this.roles = roles;
30
  }
31
}
32

          



authentication Spring Security Spring Framework Camunda

Opinions expressed by DZone contributors are their own.

Related

  • Authentication With Remote LDAP Server in Spring WebFlux
  • Authentication With Remote LDAP Server in Spring Web MVC
  • How to Implement Two-Factor Authentication in A Spring Boot OAuth Server? Part 2: Under the Hood
  • Spring Security With LDAP Authentication

Partner Resources

×

Comments

The likes didn't load as expected. Please refresh the page and try again.

  • RSS
  • X
  • Facebook

ABOUT US

  • About DZone
  • Support and feedback
  • Community research

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 215
  • Nashville, TN 37211
  • [email protected]

Let's be friends:

  • RSS
  • X
  • Facebook