Skip to content

Instantly share code, notes, and snippets.

@sturdy5
Last active August 29, 2015 14:12
Show Gist options
  • Save sturdy5/6489134078536feb3323 to your computer and use it in GitHub Desktop.
Save sturdy5/6489134078536feb3323 to your computer and use it in GitHub Desktop.
Docfinity SSO

OIT DocFinity Single Sign-On using Trusted Authentication

This is a short guide to setting up Trusted Authentication into OIT's DocFinity product. As OIT doesn't support some of this functionality except as a services engagement from OIT, some of this information is not well documented. Consequently, this was put together using trial and error until I was able to get the SSO to work.

Versions

This was tested with version 10.11 of DocFinity.

Concept

In order to maintain a viable level of work in DocFinity, we would like to separate instances based on the type of work. In order to prevent users from having to log into multiple instances, a single sign-on application will need to be put together to act as a front-end to each instance.

Each DocFinity instance will have the users managed by a single authentication authority.

Concept Diagram

In order to maintain the highest security possible, the username and password will need to be authenticated with a source before being passed to the DocFinity Work Instances. The first step of the SSO application is to authenticate and encrypt the username from the core instance. This instance will need to have all of the users identified so that this will work for anyone who needs to access any of the instances.

Configuring the Header Value for the Encrypted Username

A DocFinity administrator can change the names of the username and password parameters through Administration > System > System Properties > System > Authentication > trustedAuth.header.*

Parameter Default Value
encryptedPassword j_password_enc
encryptedUsername j_username_enc

Enabling Trusted Authentication

If you are looking to be able to authenticate with DocFinity without using the password, you need to enable trusted authentication. This not a setting that can be set through the admin system settings page, it needs to be done directly in the database. The SQL that you need to run is

UPDATE 
	SystemProperties
SET 
	value = 'true'
WHERE 
	name = 'trustedAuth.active'

This will allow you to authenticate by supplying only an encrypted username.

There are multiple modes for trusted authentication. The following table shows you how the requests will be processed based on various settings and parameters

TrustedAuth.Active Database Setting Trusted IP Username Password Authentication
True Yes plain text passes
True No plain text fails
True/False Yes/No plain text plain text passes
True No encrypted passes
True/False Yes/No encrypted encrypted passes

If you are planning on using Trusted IP, you will need to update a properties file with the comma separated list of acceptable IP addresses.

<installDir>/OITAppServer/webapps/docfinity/WEB-INF/classes/config/common/security/spring-security.properties
trustedIps=127.0.0.1,192.168.0.5

The rest of this will primarily focus on encrypted username/passwords. If you are interested in Trusted IPs, please see your DocFinity Authentication Technical Guide or contact OIT.

Launching DocFinity

There are two parameters that need to be included in the call - j_username_enc and j_password_enc. If you enabled Trusted Authentication then only j_username_enc is needed. The url should look like this:

http://servername:port/docfinity/application/index.html?j_username_enc=encryptedusername&j_password_enc=encryptedpassword

Alternatively, you can use the new, mobile-friendly, URL API

http://servername:port/docfinity/urlapi/main//?j_username_enc=encryptedusername&j_password_enc=encryptedpassword

Encrypting the Parameters

Unfortunately, there is no documentation on how to encrypt the username and password. I had to reverse engineer the URL API Assistant (see below) to figure out how to encrypt the username and password.

There is a REST API that is available that can be used to encrypt the username and password. Unfortunately, out of the box, the tomcat installation is not built to handle CORS requests. So the first step is to enable CORS on tomcat. I used the following site as a guide to enabling CORS in tomcat: http://tomcat.apache.org/tomcat-8.0-doc/config/filter.html#CORS_Filter

The TL;DR version is that you need to add the following to the web.xml of the docfinity app:

    <!-- A filter to allow CORS for the Rest API -->
    <filter>
        <filter-name>CorsFilter</filter-name>
        <filter-class>org.apache.catalina.filters.CorsFilter</filter-class>
        <init-param>
            <param-name>cors.allowed.headers</param-name>
            <param-value>Origin, Accept, X-Requested-With, Content-Type, Access-Control-Request-Method, Access-Control-Request-Headers, Authorization</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>CorsFilter</filter-name>
        <url-pattern>/webservices/rest/*</url-pattern>
    </filter-mapping>

You have to provide the cors.allowed.headers init param because the default doesn't include Authorization.

The URL to the encrypt service that can be used to get the encrypted username and password looks like this -

http://servername:port/docfinity/webservices/rest/ajax/encrypt?u=username&p=password

The REST service should be called using the POST method and the Content-Type needs to be set to application/x-www-form-urlencoded; charset=UTF-8. Additionally, it uses Basic Authentication to verify that you have permission to call the service. In order to support Basic Authentication, a header parameter needs to be added

Authorization: Basic Base64EncodedUsernameAndPassword

There are a couple ways to Base64 Encode the username and password. In modern browsers there is a built in function btoa() which accepts a string that it converts into Base64. In Internet Explorer 8 and lower, the btoa() function is not available; in which case you can specify your own equivalent implementation. The script below combines both methods. It will use btoa() if it is available, otherwise it will use the equivalent implmentation:

/**
 *
 *  Base64 encode / decode
 *  http://www.webtoolkit.info/
 *
 *  Modified to exit out to the browser capabilities if they are available.
 *
 **/
