cancel
Showing results for 
Search instead for 
Did you mean: 

Position based Role Model

Murali_Shanmu
Active Contributor
0 Kudos

Hi,

I am looking for some clarity on how to implement a position based Role model via IdM.

Assume, that we have ERP(HCM) and BW system and the roles are managed based on Position. CUA is deployed on ERP. There is a proper Organization Model with Positions maintained in ERP. Say, for a position 10234 "Accounts Payable" there will be composite role which has single roles belonging to ERP and BW system. When a user is assigned to this position, the person would automatically get all these single roles in the respective systems.

Now, IdM comes in picture. Roles need to be provisioning centrally via IdM.

A New user comes onboard and is assigned to this position in ERP system. With an ERP Delta Load and an with an HCM Integration scenario, I can get the details of the new user and the assigned position. How would IdM know to assign this user all these single roles which were previously mapped to the Position?

In order to achieve this Postion based Role Model, should I setup Rule based provisioning. If yes, how ?

Cheers,

Murali

Accepted Solutions (1)

Accepted Solutions (1)

Former Member
0 Kudos

Hi Murali

I built something similar a little while ago.  I don't have it in front of me but will try and get it right

I got a report of the current positions, composite roles and single roles from ERP.

I created roles for each position (ROLE:POSITION:number) to make the next bit easier.

I assigned the composite role and single role privileges to the Position role.

I had a custom attribute:  HIGHER_DUTIES_POSITION

I had a task which was triggered on an add/change/remove on MX_POSITION_ID(?) and the custom attribute

The Task triggered a script which assigned a role based on the position the user was in and removed those they weren't in (unless it was their substantive position and the script was doing higher duties assignments)

I had another script on the staging area which determined whether the position was a higher duties or substantive position and wrote the data to the appropriate attribute.

So the outcome was:

  • User is assigned to a position in HCM (either higher or substantive)
  • Data is updated in the staging area.
  • The MX_PERSON object is updated with the position details (either higher or substantive)
  • The script assigned the position role to the user
  • Normal provisioning takes over.

I set up a job which read the position info from HCM (rather then using extracts and imports etc) and didn't use the person objects to define them.  You want all positions, not just those currently assigned so you need to bypass users and go directly to the position data.

Peter

Murali_Shanmu
Active Contributor
0 Kudos

Brilliant.

You should probably blog it.

I can see that you are using Higher Duty Allowance (IT 509). I have seen this mostly used in Public sector implementation. Good to know how to use this too.

(1)  Could you please share both the scripts. I am keen to see how you read & write attributes. I could learn and use the same approach in some other scenarios when dealing with other attributes/objects.

(2) Did you create any new attributes in the Staging Area. I was going through an article by Christopher Leonard, where he explains how to get additional HCM fields into IdM by creation a custom attribute both in Identity Store and Staging Area. I believe this approach could be used too. Please correct me.

(3) I am not clear with the "job which read the position info from HCM". Is this to setup master data of all the Positions in IdM ? How do you read all the position data from HCM - Are you reading the SAP table from the pass ? Are you storing this data in the Identity Store ?

Thanks mate.

Cheers,

Murali.

Former Member
0 Kudos

I'll try and put something together.

1.  I'll add the scripts at the bottom of this post.

2.  I did.  There were quite a few new attributes actually (mostly around determining higher duties positions).  Specifically, I added MASSN and MASSG to get the action type and code.

3.  Yes - I read the position data directly from the table with a standard From pass (just changed the table data to get it out).  I think the table is: HRP1000.  I store the positions as roles (as mentioned).

The scripts below are provided warranty free.

/****************

* Script:               GblAssignPositionRole

* By:                    Peter Wass

* Purpose:          Assign the correct position role to a user object based on their current position.

* PAR:                    Position Number!!Higher Duties Position Number

* Returns:       Add/remove role string. e.g.: {R}existingRole|{A}newRole

* Changes:

*****************/

function GblAssignPositionRole(Par)

