Skip to Content
0

Recursiv uProvision

Jun 21, 2017 at 04:40 PM

115

avatar image

Hello SAP-Community,

I have a problem in understanding the uProvision function in the SAP Identity Management 7.2.

What I want to build is the following: We have ABAP-Systems with many clients. Most of them are only copies of 3 main clients, I will call them Mother-Clients (MC). The copies of them I will call the Child-Clients (CC).

My aim is, only provision user in the MC and the IDM will by itself provision the user in the corresponding CC's. For that I introduce a repository constant to mark the CC at the MC. I will only hold the privileges for the MC in the IDM, cause the CC are copies and will have the same privileges.

Now, when a toSAP path for the MC is called, I wrote the following script to get all CC's and run the same task for them to.

function _runTaskForSubClients(){
	
	var auditID = uGetAuditID();
	var taskID = uGetTaskID();
	var repID = uGetRepositoryID();
	var mskey = uGetEntryID();

	uWarning("taskID : " + taskID + " auditID : " + auditID + " entryID : " + mskey); 

	var repSet = [];    // 
	var subSet = uGetConstant("rep.SUB_CLIENTS");

	// Ermittle alle Mandanten, Hauptmandant zu letzt
	repSet.push(uGetConstant("rep.JCO_CLIENT_CLIENT"));
	if (subSet) {
		repSet = subSet.split(',').concat(repSet);
	}
	uWarning("DEBUG : " + repset);
	        
	// Ermittle alle noch ausstehenden Mandanten
	var executedClients = uGetContextVar("EXECUTED_CLIENTS","").split(',');
	var clients = diff(repSet, executedClients);
    
	// Definition der Rekursion
	var client = clients.pop();    
    
	if (clients.length > 0) {
		// Rekursion
		executedClients.push(client);
		uSetContextVar("EXECUTED_CLIENTS", executedClients.toString());
		uWarning("Started for " + client);
		var execState = uProvision(mskey, taskID, auditID, repID, "", 0);
		if (execState.indexOf('!ERROR') !== -1) {
			uError(execState)
		} else {
			uWarning("Start Provisioning into " + client + " with AuditID " + execState);
		}
	} else {
		// Rekursionsanker
		//uSetContextVar("EXECUTED_CLIENTS", "");
	}
	return client;
}


function diff(mainset, subset) {
	var ret = [];
	for (var i in mainset) {
		var found = false;
		for (var j in subset) {
			if (mainset[i] === subset[j]) {
				found = true;
			} 
		}
		if (!found) {
			ret.push(mainset[i]);
		}
	}
	return ret;
}

The script is located at the jco.client.client Parameter. The script is working as expacted by itself and returns recursively all clients (MC + CC's).

The problems now are:

  1. uGetEntryID() and uGetAuditID() return -1
  2. uProvision is called, but the task will not start and so the recursion is not working. Is there a lock, to prevent this?

The second problem appears also, when I hardcode the EntryID and the AuditID, so this could not be the problem.

Do anybody have an idea, what is going on here? Could it be, that the same task could not be started twice on the same repository for the same Entry?

Greetings,

Thomas

10 |10000 characters needed characters left characters exceeded
* Please Login or Register to Answer, Follow or Comment.

3 Answers

Best Answer
Harri Jäske Jun 27, 2017 at 04:41 PM
0

As you state the mskey and auditid are not available in the jco.client.client parameter evaluation.

Also the context variables are not available there. Not even writing to context variables is possible from this place.
=>
It is not possible to have a different client in one ToSap pass depending on the mskey, auditid or context variables.
=>
The different clients need to be specified

either

a) at the repository or

b) in the ToSAP pass itself => have a per client copy of SetABAPRole⪻ofileForUser task

Version b, tested on 7.2 SP9:
Set "use context variables" on at root of hook task "4. Assign User Membership to ABAP".
Add new task "Phase 1 prepare context" under trigger uProvision for child clients, ToGeneric pass (script clientResolver below)
Phase 2 conditional task per each existing client number, 100, 200, 300,...
Phase 3 under each conditional task a different copy of the SetABAPRole⪻ofileForUser task with matching hardcoded client in parameter jco.client.client

"4. Assign User Membership to ABAP"
-> "Prepare for multiclient provisioning", ToGeneric calling function clientResolver
-> "AssignAllABAPPrivileges"
----> "AssignABAPPrivileges"
------> "Process named clients"
---------> Conditional task: "Client MASTERCLIENT" 

                          SELECT 1  FROM MXPV_Audit_Variables %NOLOCK% 

                          where AuditID=%AUDITID% and  VarName ='CURRENT_CLIENT' AND VarValue='MASTERCLIENT' 
--------------> True
-----------------> link to original "SetABAPRole⪻ofileForUser"

---------> Conditional task: "Client 100" 

                            SELECT 1  FROM MXPV_Audit_Variables %NOLOCK% 

                           where AuditID=%AUDITID% and  VarName ='CURRENT_CLIENT' AND VarValue='100' 
