Single Sign On implementation in Camunda

Hello All,
We have requirement to implement SSO in Camunda for below Scenario-
There is the Centralized Portal with Camunda Tasklist Link. So once user login to the Centralized portal and click to Camunda Tasklist link then directly the tasklist should get open without asking username and password.

We have explored the filter classes(StatelessUserAuthenticationFilter) mentioned in below project for our Camunda Springboot Application(with LDAP integration) but it is not working for us.
https://github.com/camunda-consulting/code/tree/master/snippets/springboot-security-sso

Is there any way to implement the SSO across the Centralized Portal and Camunda Application ?

Regards,
Tejpal Singh

Hi @tejpalhura1, I’m using some plugins provided for keycloak and camunda. In my repo you can find how I put this to work.

Its references are https://github.com/camunda/camunda-bpm-identity-keycloak and https://github.com/iceman91176/camunda-bpm-auth-keycloak-sso for camunda-tomcat.

I wish that could help you.

1 Like

Is a two fold problem.

  1. REST API:

    @Component
    public class StatelessUserAuthenticationFilter implements Filter {
     private ProcessEngine processEngine;
     private UserEntitlements userEntitlements;
     @Autowired
     public void setProcessEngine(ProcessEngine processEngine) {
         this.processEngine = processEngine;
     }
    
     @Autowired
     public void setUserEntitlements(UserEntitlementsImpl userEntitlements) {
         this.userEntitlements = userEntitlements;
     }
    
     @Override
     public void init(FilterConfig filterConfig) {
    
     }
    
     @Override
     public void doFilter(
             ServletRequest request, ServletResponse response, FilterChain chain
     ) throws IOException, ServletException {
         String userName = userEntitlements.getUsername();
         try {
             List<String> groupNames = getGroupIds(userName);
             List<String> tenants = userEntitlements.getUserTenantNames(userName);
             processEngine.getIdentityService().setAuthentication(userName, groupNames, tenants);
             chain.doFilter(request, response);
         } finally {
             clearAuthentication(processEngine);
         }
     }
    
     @Override
     public void destroy() {
    
     }
    
     private List<String> getGroupIds(String userName) {
         return userEntitlements.getUserGroupIds(userName);
     }
    
     private void clearAuthentication(ProcessEngine engine) {
         engine.getIdentityService().clearAuthentication();
     }
    }
    
  2. For Camunda Admin Tools (Cockpit, Tasklist, Admin etc)

    @Component
    public class SpringContainerBasedAuthenticationFilter extends ContainerBasedAuthenticationFilter {
     private SpringSecurityAuthenticationProvider springSecurityAuthenticationProvider;
    
     @Autowired
     public void setSpringSecurityAuthenticationProvider(
             SpringSecurityAuthenticationProvider springSecurityAuthenticationProvider
     ) {
         this.springSecurityAuthenticationProvider = springSecurityAuthenticationProvider;
     }
    
     @Override
     public void init(FilterConfig filterConfig) throws ServletException {
         userAuthentications = new AuthenticationService();
         authenticationProvider = springSecurityAuthenticationProvider;
     }
    }
    
    
    @Component
    public class SpringSecurityAuthenticationProvider extends ContainerBasedAuthenticationProvider {
     private UserEntitlements userEntitlements;
    
     @Autowired
     public void setUserEntitlements(CeepUserEntitlementsImpl userEntitlements) {
         this.userEntitlements = userEntitlements;
     }
    
     @Override
     public AuthenticationResult extractAuthenticatedUser(
             HttpServletRequest request, ProcessEngine engine
     ) {
         String userName = userEntitlements.getUsername();
         AuthenticationResult authenticationResult = AuthenticationResult.successful(userName);
         authenticationResult.setGroups(getGroupIds(userName));
         authenticationResult.setTenants(userEntitlements.getUserTenantNames(userName));
         return authenticationResult;
     }
    
     /**
      * Adds user to the camuna-admin group on localhost only for easy access to the Cockpit
      * so we don't need to keep editing our roles.
      */
     private List<String> getGroupIds(String userName) {
         List<String> groupNames = userEntitlements.getUserGroupIds(userName);
         AppEnv env = AppEnv.fromString(System.getProperty(ACTIVE_PROFILES_PROPERTY_NAME));
         if(env == Local && !groupNames.contains(CAMUNDA_ADMIN)) {
             groupNames.add(CAMUNDA_ADMIN);
         }
         return groupNames;
     }
    }
    

Where UserEntitlements is my own interface you can impl against your SSO service.

public interface UserEntitlements {
    String getUsername(...);
    List<Group> getUserGroups(String userId);
    List<String> getUserGroupIds(String userId);
    List<String> getUserTenantNames(String userId);
}

From this point on, you no longer maintain your users and groups inside Camunda’s DB. Instead only keep there the Authorization rules you might need.

@gabepurnam - Let me rephrase the problem which Tejpal is trying to ask:

We have a centralised portal through which we try to access the tasklists page of the user who has logged in to the centralised portal. But when we click on the tasklist URL it actually opens the login screen of Camunda webapp. It asks to login again. When we login then it returns with the the tasklist page.

Our problem is we want to skip this extra login and directly access the tasklist page. When we tried to access the tasklist endpoint directly through postman or any other UI page, we got 403 error.

As per our understanding when the login screen comes at that time a csrf\xsrf token is generated from the server side and is returned back to the caller which then has to send this token in all subsequent requests for the same session so that server authenticates that call\user against this token.

We need to know how can we get this initial token from Camunda server without the Login\Welcome screen so that we can pass this token in the tasklist endpoint url and get the tasklist page opened.

Please help in resolving this problem.

Thanks!

@paulbors: Let me rephrase the problem which Tejpal is trying to ask:

We have a centralised portal through which we try to access the tasklists page of the user who has logged in to the centralised portal. But when we click on the tasklist URL it actually opens the login screen of Camunda webapp. It asks to login again. When we login then it returns with the the tasklist page.

Our problem is we want to skip this extra login and directly access the tasklist page. When we tried to access the tasklist endpoint directly through postman or any other UI page, we got 403 error.

As per our understanding when the login screen comes at that time a csrf\xsrf token is generated from the server side and is returned back to the caller which then has to send this token in all subsequent requests for the same session so that server authenticates that call\user against this token.

We need to know how can we get this initial token from Camunda server without the Login\Welcome screen so that we can pass this token in the tasklist endpoint url and get the tasklist page opened.

Please help in resolving this problem.

Thanks!

Like I said, is a two fold problem. You need to setup SSO for both the REST API calls and #2 above, the scenario you just described.

Try the code I gave you, it will work.

1 Like

Thanks for the suggestions Paul.

We have now another problem. The centralised portal can not send any information related to the user i.e. username, password or the token.

Actually the centralised portal uses windows authentication. So when the user logs in to its machine and then try to open the portal URL, it gets opened without asking any credentials as it is authenticating the user using windows authentication.

So from the portal when the user clicks on the Camunda webapp (tasklists) URL, it does not pass any information.

How can now we authenticate the user? The only way could be if we can enable the windows authentication at Camunda side as well. Is it doable?

Please advise how to proceed ahead for the above issue.

Thanks!

You must follow the best practices and implement your own custom identity service.

I fronted my app with OIDC which handles the user SSO part, and then provided a read-only Identity Provider. Will post my full solution later once I’m done testing my latest code changes.

For Windows Login / LDAP against your Windows Domain Active Directory, why not use the LDAP Identify Provider already documented by Camunda rather than implementing a new one?