Walking through the Office 365 IDM driver – Part 2

0 Likes
With all the cloud offerings out there, managing them gets to be as much as problem as they help make things easier. Good news, a new driver for IDM to provision to Microsoft's cloud offering Office 365 is available. This series will walk through the policies in as much gory detail as possible to help understand and troubleshoot issues that may arise.

In part one of this series Walking through the Office 365 IDM driver – Part 1 I walked through some of the configuration, Packages, and GCVs used in the Office 365 IDM driver.

Now to continue looking at GCVs. Continuing to look at the Entitlements GCV tab, since it has some interesting things going on.

One of the nice things the later drivers have been doing is using the group features in GCV to set up groups of GCV's, and hide/show them based on a control. So you get an Advanced Setting GCV with two options, hide and show. This way you can de-clutter your screen or not. This type of GCV option has been there all along (well I guess since IDM 3 at least) but just not been well used.

Inside Advanced Settings when expanded, there are some standard GCV values. For Data Collection, Role Mapping, and Resource Mapping it defines whether to enable them at all, and if so, for the four entitlement types, allow or deny each type, and whether to use the older entitlement formatting or the new JSON IDM 4.x version.

These options are used indirectly, during driver startup in the Input Transform, to build the entitlementsConfiguration object. You can read more about this entire process in a pair of articles. The first is about how to add this sort of support to a new driver, and the second is my explanation of why that policy works:





In this driver, clearly more GCVs and option exist, so I am sure the rule used to build the entitlementsConfiguration object is likely quite different from the specific example in those articles.

The content of the object looks something like this for a typical install.

<?xml version="1.0" encoding="UTF-8"?><entitlement-configuration modified="20130102020013">
<entitlements>
<entitlement data-collection="true" dn="CN=Group,CN=Office 365,CN=driverset1,O=system" parameter-format="idm4" resource-mapping="true" role-mapping="true">
<type category="security grouping" id="group" name="group">
<display-name>
<value langCode="de">Gruppe</value>
<value langCode="en">Group</value>
</display-name>
</type>
<parameters>
<parameter mandatory="true" name="ID" source="association"/>
<parameter mandatory="true" name="ID2" source="src-dn"/>
</parameters>
<member-assignment-extensions>
<query-xml>
<read-attr attr-name="member"/>
</query-xml>
</member-assignment-extensions>
<query-extensions>
<query-xml>
<read-attr attr-name="owner"/>
<operation-data data-collection-query="true"/>
</query-xml>
</query-extensions>
</entitlement>
<entitlement data-collection="true" dn="CN=License,CN=Office 365,CN=driverset1,O=system" parameter-format="idm4" resource-mapping="true" role-mapping="true">
<type category="license " id="license" name="license">
<display-name>
<value langCode="de"/>
<value langCode="en"/>
</display-name>
</type>
<parameters>
<parameter mandatory="true" name="ID" source="read-attr" source-name="AccountSkuId"/>
</parameters>
<member-assignment-query>
<query-xml>
<nds dtdversion="2.0">
<input>
<query class-name="MSolLicense" scope="subtree">
<search-class class-name="MSolLicense"/>
<read-attr attr-name="AccountSkuId"/>
<read-attr attr-name="AccountName"/>
</query>
</input>
</nds>
</query-xml>
</member-assignment-query>
<query-extensions>
<query-xml>
<read-attr attr-name="AccountSkuId"/>
<operation-data data-collection-query="true"/>
</query-xml>
</query-extensions>
</entitlement>
<entitlement data-collection="true" dn="CN=Role,CN=Office 365,CN=driverset1,O=system" parameter-format="idm4" resource-mapping="true" role-mapping="true">
<type category="role" id="role" name="role">
<display-name>
<value langCode="de"/>
<value langCode="en"/>
</display-name>
</type>
<parameters>
<parameter mandatory="true" name="ID" source="read-attr" source-name="Name"/>
</parameters>
<member-assignment-query>
<query-xml>
<nds dtdversion="2.0">
<input>
<query class-name="MSolRole" scope="subtree">
<search-class class-name="MSolRole"/>
<read-attr attr-name="Name"/>
<read-attr attr-name="Description"/>
</query>
</input>
</nds>
</query-xml>
</member-assignment-query>
<query-extensions>
<query-xml>
<read-attr attr-name="Name"/>
<operation-data data-collection-query="true"/>
</query-xml>
</query-extensions>
</entitlement>
<entitlement data-collection="true" dn="CN=UserAccount,CN=Office 365,CN=driverset1,O=system" parameter-format="idm4" resource-mapping="true" role-mapping="true">
<type category="security account" id="user" name="account">
<display-name>
<value langCode="de">Benutzer</value>
<value langCode="en">User</value>
</display-name>
</type>
<parameters>
<parameter mandatory="true" name="ID" source="read-attr" source-name="DomainValue"/>
</parameters>
<member-assignment-query>
<query-xml>
<nds dtdversion="2.0">
<input>
<query class-name="MSolUser" scope="subtree">
<search-class class-name="MSolUser"/>
<read-attr/>
</query>
</input>
</nds>
</query-xml>
</member-assignment-query>
<query-extensions>
<query-xml>
<read-attr attr-name="UserPrincipalName"/>
<read-attr attr-name="BlockCredential"/>
<operation-data data-collection-query="true"/>
</query-xml>
</query-extensions>
<account>
<account-id source="read-attr" source-name="UserPrincipalName"/>
<account-id source="association"/>
<account-status active="false" inactive="true" source="read-attr" source-name="BlockCredential"/>
</account>
</entitlement>
</entitlements>
</entitlement-configuration>