var Base64 = {

  // private property
  _keyStr : "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",

  // public method for encoding
  encode : function (input) {
    var output = "";

    input = Base64._utf8_encode(input);

    // check to see if btoa is available
    if (typeof btoa == "function") {
      output = btoa(input);
    } else {
      var chr1, chr2, chr3, enc1, enc2, enc3, enc4;
      var i = 0;

      while (i < input.length) {

        chr1 = input.charCodeAt(i++);
        chr2 = input.charCodeAt(i++);
        chr3 = input.charCodeAt(i++);

        enc1 = chr1 >> 2;
        enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
        enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
        enc4 = chr3 & 63;

        if (isNaN(chr2)) {
          enc3 = enc4 = 64;
        } else if (isNaN(chr3)) {
          enc4 = 64;
        }

        output = output +
        this._keyStr.charAt(enc1) + this._keyStr.charAt(enc2) +
        this._keyStr.charAt(enc3) + this._keyStr.charAt(enc4);

      }
    }
    return output;
  },

  // public method for decoding
  decode : function (input) {
    // check to see if atob is available
    var output = "";

    input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");    

    // check to see if atob is available
    if (typeof atob == "function") {
    	output = atob(input);
    } else {
      var chr1, chr2, chr3;
      var enc1, enc2, enc3, enc4;
      var i = 0;

      while (i < input.length) {

        enc1 = this._keyStr.indexOf(input.charAt(i++));
        enc2 = this._keyStr.indexOf(input.charAt(i++));
        enc3 = this._keyStr.indexOf(input.charAt(i++));
        enc4 = this._keyStr.indexOf(input.charAt(i++));

        chr1 = (enc1 << 2) | (enc2 >> 4);
        chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
        chr3 = ((enc3 & 3) << 6) | enc4;

        output = output + String.fromCharCode(chr1);

        if (enc3 != 64) {
          output = output + String.fromCharCode(chr2);
        }
        if (enc4 != 64) {
          output = output + String.fromCharCode(chr3);
        }
  
      }
    }
    output = Base64._utf8_decode(output);

    return output;
  },

  // private method for UTF-8 encoding
  _utf8_encode : function (string) {
    string = string.replace(/\r\n/g,"\n");
    var utftext = "";

    for (var n = 0; n < string.length; n++) {

      var c = string.charCodeAt(n);

      if (c < 128) {
        utftext += String.fromCharCode(c);
      } else if((c > 127) && (c < 2048)) {
        utftext += String.fromCharCode((c >> 6) | 192);
        utftext += String.fromCharCode((c & 63) | 128);
      } else {
        utftext += String.fromCharCode((c >> 12) | 224);
        utftext += String.fromCharCode(((c >> 6) & 63) | 128);
        utftext += String.fromCharCode((c & 63) | 128);
      }

    }

    return utftext;
  },

  // private method for UTF-8 decoding
  _utf8_decode : function (utftext) {
    var string = "";
    var i = 0;
    var c = c1 = c2 = 0;

    while ( i < utftext.length ) {

      c = utftext.charCodeAt(i);

      if (c < 128) {
        string += String.fromCharCode(c);
        i++;
      } else if((c > 191) && (c < 224)) {
        c2 = utftext.charCodeAt(i+1);
        string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
        i += 2;
      } else {
        c2 = utftext.charCodeAt(i+1);
        c3 = utftext.charCodeAt(i+2);
        string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
        i += 3;
      }

    }

    return string;
  }

}

Generating Testing Trusted Authentication URLs

NOTE: This only works when you've enabled Trusted Authentication. If you have not enabled Trusted Authentication then don't select Send Trusted as the type).

You can generate the URL that should be used to authenticate users using the URL API Assistant. The URL API Assistant simplifies the interaction, complication, and cryptic nature of URL API interaction. It assists with the creation of static URLs for entry into DocFinity's many key functionalities including interacting with batches, viewing documents, searching, interacting with BPM jobs, uploading files, using forms, and viewing dashboards.

The URL API Assistant is installed automatically with DocFinity and can be accessed via a web browser at the following URL:

http://servername:port/contextroot/urlapiassistant/

In the first section, the options allow you to specify the values necessary for authenticating into the DocFinity instance.

  • Set the Type to Send Trusted
  • Enter the username that you want to authenticate.
  • At the bottom of the page, click on the button that says Generate URL

Additional Notes

Custom Logout Page

By default, when a user logs out of DocFinity, they are returned to the Login screen. Since users utilizing single sign on bypass the Login screen when they access DocFinity, seeing the Login screen may be confusing or seen as an error by some users. To avoid displaying the Login screen after logout, you can specify another page to display by changing the UI > Logout > custom.logout.url system property through System Administration.

Central Administration

When there are multiple instances of DocFinity, central administration can be used to administer all instances. How it is setup is unknown, but you can access it by going to the following URL:

http://servername:port/docfinity/application/index.html#module=central

Administrators must have the Central Administration Feature Right in the DocFinity instance that functions as the Central Administration entry point

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment