Automating Group Management: A Dynamic Group Primer

Well a "short break" turned into something a bit longer than I anticipated.  My laptop is back in gear, and I again have the freedom of spending my writing time somewhere other than my office.  That little surprise I was working on for you is still in the works.  Unfortunately, it seems to take lining up a few more ducks that I first thought.  In the mean time I thought I would jump a bit ahead in my peeling of the Microsoft Identity Lifecycle Manager "2" onion and respond to a question I received recently from one of you out there.  This also allows me to celebrate my first post in the "Identity Lifecycle Manager Solution" category!  Essentially, the question is this (some editing done to maintain confidentiality of content):

After the sync with an external connected system completes, such as an HR system, is there an easy process to create/maintain groups based on a specific attribute?  For example, if one of the attributes of the user is CostCenter, how can we automatically create/populate/maintain a group for each value of CostCenter found in the system?

The benefit, of course, is that if a user has the value of their CostCenter change they automatically have their group membership updated and that update is reflected in AD on the next export/sync of the appropriate Management Agents.  Great for role based security!

The great news is that this functionality is extremely easy in the eventual released version of Microsoft Identity Lifecycle Manager "2".  The not so good news is that this dynamic creation of groups is not supported out of box in the current Beta release of Microsoft Identity Lifecycle Manager "2"; however, it is still possible with a little extra coding effort.

Since this is going to be a discussion of a possible solution on top of Microsoft Identity Lifecycle Manager "2", let me satisfy the legal folks here by starting with the following:

Disclaimer:   This posting and any code contained within are provided "AS IS" with no warranties, and confer no rights. Use of included code samples are subject to the terms specified at https://www.microsoft.com/info/cpyright.htm.

To start this discussion let me first put aside the complex part of the solution, dynamic creation of groups based on attribute values, and start talking about dynamic group membership.  As I mentioned in an earlier post (A Discussion of Computed, Explicit, and Temporal Sets in Microsoft Identity Lifecycle Manager "2") Microsoft Identity Lifecycle Manager "2" supports a variety of set membership concepts.  Although there are differences between Group and Set objects within Microsoft Identity Lifecycle Manager "2", for discussions about membership they can be viewed as synonymous.  This means that Microsoft Identity Lifecycle Manager "2" also supports the same type of memberships for groups as it does for sets.  For this particular post the type of group membership of interest in computed (also referred to as dynamic).

A dynamic group derives its membership from its Filter attribute which is essentially an XPath expression.  As an example, lets say I wanted to create a dynamic group for all users who are in the domain "Domain1".  Looking at the schema for the Person object type in Microsoft Identity Lifecycle Manager "2" there is a string attribute Domain that contains this information.  I could then create a group whose XPath filter was "/Person[Domain='Domain1']".  This group would then populate its membership with every resource in the Microsoft Identity Lifecycle Manager "2" system of type Person that has its Domain attribute set to the value "Domain1".  Further, any new resources of type Person created with Domain set to "Domain1" will be automatically added to this group as part of its creation.  Still further, any existing resource of type Person that is updated to set its Domain attribute to "Domain1" will be automatically added to this group as part of that update.  Finally, any resource of type Person that currently has its Domain attribute set to "Domain1" that is updated to change its Domain attribute to something else will be (as you have probably guessed) automatically removed from this group as part of that update.

Lets look at a bit more complex of a scenario.  Lets say that I wanted to create a dynamic group for all users who report directly to me (have me as there direct manager).  Looking at the schema for the Person object type in Microsoft Identity Lifecycle Manager "2" there is a reference attribute Manager that contains this information.  I could then create a group whose XPath filter was "/Person[Manager='{SomeGuid}']" where "{SomeGuid}" is my Person resource's ObjectID attribute.  Now this, unfortunately, would require that I know my Person resource's ObjectID and GUID's really are not that human friendly (have you ever tried to type one manually?).  It would be nice if I could instead use something else I know to be unique on my Person resource as a way of identifying the Manager value.  With a little bit of understanding of the Person resource we can identify that the AccountName and Domain attribute pair must also be unique.  Luckily those two attributes are strings (much easier to type).  Taking that into consideration, we can now write the following XPath:  "/Person[Manager=/Person[AccountName='markgabarra' and Domain='Domain1']/ObjectID]".  This group would then populate its membership with every resource in the Microsoft Identity Lifecycle Manager "2" system of type Person that has its Manager attribute set to the value of every ObjectID value for every resource in the Microsoft Identity Lifecycle Manager "2" system of type Person that has its AccountName attribute set to the value "markgabarra" and its Domain attribute set to the value of "Domain1".  Assuming that I have correctly identified my AccountName (markgabarra) and my Domain (Domain1), this results in the embedded XPath returning only my Person resource's ObjectID, thus the total XPath results in returning every resource in the Microsoft Identity Lifecycle Manager "2" system of type Person that has its Manager attribute set to my ObjectID.