{

          var lclDebug = false;

          if("%$glb.DEBUG_SCRIPT%" == "True" || "%$glb.DEBUG_SCRIPT%".indexOf("GblAssignPositionRole") > -1)

          {

                    lclDebug = true;

          }

 

          var positions = Par.split("!!");

          var substantivePosition = "";

          var hdPosition = "";

 

          substantivePosition = positions[0];

          if(positions.length > 1) {hdPosition = positions[1];}

 

          var proposedSubstantivePositionRole = "#NONE#";

          var proposedHDPositionRole = "#NONE#";

 

          var assignRole = "";

          var removeOnly = false;

          if(lclDebug){uWarning("GblAssignPositionRole. Input:" + Par);}

          if(substantivePosition.length < 1 && hdPosition.length < 1)

          {

                    removeOnly = true;

                    if(lclDebug){uWarning("GblAssignPositionRole. No positions - removing the existing role only.");}

          }

 

          if(substantivePosition.length > 0)

          {

                    if(substantivePosition == "99999999")

                    {

                              removeOnly = true;

                              if(lclDebug){uWarning("GblAssignPositionRole.Substantive Position 99999999 - user ceased employment. Removing all roles.");}

                    }

                    else

                    {

                              proposedSubstantivePositionRole = "ROLE:POSITION:" + substantivePosition;

                    }

          }

          if(hdPosition.length > 0)

          {

                    if(hdPosition == "99999999")

                    {

                              if(lclDebug){uWarning("GblAssignPositionRole.Higher Duties Position 99999999 - user ceased employment. Removing HD role.");}

                    }

                    else

                    {

                              proposedHDPositionRole = "ROLE:POSITION:" + hdPosition;

                    }

          }

 

          if(lclDebug){uWarning("GblAssignPositionRole. Input:" + Par + ", Proposed Substantive Position Role: " + proposedSubstantivePositionRole + ", Proposed HD Position Role: " + proposedHDPositionRole);}

 

          //Get the current position Role so that it can be removed if necessary.

          if(lclDebug){uWarning("GblAssignPositionRole. Calling GblGetCurrentPositionRole");}

          var curPositionRoles = GblGetCurrentPositionRole();

          if(lclDebug){uWarning("GblAssignPositionRole. Current Position Roles:" + curPositionRoles);}

 

          if((curPositionRoles.indexOf(proposedSubstantivePositionRole) > -1) && (curPositionRoles.indexOf(proposedHDPositionRole) > -1))

          {

                    //Positions already assigned.  No change required

                    uWarning("User already has position assigned.");

                    if(lclDebug){uWarning("GblAssignPositionRole. Position already assigned. Exiting.");}

                    uSkip(1);

          }

          else

          {

                    if(curPositionRoles.length > 0)

                    {

                              var arrCurrentPositions = curPositionRoles.split("!!");

                              for (i=0; i < arrCurrentPositions.length; i++)

                              {

                                        if(arrCurrentPositions[i] != proposedSubstantivePositionRole && arrCurrentPositions[i] != proposedHDPositionRole)

                                        {

                                                  if(assignRole != "") { assignRole = assignRole + "|"; }

                                                  assignRole = assignRole + "{R}<" + arrCurrentPositions[i] + ">";

                                                  if(lclDebug){uWarning("GblAssignPositionRole. Role " + arrCurrentPositions[i] + " scheduled for removal");}

                                        }

                              }

                    }

                    if (removeOnly == false)

                    {

                              if(proposedSubstantivePositionRole != "#NONE#" && curPositionRoles.indexOf(proposedSubstantivePositionRole) == -1)

                              {

                                        if(assignRole != "") { assignRole = assignRole + "|"; }

                                        assignRole = assignRole + "{A}<" + proposedSubstantivePositionRole + ">";

                                        if(lclDebug){uWarning("GblAssignPositionRole. Role " + proposedSubstantivePositionRole + " added.");}

                              }

                              if(proposedHDPositionRole != "#NONE#" && curPositionRoles.indexOf(proposedHDPositionRole) == -1)

                              {

                                        if(assignRole != "") { assignRole = assignRole + "|"; }

                                        assignRole = assignRole + "{A}<" + proposedHDPositionRole + ">";

                                        if(lclDebug){uWarning("GblAssignPositionRole. Role " + proposedHDPositionRole + " added.");}

                              }

                    }

     }

 

          if(lclDebug){uWarning("GblAssignPositionRole. Outcome: " + assignRole);}

          return assignRole;

}

/****************

* Script:          GblGetCurrentPositionRole

* By:                    Peter Wass

* Purpose:          Gets the name of the current position role for the user

* PAR:                    Null

* Returns:  A !! delimited list of role names for the current user position.

* Changes:

*****************/

function GblGetCurrentPositionRole(Par)

