Partager via


Application Security, Part 19

Remember, however, that we don’t want all of the users in Active Directory provisioned in ADAM, but only those that belong to the YourApplicationUsers group within Active Directory, yet nothing in the code for our meta-verse rule extension checked to which group the person objects in the meta-verse belonged. No: all of the objects projected into the meta-verse from Active Directory have corresponding objects created for them in the ADAM connector space. Why is that? Well, the Provision handler defined in the IMVSynchronization interface is passed a parameter of the type, MVEntry, representing the object projected into the meta-verse, and the MVEntry class provides no facilities for determining the groups to which a person object may belong. So, our sole option for ensuring that only users belonging to that group are provisioned into ADAM is write a second rule extension, one that extends the Active Directory management agent in such a way that it only projects users in the YourApplicationUsers group into the MIIS meta-verse. Thus, the management agent for Active Directory has to br configured so that, when deciding how and whether to project an object from the Active Directory connector space into the MIIS metaverse, it executes a rule extension. As was true when we associated a rule extension with the meta-verse, we can only associate one rule extension with each management agent. Once again, the MIIS Identity Manager can automatically generate a Visual Studio.NET project for programming our rule extension.

Here is the code for it:

 

using System;

using System.Collections;

using System.IO;

using System.Runtime.Serialization;

using System.Runtime.Serialization.Formatters.Binary;

using Microsoft.MetadirectoryServices;

using Microsoft.DeveloperAndPlatformEvangelism.Demonstrations.TaskVisionII.Utility;

namespace Mms_ManagementAgent_dataJoin_ActiveDirectory

{

public class MAExtensionObject: CLoggingRuleExtension, IMASynchronization

{

private const string c_sFile_Cache = "dataJoin_ActiveDirectory.dat";

private const string c_sFile_Log = @"Join_ActiveDirectory.log";

private const byte c_byThreshold_Log = 10;

private const string c_sCriterion_GroupName = @"YourApplicationUsers";

private const string c_sExceptionMessage_DeSerialization = @"De-serialization failed";

private const string c_sExceptionMessage_Serialization = @"Serialization failed";

private ArrayList m_arMembers = null;

public MAExtensionObject()

{

//

// TODO: Add constructor logic here

//

base.sFile_Log = MAExtensionObject.c_sFile_Log;

base.byThreshold_Log = MAExtensionObject.c_byThreshold_Log;

this.Log(@"Constructed.");

}

void IMASynchronization.Initialize ()

{

//

// TODO: write initialization code

//

}

void IMASynchronization.Terminate ()

{

//

// TODO: write termination code

//

}

bool IMASynchronization.ShouldProjectToMV (CSEntry rConnectorSpaceEntry, out string sMetaverseObjectType)

{

this.Log(@"ShouldProjectToMV");

string sConnectorSpaceObjectType = rConnectorSpaceEntry.ObjectType;

this.Log(string.Concat(@"Metaverse object type: ",sConnectorSpaceObjectType));

switch(sConnectorSpaceObjectType)

{

case "group":

sMetaverseObjectType = @"group";

string sGroupName = rConnectorSpaceEntry[@"cn"].Value;

if(sGroupName == MAExtensionObject.c_sCriterion_GroupName)

{

Microsoft.MetadirectoryServices.ValueCollection arMembers = rConnectorSpaceEntry[@"member"].Values;

int cMembers = arMembers.Count;

if(this.m_arMembers == null)

{

this.m_arMembers = new ArrayList(cMembers);

}

for(int cCurrentMember = 0;cCurrentMember < cMembers;cCurrentMember++)

{

this.m_arMembers.Add(arMembers[cCurrentMember].ToString());

}

foreach(string sMember in this.m_arMembers)

{

this.Log(sMember);

}

}

return false;

default:

sMetaverseObjectType = @"person";

string sName = rConnectorSpaceEntry.DN.ToString();

if(this.m_arMembers != null)

{

foreach(string sMember in this.m_arMembers)

{

this.Log(string.Concat("Comparing ",sName," to ",sMember));

if(string.Compare(sName,sMember,true)==0)

{

this.Log(string.Concat(@"Projecting ",sName));

return true;

}

}

}

return false;

}

}

DeprovisionAction IMASynchronization.Deprovision (CSEntry rConnectorSpaceEntry)

{

//

// TODO: Remove this throw statement if you implement this method

//

throw new EntryPointNotImplementedException();

}

bool IMASynchronization.FilterForDisconnection (CSEntry csentry)

{

//

// TODO: write connector filter code

//

throw new EntryPointNotImplementedException();

}

void IMASynchronization.MapAttributesForJoin (string FlowRuleName, CSEntry csentry, ref ValueCollection values)

{

//

// TODO: write join mapping code

//

throw new EntryPointNotImplementedException();

}

bool IMASynchronization.ResolveJoinSearch (string joinCriteriaName, CSEntry csentry, MVEntry[] rgmventry, out int imventry, ref string MVObjectType)

{

//

// TODO: write join resolution code

//

throw new EntryPointNotImplementedException();

}

void IMASynchronization.MapAttributesForImport( string FlowRuleName, CSEntry csentry, MVEntry mventry)

{

//

// TODO: write your import attribute flow code

//

throw new EntryPointNotImplementedException();

}

void IMASynchronization.MapAttributesForExport (string FlowRuleName, MVEntry mventry, CSEntry csentry)

{

//

// TODO: write your export attribute flow code

//

throw new EntryPointNotImplementedException();

}

}

}

 

 

The method of the IMASynchronization interface that we need to program is the ShouldProjectToMV method. That method is invoked for each object in the connector space of a management agent that does not match, join on, an object in the meta-verse, and, if and only if the method returns true, then the object in the connector space is projected into the meta-verse. Our code only returns true for user objects: those are the only ones that we need to propagate to the meta-verse for provisioning into ADAM. However, if the object in the connector space for which the ShouldProjectToMV method is called happens to be a group, then the code for the method checks to see if that group is the YourApplicationUsers group. If it is, then the code accesses the member attribute of the object to retrieve a list of the users belonging to that group, and copies their names into an arraylist. When the method is called for user objects in the connector space, the arraylist is searched to see if that user object is a member of the YourApplicationUsers group, and if and only if that is the case, then the method returns true to signify that the object should indeed be projected into the meta-verse.

 

Now, there is no guarantee that the management agents will process the user objects only after all of the group objects have been processed, so it is possible that the arraylist will be empty when the method is invoked for user objects that are in fact members of the YourApplicationUsers group; in that case, those user objects will not be recognized as members of the group and will not be projected into the meta-verse. Happily, that problem can be solved by having the management agent execute an import of objects from Active Directory to the Active Directory connector space twice in succession. The rule extension remains in memory for as long as the MIIS service is left running, so the contents of the arraylist persists across successive executions of the management agent.

Comments

  • Anonymous
    July 30, 2004
    My first thought was to wonder why you didn't use the memberOf attribute for the AD user object but I realized that MIIS doesn't list it in the Attributes for the ADMA user or the MV person objects (but it does for the organizationalPerson object in Exchange 5.5). By extending both the MA (I believe it to be possible) and MV schema you could import this attribute and maybe determine group membership more effeciently.