Now lets look at the scenario mentioned in the question regarding CostCenter.  From the discussion above creating a group for all Person resources in the CostCenter named "Department 100" would involve creating a dynamic group with the filter "/Person[CostCenter='Department 100']".  This answers the question about maintaining (and populating) a group based on a specific attribute since Microsoft Identity Lifecycle Manager "2" will automatically manage the group membership for the lifetime of that group.  This leaves the question of dynamically creating such groups.  To answer this I will have to take a step back and talk conceptually.  Due to schedule and resource constraints the current Beta of Microsoft Identity Lifecycle Manager "2" had to ship without the features needed to support this scenario.  However, those features will be available in the final released version of the product.

As a side note on XPath filters within Microsoft Identity Lifecycle Manager "2" for you administrators and IT Professionals out there, if you are interested in creating a filter of all resources created by a specific person you could use the direct manager example above with some minor changes. To tell the filter to target "all resources" and not just resources of a specific type you would use the "*" wildcard. To identify the creator of a resource you would look at the Creator attribute. In the case of finding all resources that I created (assuming the same AccountName and Domain values for my Person resource above) you would use the following XPath filter: "/*[Creator=/Person[AccountName='markgabarra' and Domain='Domain1']/ObjectID]".

In an earlier post (AuthN, AuthZ, and Action, oh my: Microsoft Identity Lifecycle Manager "2" Request Processing) I started to detail the different phases of request processing within Microsoft Identity Lifecycle Manager "2".  This post discussed the internal details of these phases but left for a later post the discussion of how scenarios can use these phases to solve specific problems.  For this discussion I will focus on one possible use of the Action phase of request processing to solve the problem of dynamic group creation based on specific attribute values.

Briefly summarizing the relevant content in my previous posts, it is important to know the following:

The creation of a dynamic group based on the possible values of an attribute can be done in a couple of ways.  Lets look at two possibilities:

  1. The attribute in question has a restricted set of possible values enforced through Microsoft Identity Lifecycle Manager "2" schema (e.g. an integer with explicit MinValue and MaxValue, a string with explicit StringRegEx defining an enumerated string, etc)
  2. The attribute in question does has an unrestricted set of possible values (it is worth noting that this solution would also work for the above scenario as well and is a more general solution to this problem)

In the first case, I would create a ManagementPolicyRule that would trigger for updates to the specified AttributeTypeDescription resource that contains the attribute's Microsoft Identity Lifecycle Manager "2" schema information (from the question above "/AttributeTypeDescription[SystemName='CostCenter']") and touched the appropriate attribute that restricted the set (from the question above "StringRegEx" since "CostCenter" is a string attribute).  To this ManagementPolicyRule I would attach a single ActionWorkflowDefinition.  This action workflow would perform the following algorithm (notes about what is available and what requires custom code are based on the current Beta of Microsoft Identity Lifecycle Manager "2" and not the final release version):

  1. Retrieve the current request (available with the Microsoft Identity Lifecycle Manager "2" CurrentRequestActivity)
  2. Inspect the current request's parameters to determine the change to the StringRegEx attribute (requires custom code)
  3. Determine the new possible set of filters for dynamic groups for each possible value (requires custom code)
  4. For each possible filter value do the following (requires custom code, can use Windows Workflow Foundation WhileActivity or ReplicatorActivity)
    1. Query Microsoft Identity Lifecycle Manager "2" for any groups whose filter is the possible value (requires custom code and reentering through the Web Service layer)
    2. If above query results in zero results do the following (requires custom code, can use Windows Workflow Foundation IfElseActivity)
      1. Create new Microsoft Identity Lifecycle Manager "2" Group resource with appropriate filter (available with the Microsoft Identity Lifecycle Manager "2" CreateResourceActivity)