{

          var lclDebug = false;

          if("%$glb.DEBUG_SCRIPT%" == "True" || "%$glb.DEBUG_SCRIPT%".indexOf("GblGetCurrentPositionRole") > -1 )

          {

                    lclDebug = true;

          }

          var roleString = "";

          // Returns all current roles separated by '!!'

          var curUserMsKey = uGetEntryID();

 

          if(lclDebug){uWarning("GblGetCurrentPositionRole. Getting current roles for user MSKEY: " + curUserMsKey );}

          var curRoles = uIS_nGetValues(curUserMsKey,"MXREF_MX_ROLE");

          if(lclDebug){uWarning("GblGetCurrentPositionRole. Current Role mskeys: " + curRoles );}

          if(curRoles.length > 0)

          {

                    var posRegExPattern = "ROLE:POSITION:\d*";

                    var posRegEx = new RegExp(posRegExPattern);

 

                    var roleMskeys = curRoles.split("!!");

                    for(i=0; i<roleMskeys.length; i++)

                    {

                              var roleName = uIS_nGetValues(roleMskeys[i], "MSKEYVALUE");

                              var posRoles = posRegEx.exec(roleName);

                              if(posRoles == null)

                              {

                                        if(lclDebug){uWarning("GblGetCurrentPositionRole. No match with " + roleName );}

                              }

                              else

                              {

                                        if(roleString != "") { roleString = roleString + "!!"; }

                                        roleString = roleString + roleName;

                                        if(lclDebug){uWarning("GblGetCurrentPositionRole. Position Role Found: " + roleName );}

                              }

                    }

          }

          else

          {

                    if(lclDebug){uWarning("GblGetCurrentPositionRole. No roles assigned." );}

          }

          if(lclDebug){uWarning("GblGetCurrentPositionRole. Returning: " + roleString );}

          return roleString;

}

This script sets the position when transferring it from the staging area to the primary ID store

MX_POSITION_ID   $FUNCTION.GblSetPositionNumber(SUBSTANTIVE~%P0001-PLANS%~%MASSN%~%MASSG%)$$

HIGHER_DUSTIES   $FUNCTION.GblSetPositionNumber(HIGHER~%P0001-PLANS%~%MASSN%~%MASSG%)$$

NOTE: There may be errors in the above calls - I don't have them in front of me

/****************

* Script:          GblSetPositionNumber

* By:                    Peter Wass

* Purpose:          Sets the position number for Substantive or Higher Duties based on

* PAR:                    POSTYPE (SUBSTANTIVE|HIGHER)~P0001-PLANS~MASSN (Z3)~MASSG

*                              NOTE: P0001-PLANS is multivalue, as is MASSG.  Format: [yyyymmdd-yyyymmdd]value|[yyyymmdd-yyyymmdd]value

* Returns:  Position Number

* Changes:

*****************/

function GblSetPositionNumber(Par)

