Hello,
Sharing MVExtension.cs
void ProvisionExternalUser(string maName, MVEntry mventry)
{
//this method updates the dn and populates the desired attributes on first synchronization
var managementAgent = mventry.ConnectedMAs[maName];
var connectors = managementAgent.Connectors.Count;
//Has the object been provisioned?
if (connectors == 0)
{
//Is the object ready for provisioning? / includes a case when the AD account was accidentally deleted in AD (re-provisions the user, password is re-generated in ADMA extension)
if (mventry["initialPassword"].IsPresent
&& mventry["employeeType"].IsPresent && mventry["employeeType"].StringValue.Equals("External", StringComparison.InvariantCultureIgnoreCase)
&& mventry["employeeStatus"].IsPresent && mventry["employeeStatus"].StringValue.Equals("Active", StringComparison.InvariantCultureIgnoreCase)
&& mventry["crmSyncStatus"].IsPresent && (mventry["crmSyncStatus"].StringValue.Equals("NonEffective", StringComparison.InvariantCultureIgnoreCase) || mventry["crmSyncStatus"].StringValue.Equals("Effective", StringComparison.InvariantCultureIgnoreCase))
)
{
var isGeneric = mventry["credentialType"].IsPresent && mventry["credentialType"].StringValue.Equals("generic", StringComparison.InvariantCultureIgnoreCase);
//Provision object
var csentry = managementAgent.Connectors.StartNewConnector("user");
//perpare firstName, lastName and cn
var lastname = (mventry["lastName"].IsPresent) ? mventry["lastName"].StringValue : "";
var firstname = (mventry["firstName"].IsPresent) ? mventry["firstName"].StringValue : "";
if (!String.IsNullOrEmpty(firstname))
{
var ti = new CultureInfo("en-US", false).TextInfo;
firstname = ti.ToTitleCase(firstname);
}
var strB = new StringBuilder();
if (!String.IsNullOrEmpty(firstname))
{
strB.AppendFormat("{0} ", firstname);
}
strB.Append(lastname.ToUpperInvariant());
if (isGeneric)
{
strB.AppendFormat(" {0}", GenericSuffix);
}
var cnString = strB.ToString();
//initialize common attributes
csentry["userAccountControl"].IntegerValue = 0x200; //Normal Account
csentry["pwdLastSet"].Value = "0"; //Change Password at first logon
csentry["unicodePwd"].Value = mventry["initialPassword"].StringValue; //set initial password
if (ProvisionUniqueId)
{
csentry["objectGUID"].BinaryValue = Guid.NewGuid().ToByteArray();
}
//initialize provisioning dependent on DN and samAccountName
//the advanced logic is there for cases when more than one user is provisioned
//to AD at the same time - the existence check is done in AD-GetAdId and then in MV-try,catch on commmit
var provisioned = false;
var iteration = 0;
bool userExists = false;
while (!provisioned)
{
//Get unique samAccountName
var samAccountNameVal = this.GetAdId(firstname, lastname, isGeneric, ref iteration, ref userExists);
var cn = String.Concat(cnString, " (", samAccountNameVal, ")");
var rdn = String.Concat("CN=", cn);
//Fill attributes of csentry
csentry["cn"].Value = cn;
csentry["sAMAccountName"].Value = samAccountNameVal;
csentry["userPrincipalName"].Value = String.Concat(samAccountNameVal, "@", UpnSuffix);
//set the DN
csentry.DN = csentry.MA.EscapeDNComponent(rdn).Concat(RootOu);
if (userExists)
csentry["description"].Value = "userExistsInAD";
try
{
//Finish new connector
csentry.CommitNewConnector();
provisioned = true;
}
catch (ObjectAlreadyExistsException)
{
//if (iteration > MaxProvisioningAttempts)
//{
// //exceeded number of attempts
// throw;
//}
}
}
}
}
else if (connectors > 1)
{
throw new UnexpectedDataException("Too many connectors on Management Agent " + maName);
}
}
DMZ MA Extension
DMZ ECMA2
ActiveDirectoryContext.cs
public IEnumerable<CSEntryChangeResult> PutExportCsObjects(IEnumerable<CSEntryChange> changes)
{
var csEntryChangeResults = new List<CSEntryChangeResult>();
foreach (var csEntryChange in changes)
{
var exportObject = exportObjectFactory.CreateExportObject(csEntryChange);
csEntryChangeResults.Add(this.writer.Write(exportObject));
}
return csEntryChangeResults;
}
ExportObjectFactory.cs
public ActiveDirectoryExportObject CreateExportObject(CSEntryChange csEntry)
{
switch (csEntry.ObjectType.ToLowerInvariant())
{
case "user":
return new UserExportObject(csEntry, connection, mapper);
case "group":
return new GroupExportObject(csEntry, connection, mapper);
case "foreignsecurityprincipal":
return new FspExportObject(csEntry, connection, mapper, FspDecoyGroupDn);
default:
return new ActiveDirectoryExportObject(csEntry, connection, mapper);
}
}
class UserExportObject : ActiveDirectoryExportObject
{
public UserExportObject(CSEntryChange csEntry, IActiveDirectoryConnection connection, ActiveDirectoryObjectMapper mapper)
: base(csEntry, connection, mapper)
{
}
public override byte[] Create()
{
using (var parentDirEntry = this.connection.GetParentDirectoryEntryFromDn(this.Dn))
{
using (var newObj = parentDirEntry.Children.Add(this.Rdn, this.ObjectType).Wrap())
{
mapper.MapActiveDirectoryExportObjectToExistingDirectoryEntry(this, newObj);
newObj.CommitChanges();
mapper.MapActiveDirectoryExportObjectToExistingDirectoryEntrySecondPass(this, newObj);
return newObj.Guid.ToByteArray();
}
}
}
public override byte[] Update()
{
if (!this.connection.DirectoryEntryExistsFromDn(this.Dn))
{
throw new ObjectMissingException(String.Format("Object {0} does not exist in Active Directory.", this.Dn));
}
using (var adObject = this.connection.GetDirectoryEntryFromDn(this.Dn))
{
if (this.IsRenamed)
{
string attributeDNValue = this.GetSingleValuedAttributeValue("DN") as string;
adObject.Rename(Utils.GetRdnFromDn(attributeDNValue));
if (attributeDNValue.Contains("DisabledAccounts"))
{
var adnewObject = this.connection.GetDirectoryEntryFromDn(attributeDNValue.Substring(attributeDNValue.IndexOf(",") + 1));
adObject.MoveTo(adnewObject);
}
}
mapper.MapActiveDirectoryExportObjectToExistingDirectoryEntry(this, adObject);
adObject.CommitChanges();
mapper.MapActiveDirectoryExportObjectToExistingDirectoryEntrySecondPass(this, adObject);
return adObject.Guid.ToByteArray();
}
}
}
With the above code, MIM Export throws below error.
I am not sure how much this code helps you understand my project. Please feel free to contact me for more details.
I don't know if its normal, but if you would like a Teams meeting, i can arrange that to show you my code in detail.
Kind Regards,
Madhu