Single sign-on AuthenticationGenerally speaking, enterprise applications encompass multiple line-of-business (LOB) applications. These LOB applications are primarily accessed via a common authentication gateway module i.e. by implementing or making use of a single sign-on authentication. Is it similar in Bonita application too? Let’s find out, along with this, we will also figure out the process of integrating an existing SSO authentication module to Bonita application.

SSO Authentication

When the Bonita application is added to an existing enterprise application stack, Bonita users are authenticated via an existing SSO authentication module, instead of Bonita application’s login module. After successful authentication by the SSO module, users are directed to the Bonita application’s home page without seeking any additional login credentials.

Customer Authentication Module

Here’s a high-level process to integrate the customer authentication module in Bonita. In the example cited for reference, we have utilized Bonita 6.3.1 and Oracle Access Manager (OAM) for the authentication module. Generally speaking, the Bonita application is accessed via an enterprise dashboard, where authentication is performed against OAM service. The below diagram clearly illustrates the SSO authentication mechanism employed by the Bonita application.
Image depicting SSO Authentication in Bonita

Implementing SSO Authentication 

Implementing SSO Authentication in the Bonita application is a fairly simple process. The implementation process has been divided into five simple steps to make the users easily understand the concept of SSO Authentication in Bonita.

  1. Create a standalone Java project with Bonita dependencies.
  2. Implement SSOIntegrationFilter logic to validate the authentication cookie/token as per respective SSO mechanism, which is followed by the custom authentication module.
  3. Implement logic to create APISession for trusted users.
  4. Build a JAR and add to the Bonita classpath.
  5. Define SSOIntegrationFilter configuration into Bonita web.xml.

Step 1 – Creating a standalone Java project with Bonita dependencies

The first step is to create a standalone maven project and define all the required dependencies in the pom.xml file. Below is the code, which would help you achieve this activity:

[xml]
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
 <modelVersion>4.0.0</modelVersion>
 <groupId>com.company.bonita6</groupId>
 <artifactId>bonita-dashboard-sso</artifactId>
 <version>1.0</version>
 <packaging>jar</packaging>
 <properties>
 <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
 <bonita.version>6.3.1</bonita.version>
 <spring.version>3.1.1.RELEASE</spring.version>
 <spring.security.version>3.1.0.RELEASE</spring.security.version>
 <java.version>1.6</java.version>
 </properties>
 <dependencies>
 <dependency>
 <groupId>com.bonitasoft.engine</groupId>
 <artifactId>bonita-server-sp</artifactId>
 <version>${bonita.version}</version>
 <scope>provided</scope>
 </dependency>
 <dependency>
 <groupId>org.bonitasoft.console.common.server</groupId>
 <artifactId>common-server-sp</artifactId>
 <version>${bonita.version}</version>
 <scope>provided</scope>
 </dependency>
 <dependency>
 <groupId>com.bonitasoft.engine</groupId>
 <artifactId>bonita-common-sp</artifactId>
 <version>${bonita.version}</version>
 <scope>provided</scope>
 </dependency>
 <dependency>
 <groupId>com.bonitasoft.engine</groupId>
 <artifactId>bonita-client-sp</artifactId>
 <version>${bonita.version}</version>
 <scope>provided</scope>
 </dependency>
 </dependencies>
</project>
[/xml]

Step 2 – Servlet Filter Implementation

Subsequently, implement a servlet filter to ensure that each request has a valid SSO cookie/token. Bonita users also need to ensure that the token/cookie has not expired. As mentioned earlier, the process requires invoking the OAM web service to validate a cookie/token. Here’s the servlet filter implementation code:

[java]
public class CustomSSOIntegrationFilter implements Filter {
public void doFilter(ServletRequest servletRquest,
 ServletResponse servletResponse, FilterChain chain)
 throws IOException, ServletException {
 HttpServletRequest httpRequest = (HttpServletRequest) servletRquest;
 HttpSession httpSession = httpRequest.getSession();
 /**
 * Create Bonita session, if the user is a trusted user and session not yet
 * available.
 */
 if (httpSession.getAttribute(BONITA_SESSION) == null) {
 String ssoCookie = retrieveSSOCookie(httpRequest);
 if (ssoCookie == null || ssoCookie.trim().length() == 0) {
 /**
 * This is to ensure that if Bonita portal is accessed
 * directly (in case of Admin, Install, etc.) user will be
 * redirected to login page and SSO is ignored.
 */
 if (LOGGER.isLoggable(Level.WARNING)) {
 LOGGER.log(
 Level.WARNING,
 " ssoCookie is not available in the request, the user will be redirected to Bonita login page.");
 }
 } else {
 if (LOGGER.isLoggable(Level.FINE)) {
 LOGGER.log(Level.FINE, "Found ssoCookie in Request....."
 + ssoCookie);
 }
 String trustedUser = new OAMServiceStub(OAM_SERVICE_URL).authenticateSSOCookie(ssoCookie);
 if (trustedUser == null || trustedUser.trim().length() == 0) {
 new InvalidUserException(
 "Invalid User credentials. Please login with valid user credentials.");
 }
 BonitaSessionCreator.getInstance().createSession(httpRequest,
 trustedUser);
 }
 }
 chain.doFilter(httpRequest, servletResponse);
 }
private String retrieveSSOCookie(final HttpServletRequest request) {
 String ssoCookie = "";
 Cookie cookies[] = request.getCookies();
 if (cookies != null) {
 for (int i = 0; i < cookies.length; i++) {
 if (cookies[i].getName().equalsIgnoreCase(SSO_COOKIE)) {
 ssoCookie = cookies[i].getValue();
 }
 }
 }
 return ssoCookie;
 }
}
[/java]