{

          var lclDebug = false;

          if("%$glb.DEBUG_SCRIPT%" == "True" || "%$glb.DEBUG_SCRIPT%".indexOf("GblSetPositionNumber") > -1 )

          {

                    lclDebug = true;

          }

 

          var ParArray = Par.split("~");

          var posType = ParArray[0];

          var posNumber = ParArray[1];

          var actionType = ParArray[2];

          var actionCode = ParArray[3];

          var currActionCode = 0;

          var currPosNumber = "";

 

          var returnValue = "";

          if(lclDebug){uWarning("GblSetPositionNumber. Getting position with parameter: " + Par);}

 

          //Get Current Position Data

          var primaryPositionNumber;

          var HRMskeyvalue = uIS_GetValue(uGetEntryID(), "%$glb.HR_STAGING_AREA_IDS_ID%", "MSKEYVALUE");

if(lclDebug){uWarning("GblSetPositionNumber. Retrieved " + HRMskeyvalue);}

          var mskVal = HRMskeyvalue.split(" ");

          var currPersonnelNumber = GblApplyUserPrefixByStream(GblCorrectUsernames(mskVal[1]));

 

          if(lclDebug){uWarning("GblSetPositionNumber. User has MSKEYVALUE " + currPersonnelNumber + " in primary ID Store");}

 

          var primaryIDSMskey = uIS_sGet(1, "MSKEYVALUE", currPersonnelNumber);

          if(primaryIDSMskey.indexOf("ERROR") > -1)

          {

                    if(lclDebug){uWarning("GblSetPositionNumber. User with PERNR " + currPersonnelNumber + " could not be found. Result:" + primaryIDSMskey);}

                    primaryPositionNumber = "";

          }

          else

          {

                    primaryPositionNumber = uIS_GetValue(primaryIDSMskey, "$glb.SAP_MASTER_IDS_ID%", "MX_FS_POSITION_ID");

                    if(primaryPositionNumber.indexOf("ERROR") > -1)

                    {

                              if(lclDebug){uWarning("GblSetPositionNumber. Could not retrieve primary position number for user. Result:" + primaryIDSMskey);}

                              primaryPositionNumber = "";

                    }

          }

          if(lclDebug){uWarning("GblSetPositionNumber. Existing position number in primary ID Store: " + primaryPositionNumber);}

 

          //Get Current Date

          var today = new Date();

          var month;

          var day;

          if((today.getMonth() + 1) < 10) { month = "0" + today.getMonth()+1; } else { month = today.getMonth();}

          if(today.getDate() < 10) { day = "0" + today.getDate(); } else { day = today.getDate();}

          var currDate = today.getFullYear() + "" + month + "" + day;

          if(lclDebug){uWarning("GblSetPositionNumber. Current date for comparisson: " + currDate);}

 

          // Get action code for current date

          var actionArray = actionCode.split("|");

          for(i=0; i < actionArray.length; i++)

          {

                    var endSquare = actionArray[i].indexOf("]");

                    var separator = actionArray[i].indexOf("-");

                    var startDate = actionArray[i].substring(1,separator);

                    var endDate = actionArray[i].substring(separator + 1, endSquare);

                    if(startDate <= currDate && endDate >= currDate)

                    {

                              //Current date falls within date range.

                              currActionCode = actionArray[i].substring(endSquare + 1);

                              if(lclDebug){uWarning("GblSetPositionNumber. Found current action code: " + currActionCode + ". Start Date:" + startDate + ", End Date:" + endDate);}

                              break;

                    }

          }

          //Get Position Number for current Date.

          var posArray = posNumber.split("|");

          for(i=0; i < posArray.length; i++)

          {

                    var endSquare = posArray[i].indexOf("]");

                    var separator = posArray[i].indexOf("-");

                    var startDate = posArray[i].substring(1,separator);

                    var endDate = posArray[i].substring(separator + 1, endSquare);

                    if(startDate <= currDate && endDate >= currDate)

                    {

                              //Current date falls within date range.

                              currPosNumber = posArray[i].substring(endSquare + 1);

                              if(lclDebug){uWarning("GblSetPositionNumber. Found current position number: " + currPosNumber + ". Start Date:" + startDate + ", End Date:" + endDate);}

                              break;

                    }

          }

 

          if(currPosNumber == "")

          {

                    if(lclDebug){uWarning("GblSetPositionNumber. No current position number found. Returning empty value.");}

                    returnValue = currPosNumber;

          }

          else if(posType == "HIGHER")

          {

                    if(lclDebug){uWarning("GblSetPositionNumber. Evaluating for Higher Duties Position.");}

                    if(actionType.indexOf('Z3') > -1 && currActionCode == '40')

                    {

                              //User is on higher duties.  The position code is for higher duties position.

                              if(lclDebug){uWarning("GblSetPositionNumber. Action Code: 40 - Higher Duties currently active. Returning position number: " + currPosNumber);}

                              returnValue = currPosNumber;

                    }

 

                    if(actionType.indexOf('Z3') > -1 && currActionCode == '20')

                    {

                              //User is not on higher duties.  The position code is for higher duties position.

                              if(lclDebug){uWarning("GblSetPositionNumber. Action Code: 20 - Higher Duties ended. Returning no position number.");}

                              returnValue = "";

                    }

          }

          else

          {

                    if(lclDebug){uWarning("GblSetPositionNumber. Evaluating for Substantive Position.");}

                    if(currActionCode == '40')

                    {

                              if(lclDebug){uWarning("GblSetPositionNumber. Action Code: 40 - Higher Duties currently active. Returning existing position number: " + primaryPositionNumber);}

                              //Position Number is for Higher Duties.  Setting SUBSTANTIVE number to existing.

                              returnValue = primaryPositionNumber;

                    }

                    else

                    {

                              if(lclDebug){uWarning("GblSetPositionNumber. Action Code: " + currActionCode + " - Higher Duties not currently active. Returning position number: " + currPosNumber);}

                              returnValue = currPosNumber;

                    }

          }

          if(lclDebug){uWarning("GblSetPositionNumber. Returning value: '" + returnValue + "' for " + posType + " position number.");}

 

          return returnValue;

}

Murali_Shanmu
Active Contributor
0 Kudos

Thanks Peter. Well explained.

Cheers,

Murali

Matt_Marples
Participant
0 Kudos

Hi Murali,


Did you manage to successfully implement position-based provisioning, and if so how did you overcome assigning Structural Profiles. Currently, we have Structural Auths defined with the PFCG role and we maintain a separate Z object within HRP1001 for access to a specific Org Unit.

Answers (1)

Answers (1)

Former Member
0 Kudos

Hi,

you'll need a  mapping table that links the position to the roles belonging to that position. You may define a custom entity type for that.

Given that mapping table it is then easy to assign the users the roles belonging to their position while you're copying the users from the HCM staging area to the main Identity Store...

Regards,

Sietze

Murali_Shanmu
Active Contributor
0 Kudos

Sietze,

(1) Could you please elaborate more on how you would create a mapping table. I am not clear as to how I can do this even with creating a new Entry Type.

(2) I believe we would need to write a custom script which will assign roles to user based on position (reading the above mapping table) from the HCM Staging Area.

Thanks

Murali

Former Member
0 Kudos

Murali;

you just need a table with two columns: Position and Role. The script (from the second step) reads all roles from the table given the position and assigns them to the user (using the MX_PERSON attribute MXREF_MX_ROLE or some such).

You can also hardcoade the table using if statements but this becomes rather unwieldy once the number of positions and roles grow.

Thanks,

Sietze