In the end, as far as I can tell, the core reason for doing this in policy, every driver restart instead of at driver creation time is as likely to be due to the need for an LDAP DN inside the object. It is hard (I am not sure it even possible) in the options available during

You can see an example in the first entitlement node in my example above, since the above longer example is actually for the four different entitlement types.

<entitlement data-collection="true" dn="CN=Group,CN=Office 365,CN=driverset1,O=system" parameter-format="idm4" resource-mapping="true" role-mapping="true">
<type category="security grouping" id="group" name="group">
<display-name>
<value langCode="de">Gruppe</value>
<value langCode="en">Group</value>
</display-name>
</type>
<parameters>
<parameter mandatory="true" name="ID" source="association"/>
<parameter mandatory="true" name="ID2" source="src-dn"/>
</parameters>
<member-assignment-extensions>
<query-xml>
<read-attr attr-name="member"/>
</query-xml>
</member-assignment-extensions>
<query-extensions>
<query-xml>
<read-attr attr-name="owner"/>
<operation-data data-collection-query="true"/>
</query-xml>
</query-extensions>
</entitlement>


Here you can see in the <entitlement> node that the dn= value is an LDAP format DN of the driver, which of course cannot be preset, since it depends on the tree structure. But the various GCVs seen in the Entitlements section are obviously implemented here. The parameter-format to idm4, is the difference between legacy and idm4. You can see the data-collection, resource-mapping, and role-mapping values that come from the GCVs.

The <display-name> values come out of a mapping table, which should support any other languages if you need them.

The <parameters> set of nodes is actually a custom rule and you can see there are two mandatory parameters to add a group. ID, which is the association of the Group, and ID2, the source DN. The <query-xml> and the <query-extensions> come from the GCVs in the Entitlement Extensions section.

In the case of the License and Role entitlements, where it is not clear what values they want in the entitlement, you can see from the example entitlementsConfiguration object that the Role is looking for a parameter, of ID, with the Name of the license:

    <parameter mandatory="true" name="ID" source="read-attr" source-name="Name"/>


The query extensions look like they read just the Name and Description values.

For the License objects it looks like the parameter it wants is:

    <parameter mandatory="true" name="ID" source="read-attr" source-name="AccountSkuId"/>


Which suggests an ID based on the AccountSkuId values. I asked a friend running Office 365 and they looked at the objects with the PowerShell cmdlet:

	Get-MsolAccountSku


Which returned:

ExtensionData   : System.Runtime.Serialization.ExtensionDataObject
AccountName : acmemail
AccountObjectId : c3135dc0-73fc-4123-a174-17f256ed7fe7
AccountSkuId : acmemail:EXCHANGEDESKLESS
ActiveUnits : 1500
ConsumedUnits : 0
ServiceStatus : {Microsoft.Online.Administration.ServiceStatus}
SkuId : 89999799-d77a-552a-8842-fb0fff3a4b82
SkuPartNumber : EXCHANGEDESKLESS
SubscriptionIds : {356aa8c0-c37a-4428-ba9c-26ed1afb35af}
SuspendedUnits : 0
TargetClass : User
WarningUnits : 0