--------------> True
-----------------> copy of "SetABAPRole⪻ofileForUser" where hardcoded 100 to jco.client.client

---------> Conditional task: "Client 200" 

                             SELECT 1  FROM MXPV_Audit_Variables %NOLOCK% where AuditID=%AUDITID% 

                             and  VarName ='CURRENT_CLIENT' AND VarValue='200' 
--------------> True
----------------->  copy of "SetABAPRole⪻ofileForUser" where hardcoded 200 to jco.client.client

Here the script function for prepare:

// Main function: clientResolver

function clientResolver(Par){
    uErrMsg(1,"clientResolver - Par:"+Par);

    return _runTaskForSubClients();
}

function _runTaskForSubClients(){
    
    var auditID = uGetAuditID();

    var taskID = uGetTaskRoot();  // recursion to my parent

    var repID = uGetRepositoryID();
    var mskey = uGetEntryID();


    var todoClients = (""+uGetContextVar("TODO_CLIENTS","initial")).split(',');
    uErrMsg(1,"todoClients :"+todoClients );

    if (todoClients[0]=="initial"){
        var subSet = uGetConstant("rep.SUB_CLIENTS");
        uErrMsg(1,"DEBUG : sub clients:" + subSet);

        //sub clients into todo list - to be processed by successive uProvision calls
        todoClients = subSet.split(",");

        // Hauptmandant zu erst
            uSetContextVar("CURRENT_CLIENT", "MASTERCLIENT"); // used in conditional task
        uErrMsg(1,"Now doing for MASTERCLIENT");
    }else{
        // Ermittle alle noch ausstehenden Mandanten

        // Definier jetziger Client zu erledigen
        var client = todoClients.pop();
        uErrMsg(1,"Now doing for " + client);

            uSetContextVar("CURRENT_CLIENT", client);
    }


    // Rekurse oder nicht
    if (todoClients.length > 0) {

        // Rekursion
        uSetContextVar("TODO_CLIENTS", todoClients.join(","));

        if (  (""+mskey).indexOf("!ERROR")==-1 && (""+mskey)!="-1"){

            var execState = uProvision(mskey , taskID, auditID, repID, "", 0);
            if (execState.indexOf('!ERROR') !== -1) {
                uErrMsg(2,execState)
            } else {
                uErrMsg(1,"Start Provisioning into clients" + todoClients.join(",") + " with AuditID " + execState);
            }
        }else{
            uErrMsg(2,"mskey corrupt");
        }
    } else {
        // Rekursionsanker
        //uSetContextVar("TODO_CLIENTS", "");
    }

}

And do the same prepare and conditional tasking to all hook tasks: create, modify, etc

Best Regards,

Harri

Show 1 Share
10 |10000 characters needed characters left characters exceeded

Thanks Harri for the detailed solution. Your implementation looks great and is one solution I had in mind before. One idea to it : I use a switch task instead of the conditional tasks.

But, after implementing it, I see, that it is not operational for us, when we get a new child system. Cause I always had to copy and modify all hooks for the special sub client. This is not the biggest disadvantage. When there is a change in a hook Task, I must correct all copies. And there I see the future problem.

After some brainstorming, searching for a generic solution and looking at our process, I review the underlying requirement and we decide to do it the "traditional way" : Connect them all to the IDM. It looks after this cleaner and maintainable for us.

But very thanks to you both for your ideas.

Greetings

Thomas

0
Matt Pollicove
Jun 22, 2017 at 12:25 PM
0

Hello Thomas,

I'm not an expert programmer (I tend not to go outside of basic JavaScript) but I can think of a few issues and troubleshooting steps for your issue:

1. Try setting a trace on the user in IDM and review the results. Yes, I know the code is not triggering, but it could be interesting to see what did trigger and in what order.

2. My deeper suspicion is that recursive techniques just won't work. I'm not sure why, but I think your comment towards the end of your post is of interest regarding same task, same repository. Just wondering, what database are you using? Are you seeing any DB deadlock issues? Also maybe introducing a pause between uProvision calls would help.

Just a couple of thoughts....

Matt

Share
10 |10000 characters needed characters left characters exceeded
Deva Prakash B Jul 12, 2017 at 09:35 AM
0

Hi Thomas,

As per my understanding, whenever you are assigning privileges for MC system, then same privileges needs to be assigned to its respective Childsystems?

If it is correct, then i would suggest the below procedure.

1. Create a New repository constant for the Mother client and maintain the child systems repository names/id or else you can create a new attribute and maintain it at privilege level too

2. create a new task which checks based on the attribute or constant whether repository is mother client, then calculate the privileges which are have been requested for assignment newly and then check relevant privileges belonging to Child systems and assign them to the user.

Regards,

DP

Share
10 |10000 characters needed characters left characters exceeded