How to synchronize users

<< Click to Display Table of Contents >>

Navigation:  How to's >

How to synchronize users

Overview

For Bizagi PaaS, you need to register your end users in Bizagi Work portal.

When using an integrated authentication (i.e., connecting your corporate Identity Manager), registering your end users should be set as a periodical task so that you constantly synchronize their information (replicate any change regarding users in your Identity Manager, import a new user, or disable one).

 

This means that end users should be reflected when accessing the admin options for users in the Work portal:

 

ImportUsers_11

 

In order to import and synchronize end users, you have options such as:

1. Having a SOAP web services client on your side (at the customer's premises), which invokes Bizagi SOAP API in order to push information of users.

2. Having secure web services on your side (for the customer's Identity provider), so that these web services are invoked from a Bizagi process that pulls information of users.

Such Bizagi process you will need to define.

3. Having Bizagi connect to your Active Directory through an out-of-the-box feature which is set to run on a daily basis.

Recall that in order for Bizagi PaaS to access an on-premises system which does not offer a public endpoint, such as an Active Directory, you will need to use a VPN.

 

In scenarios where the above options are not feasible or optimal, you may choose to use a solution which isn't as technical: having a Bizagi process which expects an Excel file to be uploaded.

Such Bizagi process will need to be built by you; and such Excel file you will need to generate from the users information as managed by your Identity Provider.

This article illustrates how to build that Bizagi process and configure it for such purpose, through a series of guided steps.

 

 

What you need to do

The general outline to build the Bizagi process mentioned above, has three main steps:

 

1. Download, customize or create an Excel connector.

To read the incoming information of users from an Excel file, you will need an specialized Bizagi Connector.

You may create a connector by using our Connector Editor, or you may choose to download the one used in this example.

Notice that at this point, you should already know which format (i.e, columns definitions) you will employ for information of your users.

 

2. Implement the basics of the Bizagi process.

Create a process using Bizagi Studio in which, an Excel file is expected as input having the users to be added or synchronized to your project.

When modeling the process, you define basic aspects of it such as the data model employed and the user interfaces.

At this point you may also add other configuration aspects to the process such as making sure it has adequate access rights (i.e, restricted to non-admins).

 

3. Define processing rules.

Define business rules to be executed in order to interpret incoming information.

 

 

Example

In this example, all users are to be uploaded to a single organization (the default one), while using the following attributes:

Username: should be unique per user, when combined with the Domain information.

Email: should be unique per user.

Full Name

Domain: should be unique per user, when combined with the Username information.

Role: this information belongs to a multiple relationship with users. This means that one user may have multiple roles, and a same role is applicable to many users.

Enabled

 

Because a single user can have more than one role, it is best to have multiple rows in the Excel file where each row defines a role for a user (i.e., users basic information could be repeated within different rows).

The structure of the Excel file employed in this example will be:

 

ImportUsers_01

 

If you wish to reuse this same Excel file so that it works with the example instructed in this article, you may download it from: http://resources.bizagi.com/docs/UsersUploadSample.xlsx.

 

Procedure

Follow these steps.

 

1. Download, customize or create an Excel connector.

Download a ready-to-use connector fit for this example from http://resources.bizagi.com/docs/Read Users From Excel.bizc.

Alternatively, create a connector from scratch or edit the downloaded one by using our Connector Editor.

 

In the end, you should have a connector which complies to the Excel file structure, in a .bizc file:

 

ImportUsers_12

 

When moving on to Bizagi Studio, you should make sure you install and create an instance of this connector.

Notice that its configuration demands no specific settings:

 

ImportUsers_13

 

 

2. Implement the basics of the Bizagi process.

This step is about using Bizagi Studio to implement the process used to import, update or disable/enable users, through assisted steps.

 

2.1 Model the process

Model a process consisting of simply two activities: a manual activity in which the Excel file is uploaded, and an activity performed by the system in which the file is processed.

 

The following image illustrates this model:

 

ImportUsers_02

 

2.2 Define the data model

Next, define a data model to support this processs' use case, especially having a collection to temporarily store users, a file attachment attribute to capture the incoming Excel file, and other data for configuration so that you can target specific information within the Excel file.

 

The following image illustrates the suggested data model:

 

ImportUsers_03

 

2.3 Design the user interfaces

Recall that the only activity in this process which needs user intervention is the Load File activity.

The following form is suggested in order to support uploading the Excel file and previewing the records it has in it.

 

ImportUsers_04

 

For this form, create an action to execute the connector (to fetch all information coming from the uploaded Excel file).

The actions should be set as suggested in the following image:

 

ImportUsers_05

 

Inputs for the execution of the connector are the following:

 

ImportUsers_06

 

Outputs for the execution of the connector are the following:

 

ImportUsers_07

 

Notice no error handling configuration is needed.

 

2.4 Grant access rights for case creation to admin users.

At this point it is recommended to perform other configuration tweaks such as granting access to this process to admin users only.

 

ImportUsers_14

 

 

3. Define processing rules.

Now that the basics have been taken care of, move forward to create rules that process what has been temporarily stored in a collection to the final users entity.

 

note_pin

Recall that the Process File activity is where the uploaded file will be processed.

As mentioned before, the Excel file will have a multiple relation (Role), so among the processing, it will need to be considered that multiple user entries or existing users are not imported.

 

3.1 Define rules as activity actions

Create the following Expression at the On Exit event of the activity, and as shown below:

 

ImportUsers_08

 

To do this, first declare variables as suggested below:

 

ImportUsers_09

 

Type

Name

Initial Value

int

index

Index of the current element of the list of users imported

int

counter

Total number of users imported

string

inputXML

String to be executed using the Bizagi SOA Layer

string

inputXML

String with the XML of a user

List

CurrentUser

Collection to control that a user is not processed more than once.

List

CurrentFullname

Collection to control that a user with multiple roles does not have many full names

List

CurrentEmail

Collection to control that a user with multiple roles does not have many emails

List

CurrentDomain

Collection to control that a user with multiple roles does not have many domains

List

CurrentRole

Collection to control that a role is not assigned more than once to the same user.

List

CurrentEnabled

Collection to control that a status is not assigned more than once to the same user.

 

3.2 Add coding into the first expression box

For the Process file graphical expression box shown in the image above, add the following code:

 

// Get a collection with the useres uploaded. Use this method to return a collection even if only one record is sent

var colUsers = CHelper.GetValueAsCollection(<UploadUsers.ImportedUsers>);

// number of records in the file

counter = colUsers.size();

// This collections allows you to control that a user with mutiple roles does not have multiple domains, full names, etc.

CurrentUser = new ArrayList();

CurrentDomain = new ArrayList();

CurrentEmail = new ArrayList();

CurrentFullname = new ArrayList();

CurrentRole = new ArrayList();

CurrentEnabled = new ArrayList();

// The uploading of the users is done through the Bizagi SOA Layer.

inputXML = "<BizAgiWSParam>";

inputXML += "<Entities>";

 

3.3 Configure the For graphical element

For the Iterate over users graphical element, configure the following:

 

ImportUsers_10

 

3.4  Add coding into the second expression box

For the Initialize value fields for user graphical expression box shown in the image above, add the following code:

 

// gets the i-th user

var oUser = colUsers.get(index);

var sUsername = oUser.getXPath("Username");

// This variable is to search if a user already exists or not.

var sSearchDomain = "";

// If the user is already in the collection, this user will not be processed

if(!CurrentUser.Contains(sUsername.ToLower())) {

 CurrentUser.Add(sUsername.ToLower());

 inputXMLUser = "<WFUSER>";

 inputXMLUser += "<userName>" + sUsername + "</userName>";

 inputXMLUser += "<Organizations><idOrg key=\"1\"/></Organizations>";

 // The collections are clared in order to star over again

 CurrentFullname.Clear();

 CurrentEmail.Clear();

 CurrentRole.Clear();

 CurrentDomain.Clear();

 CurrentEnabled.Clear();

 var colUsernames = CHelper.GetValueAsCollection(<UploadUsers.ImportedUsers>);

 // New iteration to get the multiple values of the current user

 for(var i = 0; i < colUsernames.size(); i++) {

         var oUsername = colUsernames.get(i);

         if(oUsername.getXPath("Username").ToLower().Trim() == sUsername.ToLower()) {

                 var sFullName = oUsername.getXPath("Fullname");

                 var sEmail = oUsername.getXPath("EmailAddress");

                 var sDomain = oUsername.getXPath("UserDomain");

                 var sRole = oUsername.getXPath("UserRole");

                 var sEnabled = oUsername.getXPath("UserEnabled");

                 //To add single attributes, the attribute must not be empty and:

                 //if the collection is empty, the attribute has to be added

                 //if the collection contains the given attribute, this will not be processed

                 //if the collection does not contain the given attribute and it's not empty, an error must be thrown

                 //set domain

                 if(sDomain && !CurrentDomain.Contains(sDomain.ToLower().Trim())) {

                         CurrentDomain.Add(sDomain.ToLower().Trim());

                         // set the domain to search if the user exists

                         sSearchDomain = sDomain;

                         if(CurrentDomain.Count > 1)

                                 CHelper.ThrowValidationError("Username " + sUsername + " has different Domains");

                         sDomain = sDomain.Replace(" ", "");

                         inputXMLUser += "<domain>" + sDomain + "</domain>";

                 }

                 //set fullname

                 if(sFullName && !CurrentFullname.Contains(sFullName.ToLower().Trim())){

                         CurrentFullname.Add(sFullName.ToLower().Trim());

                         if(CurrentFullname.Count > 1)

                                 CHelper.ThrowValidationError("Username " + sUsername + " has different Fullnames");

                         inputXMLUser += "<fullName>" + sFullName.Trim() + "</fullName>";

                 }

                 //set email

                 if(sEmail && !CurrentEmail.Contains(sEmail.ToLower().Trim())){

                         CurrentEmail.Add(sEmail.ToLower().Trim());

                         if(CurrentEmail.Count > 1)

                                 CHelper.ThrowValidationError("Username " + sUsername + " has different Emails");

                         inputXMLUser += "<contactEmail>" + sEmail.Trim() + "</contactEmail>";

                 }

                 //set enabled

                 if(sEnabled && !CurrentEnabled.Contains(sEnabled.Trim())){

                         sEnabled = sEnabled.Trim();

                         if(sEnabled != "1" && sEnabled != "0")

                                 CHelper.ThrowValidationError("Username " + sUsername + " has an invalid status");

                         CurrentEnabled.Add(sEnabled);

                         if(CurrentEmail.Count > 1)

                                 CHelper.ThrowValidationError("Username " + sUsername + " has different status");

                         inputXMLUser += "<enabled>" + sEnabled + "</enabled>";

                 }

                 //To add multiple attributes, the attribute must not be empty and:

                 //if the collection is empty, the attribute has to be added

                 //if the collection contains the given attribute, this will not be processed

                 //set multiple roles

                 if(sRole && !CurrentRole.Contains(sRole.ToLower().Trim())){

                         CurrentRole.Add(sRole.ToLower().Trim());

                         sRole = sRole.Replace(" ", "");

                         var iRoleId = CHelper.getEntityAttrib("Role","idRole","LOWER(roleName) = '" + sRole.ToLower() +  "'");

                         if(!iRoleId)

                                 CHelper.ThrowValidationError("The Role " + sRole + " does not exist.");

                         inputXMLUser += "<Roles><idRole key='" + iRoleId + "'/></Roles>";

                 }

         }

 }

 //Validations

 //If any required user attributes is empty

 if(CurrentDomain.Count == 0)

         CHelper.ThrowValidationError("No domain was set for user " + sUsername);

 if(CurrentFullname.Count == 0)

         CHelper.ThrowValidationError("No full name was set for user " + sUsername);

 if(CurrentEmail.Count == 0)

         CHelper.ThrowValidationError("No email was set for user " + sUsername);

 if(CurrentRole.Count == 0)

         CHelper.ThrowValidationError("No roles was set for user " + sUsername);

 if(CurrentEnabled.Count == 0)

         CHelper.ThrowValidationError("No status was set for user " + sUsername);

 //Serch for the user with the domain to see if the user already exists

 var oUserCount = Me.getXPath("entity-list('WFUSER','userName = \"" + sUsername + "\" AND domain = \"" + sSearchDomain + "\"')");

 if(oUserCount.size() == 1) {

         inputXMLUser = inputXMLUser.Replace("<WFUSER>", "<WFUSER businessKey=\"userName = '" + sUsername + "' AND domain = '" + sSearchDomain + "'\">");

 }

 //Close the XML of the user

 inputXMLUser += "</WFUSER>";

 //Add the user XML to the XML to be processed

 inputXML += inputXMLUser;

 <UploadUsers.ProcessEnddate> = DateTime.Now;

}

 

3.5 Add coding into the third expression box

For the Insert values graphical expression box shown in the image above, add the following code:

 

//Close the XML string

inputXML += "</Entities>";

inputXML += "</BizAgiWSParam>";

//save records

var sResult = CEntityXmlHelper.fromXmlToEntity(inputXML);

 

Execution

Once you are done, ensure you run the process to test it thoroughly in your development environment.

All it takes is to create a new case, upload the sample Excel file, and click the Load users button to preview the information, and finally click Next.

 

ImportUsers_15

 

Finally and once you have verified it works adequately in development and testing environments, you may deploy this process to production environments.

 

What's next?

The procedure mentioned before is recommended for every project.

Nevertheless, you may customize the process and how it is executed, for instance:

 

If you need to consider additional user attributes, such as user properties or others, recall that you will need to customize and update the connector used for this purpose so that it fetches other information. Similarly you would need to consider the above attributes in your data model and within the business rules that process the uploaded information.

On top of this process, you may rely on Bizagi SOAP web services. This means that you could choose to avoid creating the cases manually and further automate this by having a SOAP web services client periodically invoke the Bizagi SOAP's createCasesAsString web method.