Which would seem to indicate the value is likely sitename:EXCHANGEDESKLESS as a possible value for the entitlement.

The query extension looks for AccountSkuId and AccountName, which gives further hints.

I was able to track down some scripting examples for doing this with PowerShell, and in it, he defined the various license values. So I think this at least is a first approximation of the possible values to provide. The upper case short name appear to be the license value, and the second value on each line is a more human readable version of that.

"DESKLESSPACK" = "Office 365 (Plan K1)"
"DESKLESSWOFFPACK" = "Office 365 (Plan K2)"
"LITEPACK" = "Office 365 (Plan P1)"
"EXCHANGESTANDARD" = "Office 365 Exchange Online Only"
"STANDARDPACK" = "Office 365 (Plan E1)"
"STANDARDWOFFPACK" = "Office 365 (Plan E2)"
"ENTERPRISEPACK" = "Office 365 (Plan E3)"
"ENTERPRISEPACKLRG" = "Office 365 (Plan E3)"
"ENTERPRISEWITHSCAL" = "Office 365 (Plan E4)"
"STANDARDPACK_STUDENT" = "Office 365 (Plan A1) for Students"
"STANDARDWOFFPACKPACK_STUDENT" = "Office 365 (Plan A2) for Students"
"ENTERPRISEPACK_STUDENT" = "Office 365 (Plan A3) for Students"
"ENTERPRISEWITHSCAL_STUDENT" = "Office 365 (Plan A4) for Students"
"STANDARDPACK_FACULTY" = "Office 365 (Plan A1) for Faculty"
"STANDARDWOFFPACKPACK_FACULTY" = "Office 365 (Plan A2) for Faculty"
"ENTERPRISEPACK_FACULTY" = "Office 365 (Plan A3) for Faculty"
"ENTERPRISEWITHSCAL_FACULTY" = "Office 365 (Plan A4) for Faculty"
"ENTERPRISEPACK_B_PILOT" = "Office 365 (Enterprise Preview)"
"STANDARD_B_PILOT" = "Office 365 (Small Business Preview)"


Of course, my friends license type (EXCHANGEDESKLESS) is not to be found in that list, and I am not entirely certain what that means in terms of its completeness, but so far this is the best list I have found. In fact, I would be fairly certain it will change over time as well as more services, plans, and combinations are made available by Microsoft.

A further concern is that when I look at the output above of the Get-MsolAccountSku PowerShell cmdlet I see that the AccountSkuId is the companies shortname:LICENSETYPE and I am still not sure exactly what should be set exactly in the ID parameter yet. But getting closer with every step.

Back to the entitlementsConfiguration object, we will see later, in the Input Transform we will look at the policy that generates this object. I happen to think the current model is sort of silly, because it requires a code change in policy to handle additional types of entitlements, and thus each driver really needs a custom policy to build its custom entitlementsConfiguration object which begs the question: Why not just include a custom object instead of the custom policy? Yes, I understand you get a slightly easier way to tune the object via the GCVs but in reality, how often does that ever happen? I accept it as a design choice, but wonder if it is the most effective way to do it. If it worked to easily handle additional entitlements without a code change, I think I would be less bothered by it. For example, if the GCV's that control were all instances of a Structured GCV, then a loop over them would be a single piece of code that could do 0, 1, or N values. I may just propose that to them, since it is a slightly more generic solution. Lets see, Structured GCV's showed up in IDM 3.6.1 to support the SAP fanout configurations, along with the pipe separated Entitlement parameter values, and RBPM 3.7 was meant to be run on IDM 3.61 so timing is about right, that they could have taken advantage of this possibility. That might be a fun side project for an article, how to rewrite the ITP init EntitlementsConfiguration object using a structured GCV. (Upgrading to it would stink, though in reality, with Package Prompts it should be possible.)