Step 3 – Create APISession

Once the SSO authentication module successfully validates a cookie/token, the next step is to create an APISession using Bonita application’s login API. Please make a note, when an APISession is available in the request, Bonita does not redirect users to the login page till the user session is valid.

[java]
public class BonitaSessionCreator {
 private static final Logger LOGGER = Logger
 .getLogger(BonitaSessionCreator.class.getName());
 private static final String BONITA_SESSION = "apiSession";
 private static BonitaSessionCreator sessionCreator = null;
 public synchronized static BonitaSessionCreator getInstance() {
 if (sessionCreator == null) {
 sessionCreator = new BonitaSessionCreator();
 }
 return sessionCreator;
 }
 public void createSession(HttpServletRequest httpRequest, String trustedUser)
 throws ServletException {
 HttpSession httpSession = httpRequest.getSession();
 /**
 * trusted user name is considered as default password to log onto
 * bonita. Or we can obtain the password form SSO module too.
 */
 String password = trustedUser.toLowerCase();
 try {
 loginIntoBonita(trustedUser, password, httpSession);
 } catch (LoginException le) {
 if (LOGGER.isLoggable(Level.WARNING)) {
 LOGGER.log(Level.WARNING,
 "Unable to login into Bonita for trusted user = "
 + trustedUser);
 }
throw new ServletException(e);
 }
 }
 private APISession loginIntoBonita(String trustedUser, String password,
 HttpSession httpSession) throws ServletException, LoginException {
 APISession apiSession = null;
 try {
 LoginAPI loginAPI = TenantAPIAccessor.getLoginAPI();
 apiSession = loginAPI.login(trustedUser, password);
 httpSession.setAttribute(BONITA_SESSION, apiSession);
 if (LOGGER.isLoggable(Level.FINE)) {
 LOGGER.log(Level.FINE, "Bonita session created for the user= "
 + trustedUser);
 }
 } catch (LoginException le) {
 throw le;
 } catch (Exception e) {
 if (LOGGER.isLoggable(Level.SEVERE)) {
 LOGGER.log(
 Level.SEVERE,
 "Error while creating bonita session for the user = "
 + trustedUser + ", " + password
 + e.getMessage(), e);
 }
 throw new ServletException(
 "Unable login into Bonita Portal. Please contact System Administrator. "
 + e.getMessage());
 }
 return apiSession;
 }
 }
[/java]

Step 4 – Building the Bonita Java Project

This is an important step, execute the maven install/build command to build a standalone Bonita Java project .jar file. Here’s the code snippet, which would help you accomplish this activity:

[java]
<Bonita_Home>/webapps/bonita6/WEB-INF/lib/bonita-custom-sso-1.0.jar
[/java]

Step 5 – SSOIntegrationFilter Configuration into Bonita web.xml

The final step is to add SSOIntegrationFilter configuration in the Bonita web.xml file. Add the below filter mapping element in the web.xml file, which can be located in the path mentioned below.

[xml 1="[/xml" language="<Bonita_Home>/webapps/bonita6/WEB-INF/web.xml"]</pre>
<h6><span style="color: #000000;">Add the below filter definition before “InternalSSOFilter” filter definition</span></h6>
<pre>[xml]
 <!-- Custom SSO filter definition-->
<filter>
 <filter-name>CustomSSOIntegrationFilter</filter-name>
 <filter-class>com.company.bonita6.sso.filter.CustomSSOIntegrationFilter</filter-class>
</filter>
[/xml]
Add the below filter mapping before “AuthenticationFilter” filter mapping:
[xml]
<!-- Custom SSO filter mapping-->
 <filter-mapping>
 <filter-name>CustomSSOIntegrationFilter</filter-name>
 <url-pattern>/portal/BonitaConsole.html</url-pattern>
 </filter-mapping>
 <filter-mapping>
 <filter-name>CustomSSOIntegrationFilter</filter-name>
 <url-pattern>/portal/homepage</url-pattern>
 </filter-mapping>
[/xml]
Add the below filter mapping before “ShutdownListener” listener:
[xml]
<filter-mapping>
 <filter-name>AuthorizationFilter</filter-name>
 <url-pattern>/portal/BonitaConsole.html</url-pattern>
 </filter-mapping>
 <filter-mapping>
 <filter-name>AuthorizationFilter</filter-name>
 <url-pattern>/portal/homepage</url-pattern>
</filter-mapping>
[/xml]

Conclusion

The above guidance would certainly help Bonita users to integrate existing SSO Authentication module to Bonita application. Although, users are authenticated via the SSO authentication module, Bonita application still requires user data to be present in the Bonita user tables in journal schema. The Bonita application performs workflow/task authorization based on a users membership level. Nevertheless, there are several other ways to sync users information from LDAP/AD into Bonita Journal, which is an altogether different topic and can be discussed in a separate blog.

Author

Hari Prasad Alla is a Associate Technical Architect at Evoke Technologies. He has strong expertise in requirements analysis, design, implementation and release. He has technically adept in Bonitasoft BPM, Java, Spring MVC, Spring Batch, Spring Integration, Hibernate, Web Services (SOAP, REST), JMS, Jasper reports, Hadoop and NoSQL (MongoDB).
Please follow and share

11 Comments

  1. Jose Aróstegui

    May 12, 2016

    Great job!
    Have you tested it with Comunity version?
    Thanks!
    Jose.

    • Thanks Jose for the feedback.
      We haven’t tested this in Community version. However, we believe this approach should work in community platform. Please let us know if we can help you.
      Hari

  2. Amit Dhage

    September 19, 2016

    Hi Hari,
    I’m working on Bonita 7.2. I have a requirement of configuring SSO with CAS in Bonita. I have implemented it using Bonita document but I need to do some customization here. After CAS login page before redirecting to home page some custom code needs to be added. Can you help me in understanding how custom CAS filter can be implemented.
    Thanks,
    Amit

    • Hello Amit,
      Firstly, apologies for the delay in responding to your comments.
      After successful authentication, Bonita BPM redirects the page to source URL (custom app). You may add a servlet filter in the Bonita web.xml file for your source URL. If you are accessing the general Bonita BPM portal, it redirects you to the /portal/homepage, which enables you to add filter mapping to the homepage URL.
      Regards,
      Hari Alla

      • Amit Dhage

        October 18, 2016

        Hello Hari,
        Thank you for the reply.
        Could you please explain this with steps like you have mentioned for SSO Authentication above.
        Regards,
        Amit

        • Hari Alla

          October 19, 2016

          Amit,
          You can add the Servlet filter for Homepage url, as mentioned in Step 5 of this blog.
          Thanks,
          Hari Alla

  3. Alex

    September 26, 2016

    Hi, could you explain how sso cookie is set?

    • Hi Alex,
      SSO cookie is not distinct than a regular http cookie. The value of the cookie depends on authentication service that is being used. In this case, we set encrypted token that is generated by an OAM server. Hence, we request OAM service to validate the token for the next consecutive user requests.
      Please let us know if you are looking for any other specific information.
      Thanks,
      Hari Alla

      • Alex

        October 17, 2016

        Hi,
        I added necessary cookies, but there is another problem, it seems that i must set also PERMISSIONS_SESSION_PARAM_KEY (“permissions”) session attribute, otherwise i’m getting error: Permission denied: you do not have the rights to perform this action.
        Thanx, Alex.

        • Hari Alla

          October 19, 2016

          Thanks Alex for the update, we implemented this using 6.5 version. I am not too sure if PERMISSIONS_SESSION_PARAM_KEY is newly added in 7.0 version. Could you please let me know when do you get the error? And are you able to see Bonita portal page? Does the user has ‘User’ profile configured?

          • Alex

            November 4, 2016

            I had to use bonita private PermissionsBuilderAccessor class (added console-common-7.3.2.jar dependency to maven), could not find any other way:

            LoginAPI loginAPI = TenantAPIAccessor.getLoginAPI();
            apiSession = loginAPI.login(trustedUser, password);
            long userId = apiSession.getUserId();
            IdentityAPI identityAPI = TenantAPIAccessor.getIdentityAPI(apiSession);
            User user = identityAPI.getUser(userId);
            PermissionsBuilder permissionBuilder = PermissionsBuilderAccessor.createPermissionBuilder(apiSession);
            Set permissions = permissionBuilder.getPermissions();
            httpSession.setAttribute(API_SESSION_PARAM_KEY, apiSession);
            httpSession.setAttribute(USERNAME_SESSION_PARAM, apiSession.getUserName());
            httpSession.setAttribute(USER_SESSION_PARAM_KEY, user);
            httpSession.setAttribute(PERMISSIONS_SESSION_PARAM_KEY, permissions);

Leave a comment