In the second case, I would create a ManagementPolicyRule that would trigger for all creates and updates of an appropriate set of resources (from the question above "All Persons") where the request touched the specific attribute (from the question above "CostCenter").  To this ManagementPolicyRule I would attach a single ActionWorkflowDefinition.  This action workflow would perform the following algorithm (notes about what is available and what requires custom code are based on the current Beta of Microsoft Identity Lifecycle Manager "2" and not the final release version):

  1. Retrieve the current request (available with the Microsoft Identity Lifecycle Manager "2" CurrentRequestActivity)
  2. Inspect the current request's parameters to determine the value this request set the key attribute (requires custom code)
  3. Determine the new possible filters for the dynamic group for this value (requires custom code)
  4. Query Microsoft Identity Lifecycle Manager "2" for any groups whose filter is the possible value (requires custom code and reentering through the Web Service layer)
  5. If above query results in zero results do the following (requires custom code, can use Windows Workflow Foundation IfElseActivity)
    1. Create new Microsoft Identity Lifecycle Manager "2" Group resource with appropriate filter (available with the Microsoft Identity Lifecycle Manager "2" CreateResourceActivity)

These two approaches will result in the dynamic creation of these groups when new (possible) values are detected for the key attribute.  They do not address the deletion of such groups when those values are no longer available.  This is a bit more complex of a problem, but is possible.  Staying at a very high conceptual level, I would recommend extending the schema of the Microsoft Identity Lifecycle Manager "2" Group resource to add an attribute that can be used to mark these dynamically created groups.  I would then create an Microsoft Identity Lifecycle Manager "2" temporal Set that contains an XPath filter selecting all of these dynamically created groups that were modified in the last 24 hours (I will leave the details of creating a temporal set to another post).  Next, I would create a ManagementPolicyRule that triggered on resources that transitioned into that Set and attach a single ActionWorkflowDefinition.  The action workflow would Use the Microsoft Identity Lifecycle Manager "2" ReadResourceActivity to retrieve the target resource and count the number of values in the ComputedMember attribute.  If that number is zero (meaning the group has zero membership), it would use the Microsoft Identity Lifecycle Manager "2" DeleteResourceActivity to delete the target resource.  This would result in the dynamically created groups deleting themselves shortly after their membership become empty.

The workflow definitions for these two approaches may seem complex and require a number of steps utilizing custom code and (in the case of querying Microsoft Identity Lifecycle Manager "2") reentering the Microsoft Identity Lifecycle Manager "2" Web Service layer from within workflow.  This may be disheartening to some of the potential customers of Microsoft Identity Lifecycle Manager "2"; however, let me provide some good news.  Shortly after the current Beta of Microsoft Identity Lifecycle Manager "2" released I was able to get to the missing features to better support these scenarios with less custom code.  Microsoft Identity Lifecycle Manager "2" will ship with an EnumerateResourcesActivity that will allow workflow developers to set an XPath filter and perform operations on each resource returned (or just use it to get a count of resources that match a specified filter).  Additionally, Microsoft Identity Lifecycle Manager "2" will ship with a ResourceTemplateActivity that can be used to dynamically create a resource based off of a template should a test filter return a count of zero.  In other words, the ResourceTemplateActivity can be used to perform steps 4, 5, and 5.1 in the algorithm of option two, and steps 4.1, 4.2, and 4.2.1 of option one.  The EnumerateResourcesActivity can be used to perform step 4 of option one.  In both options this reduces the amount of custom code to inspecting the contents of the request to calculate the desired filter(s).

This begs the question, how do I write this custom code?  That is a longer topic for multiple follow up posts around the topics of writing custom workflow and/or custom activities.  I will have to leave it for another time, although I am working my way in that direction and I appreciate your patience.  In the mean time, feel free to use my Contact Form or the Comments on my blog to ask questions or suggest topics.