Custom Activity to make changes as different user
Hello everyone,
I am trying to execute an approval workflow as a result of a synchronization into FIM.
Here's a similar thread for context: http://social.technet.microsoft.com/Forums/en/ilm2/thread/ca6ad47b-6cc7-459d-a446-dc69dde3b162
Basically, when attribute A changes in the connected system, it is imported to the metaverse, and then exported to FIM. I have an MPR that detects this change has happened. It then copies the value of attribute A into attribute B. The catch
here is that the copying of A into B needs to be approved.
Since AuthN workflows are skipped by the built in sync account, I created a custom activity which copies the attribute using the credentials of a different user. Then I created an MPR which detects changes to attribute B, and executes the approval
workflow. However, this didn't work as expected, and the approval workflow was never called.
After some digging I found the thread referenced above, where NimaG has stated
"To trigger an approval workflow from a workflow activity, you will need to submit the request from a custom activity that issues the reuqest through a Web Service client instead of one of the FIM activities. The FIM PowerShell cmdlets can be used,
for example, to submit a request through the FIM Web Service"
So I tried executing the Import-FIMConfig powershell cmdlet from the custom WF activity, but kept running into an error:
{"The type initializer for 'Microsoft.ResourceManagement.WebServices.Client.ResourceManagementClient' threw an exception."}
and the inner exception:
{"This operation is not supported for a relative URI."}
Stack Trace:
at System.Uri.get_Fragment()
at System.UriBuilder.Init(Uri uri)
at Microsoft.ResourceManagement.WebServices.Client.ResourceManagementClient..cctor()
The strange thing is, I can run the same C# code in a console application and it runs perfectly. As soon as I put it into the custom activity, I see the above error. I have also tried impersonating another user prior to making the Powershell
calls, but still ended up with the above exception.
Also, I have checked the URI which I'm passing to the Import-FIMConfig cmdlet, and it is definitely NOT relative. I have set it to "http://servername:5725". As a matter of fact, even if I leave out the URI parameter I still get the same error
as above. (leaving out the URI is valid, it just defaults to http://localhost:5725)
I have tried building the powershell command in C#, and also tried just calling an external powershell script, both yielded the same results as above.
Here's the code which calls the powershell command from the custom activity:
// Set up the credentials to use for the powershell command
string user = @"domain\testuser";
string password = "mypassword";
System.Security.SecureString pass = new System.Security.SecureString();
foreach (char c in password.ToCharArray())
pass.AppendChar(c);
PSCredential credential = new PSCredential(user, pass);
// Build the import object
ImportChange change = new ImportChange();
change.Operation = ImportOperation.Replace;
change.AttributeName = targetAttribute;
change.AttributeValue = targetValue;
change.FullyResolved = true;
change.Locale = "Invariant";
ImportObject import = new ImportObject();
import.ObjectType = objectType;
import.TargetObjectIdentifier = targetResourceId.ToString();
import.SourceObjectIdentifier = targetResourceId.ToString();
import.State = ImportState.Put;
import.Changes = new ImportChange[] { change };
// Execute the powershell command
PowerShell ps = PowerShell.Create();
PSSnapInException snapInException = null;
ps.Runspace.RunspaceConfiguration.AddPSSnapIn("FIMAutomation", out snapInException);
Hashtable parameters = new System.Collections.Hashtable();
parameters.Add("Uri", uri);
parameters.Add("ImportObject", import);
parameters.Add("Credential", credential);
ps.AddCommand("Import-FIMConfig").AddParameters(parameters);
//ps.AddCommand(@"C:\temp\updateUser.ps1");
Collection<string> psOutput = ps.Invoke<string>(); // This is where the exception is thrown.
I've also tried just executing a powershell script which contains the Import-FIMConfig, but had the same effect. Here's the one-liner source for that:
new RunspaceInvoke().Invoke(@"C:\temp\updateUser.ps1");
Since these methods work perfectly within a regular console application, but not within the workflow activity, there must be some environment configuration which is throwing things off. I am at a loss as to where this difference is.
Any ideas?
Thanks in advance,
Mark
December 15th, 2010 12:43pm
Hi Mark!
Simply put, correct me if I'm wrong... Your main goal is to interfere an attribute change from Metaverse during export to FIM using an approval activity and since you can't do that in the authorization stage you are triggering another request to copy this
attribute value into another attribute using a different user (ActorID) and for this you're trying to use Powershell within a custom actvity to do this in some way... Sorry I'm not very much into Powershell and I wish to enlight you with another way to solve
the problem...
Approvals can be executed from the Action stage but it requires a little tweak that I'm not sure its supported but if you create a new Activity Information Configuration resource and use the same class names and assembly used for the standard approval
activity, give it a new name like for example "Action Approval" and mark it as an Action activity you have a solution that allows you to interfere your attribute copy operation with an approval in the action stage instead of having to do such an
advanced workaround.
//HenrikHenrik Nilsson, ILM/FIM MVP Blog: http://www.idmcrisis.com Company: Cortego (http://www.cortego.se)
Free Windows Admin Tool Kit Click here and download it now
December 15th, 2010 3:00pm
Henrik, i am not aware of changing the basic model of "AuthN -> AuthZ -> Commit -> Action". So commit happens before Action phase.
December 16th, 2010 3:48am
What's the value of the uri object?My Book - Active Directory, 4th Edition
My Blog - www.briandesmond.com
Free Windows Admin Tool Kit Click here and download it now
December 16th, 2010 10:45am
Brian, The value of the uri object is http://servername:5725. I've also tried using http://(ip address):5725 and http://localhost:5725
Henrik, thanks for your response. I tested using an Action Approval, but found some weird things happened.
As Anthony mentioned, the changes would be committed prior to the action workflow being executed, so the approval wasn't very useful at that stage.
So I changed things around and put the action approval workflow activity in the same workflow as the copy attribute activity. At this point, here's what I had:
MPR: On changes to attribute A, execute Workflow A (which is an action workflow)
Workflow A:
Activity 1: Action Approval
Activity 2: Copy Attribute A to Attribute B (using Function Evaluator)
This worked somewhat, but I found that any MPRs which were supposed to be triggered off of the change to Attribute B would not be fired. So I changed Activity 2 to use a custom activity which copies attribute A to
attribute B as a different user.
Workflow A:
Activity 1: Action Approval
Activity 2: Copy Attribute A to Attribute B (using Custom Activity, as a different user)
This worked a bit better, all the MPRs were now triggered as expected on the change to attribute B.
However, upon further testing, I found that this would only work if the only attribute being changed was attribute A. If any other attribute was being changed at the same time, the approval activity would not fire, and neither would the subsequent
activities.
December 16th, 2010 12:20pm
Mark,
I don't know of any way you're able to kick off an authz wf on sync (Built-In sync account) so you'll have to depend on action wf for doing this unless someone could tell how to do it without affecting performance in a negative way. I'm well aware attribute
A is committed but I understand that it is the copying of attribute A to attribute B that is the crucial part here!
However, upon further testing, I found that this would only work if the only attribute being changed was attribute A. If any other attribute was being changed at the same time, the approval activity would not fire, and neither would the subsequent
activities.
Isn't this simply because your MPR is configured that way?..
MPR: On changes to attribute A, execute Workflow A (which is an action workflow)
About your custom activity that you use to do the copy values as a different user, I think you could simply edit the ActorID property in wf XOML in order for your activities to inherit it (under Extended attributes in you WF)...
<ns0:SequentialWorkflow RequestId="00000000-0000-0000-0000-000000000000" x:Name="SequentialWorkflow" TargetId="00000000-0000-0000-0000-000000000000" ActorId="00000000-0000-0000-0000-000000000000
" WorkflowDefinitionId="00000000-0000-0000-0000-000000000000"
...At least it's worth a try but it won't allow you to kick off authz wf's on sync...
//Henrik
Henrik Nilsson, ILM/FIM MVP Blog: http://www.idmcrisis.com Company: Cortego (http://www.cortego.se)
Free Windows Admin Tool Kit Click here and download it now
December 17th, 2010 1:43am
Mark,
I don't know of any way you're able to kick off an authz wf on sync (Built-In sync account) so you'll have to depend on action wf for doing this unless someone could tell how to do it without affecting performance in a negative way. I'm well aware attribute
A is committed but I understand that it is the copying of attribute A to attribute B that is the crucial part here!
However, upon further testing, I found that this would only work if the only attribute being changed was attribute A. If any other attribute was being changed at the same time, the approval activity would not fire, and neither would the subsequent
activities.
Isn't this simply because your MPR is configured that way?..
MPR: On changes to attribute A, execute Workflow A (which is an action workflow)
About your custom activity that you use to do the copy values as a different user, I think you could simply edit the ActorID property in wf XOML in order for your activities to inherit it (under Extended attributes in you WF)...
<ns0:SequentialWorkflow RequestId="00000000-0000-0000-0000-000000000000" x:Name="SequentialWorkflow" TargetId="00000000-0000-0000-0000-000000000000" ActorId="00000000-0000-0000-0000-000000000000
" WorkflowDefinitionId="00000000-0000-0000-0000-000000000000"
...At least it's worth a try but it won't allow you to kick off authz wf's on sync...
//Henrik
Henrik Nilsson, ILM/FIM MVP Blog: http://www.idmcrisis.com Company: Cortego (http://www.cortego.se)
December 17th, 2010 1:43am
Henrik,
I realize that the Built-in sync account skips the AuthZ workflows, which is really why I've been trying to find a way to have another user be the Actor for the copying of attribute A to B. I had initially tried just setting the ActorId on the UpdateResourceActivity
in the custom wf. An MPR triggered by changes to Attribute A (by the built in sync account) would call the custom wf to copy the value of attribute A to attribute B (as a regular user). A second MPR would be triggered by changes to Attribute B
by the regular user. This second MPR contained the approval workflow. Unfortunately, despite the copy request coming from a regular user, the approval workflow still would not fire. This is why I then tried (unsuccessfully) to use powershell
and Import-FIMConfig to make the web service call.
>Isn't this simply because your MPR is configured that way?..
Actually, no. When trying to use the Action Approval, the MPR was configured like this:
MPR: On changes to attribute A, execute Workflow A (action approval, then copy attribute)
If I changed the corresponding attribute A (and only that attribute) in the connected system, imported to the MV, and then exported to FIM, the workflow would be executed as expected.
However, if I changed attribute A and any other attribute at the same time in the connected system, the workflow would not be executed on the export to FIM.
>About your custom activity that you use to do the copy values as a different user, I think you could simply edit the ActorID property in wf XOML in order for your activities to inherit it (under Extended attributes in you WF)...
I tried changing the copy attribute workflow and using a function evaluator instead of the custom activity to do the copy, and then edited the XOML to put change the ActorId on the SequentialWorkflow. Strangely, when the workflow ran, the ActorId
was ignored and the copy was still performed by the FIM Service Account.
Thanks,
Mark
Free Windows Admin Tool Kit Click here and download it now
December 17th, 2010 8:53am
Henrik,
I realize that the Built-in sync account skips the AuthZ workflows, which is really why I've been trying to find a way to have another user be the Actor for the copying of attribute A to B. I had initially tried just setting the ActorId on the UpdateResourceActivity
in the custom wf. An MPR triggered by changes to Attribute A (by the built in sync account) would call the custom wf to copy the value of attribute A to attribute B (as a regular user). A second MPR would be triggered by changes to Attribute B
by the regular user. This second MPR contained the approval workflow. Unfortunately, despite the copy request coming from a regular user, the approval workflow still would not fire. This is why I then tried (unsuccessfully) to use powershell
and Import-FIMConfig to make the web service call.
>Isn't this simply because your MPR is configured that way?..
Actually, no. When trying to use the Action Approval, the MPR was configured like this:
MPR: On changes to attribute A, execute Workflow A (action approval, then copy attribute)
If I changed the corresponding attribute A (and only that attribute) in the connected system, imported to the MV, and then exported to FIM, the workflow would be executed as expected.
However, if I changed attribute A and any other attribute at the same time in the connected system, the workflow would not be executed on the export to FIM.
>About your custom activity that you use to do the copy values as a different user, I think you could simply edit the ActorID property in wf XOML in order for your activities to inherit it (under Extended attributes in you WF)...
I tried changing the copy attribute workflow and using a function evaluator instead of the custom activity to do the copy, and then edited the XOML to put change the ActorId on the SequentialWorkflow. Strangely, when the workflow ran, the ActorId
was ignored and the copy was still performed by the FIM Service Account.
Thanks,
Mark
December 17th, 2010 8:53am
I remember now that the Function Evaluator is hard coded to use the sync account, sad but true...
It sounds strange the MPR isn't triggering workflows when more attributes than the A attribute is changed in the same request, could this be because you have a before or after Set that makes this MPR not being evaluated?
//HenrikHenrik Nilsson, ILM/FIM MVP Blog: http://www.idmcrisis.com Company: Cortego (http://www.cortego.se)
Free Windows Admin Tool Kit Click here and download it now
December 17th, 2010 9:29am
I agree, I found it quite strange as well.
Both the before and after sets are "All People", so that wouldn't be causing the MPR to not be evaluated.
December 17th, 2010 9:31am
I agree, I found it quite strange as well.
Both the before and after sets are "All People", so that wouldn't be causing the MPR to not be evaluated.
Free Windows Admin Tool Kit Click here and download it now
December 17th, 2010 9:31am
This is going to be a late reply. To use the FIM automation cmdlets inside a WF, we need to modify the service exe configuration file.
You want to change the following:
<resourceManagementClient resourceManagementServiceBaseAddress="localhost" />
TO
<resourceManagementClient resourceManagementServiceBaseAddress="http://localhost:5725" />
May 9th, 2011 9:08pm