The other GCV object of interest is from the Default Configuration package, and is labeled Driver Configurations in the GUI. This one has the Office 365 domain name, which makes sense, need that as a parameter no doubt for sending events and calculating a proper User Principal Name (UPN). Then there is an interesting GCV called Identities to be synchronized with a choice of AD or IDV. This is one of those things I may wait until we hit a policy to implement since I do not usually read that far ahead in these articles, and I do not yet know how this is implemented. Principally the idea is to allow two modes for the driver. The first would be to only sync users in your AD to Office 365, so users in the IDV would require a DirXML-Associations value to your AD driver (possibly the key point being a GUID in AD being sent to O365). The second would be to sync any user who meets the criteria in the IDV.

When you switch between the two options, different choices show up in the GUI. For the IDV there is no further configuration. However for the AD option, you get a Structured GCV (Still one of my favorite GCV types!) that allows multiple instances, of two values. The AD Domain name (like myDomain.com) and the DN of the driver to that domain. This is actually a useful enhancement. There is a problem that Microsoft has not addressed as of this writing, related to having multiple domains. They want you to use DirSync to do a point to point sync, AD to O365. Then use ADFS (Their federation service) to federate the O365 login to your AD domain, which is nice as you get SSO to O365. I was going to say password sync, but now I wonder. If they are just federating, does it matter if the password in O365 matches? But what if you have more than one AD Forest. Apparently you can only run one DirSync to O365. So you have to pick one forest.

The issue appears to be that the GUID of the AD user is used in O365 as a unique identifier. (After all as a hosted service, there may be millions of users and names will likely duplicate but GUIDs are a girls best friend? No wait that is diamonds. GUIDs are forever, ya, that's the ticket).

Thus this is a neat possible solution to a problem MS itself does not have a good solution for. Here you would use your IDM system, with the multiple AD domains. But if you wanted to use the MS approach to O365 they would want you to install DirSync as a point to point AD to O365 sync tool. Then ADFS to do SSO via Federation.

However, if you have more than one AD forest, DirSync won't cut it, since there seems to be a limit of one DirSync to O365 endpoint, so you could only sync one forest. (It is not clear to me if one DirSync per forest can consume multiple domains or not yet). But further, when you try to do federate via SAML to Office 365 whether that be in Tivoli (TAM), NetIQ Access Manager (NAM), CA SiteMinder, or even ADFS you need to identify your target with a unique identifier, which is called ImmutableId. A GUID is a good choice in theory, since it ought not to change (That is why it is used as the DirXML-Associations value in the AD driver) but what if you have different GUID values. Which one should you sync to O365 and where should you read to assert that GUID? On the Windows side, folk want their Kerberos ticket to be the authentication source, and be trusted for SSO with no further prompting.

I was surprised, when I looked in the Output Transform for the code to handle this. I expected that the GUID being sent as ImmutableId would be the AD GUID from the DirXML-Associations for the matched domain, but it turns out it is always the eDirectory GUID attribute. I have a different policy approach that I am submitting for consideration, that in eDir mode, still sends the eDir GUID. But in AD sync mode, it will take the last DirXML-Associations it finds that matches one of your listed AD drivers, and send that value to O365 as ImmutableID. Thus you should have an easier time of doing federation with whatever tool you intend to use.

Depending on how that goes, I will at least talk about that specific policy a bit later in this series and include some sample code for it. I would prefer to try and get the package updated for everyone, instead of running dirty (where Package Manager notices you have modified an existing package) but sometimes you gotta get down in the dirt and play.

Finally there is one last GCV in this object that is labeled Usage Location. The Description on the GCV says it is a two letter country code that is required before a license can be assigned. The default is provided as US, and for most countries I am sure Microsoft is using a standard country code, and you can guess what yours must be.

That about wraps up the GCVs in this driver, which took longer than I expected, but it turns out they have a lot more consequence in the end than in some other drivers. One of the design goals for the packaged drivers, as I have heard it, is to try and offer choices that are controlled by settings, not by code changes. If there are two or three good ways to do something, implement all three, and use GCVs to control which is applied. Of course this adds to the testing complexity, but that is the nature of life.

Next up we will look at the Filter and Schema Map a bit to understand what attributes are in play, and what they are represented as, in Office 365.

Labels:

How To-Best Practice
Comment List
Related
Recommended