private void SetupInitialValues(ConnectedMA ma, CSEntry csentry, MVEntry mventry, Rule connectorRule) { Tracer.TraceInformation("enter-setupinitialvalues"); try { if (connectorRule.Helpers != null) { Tracer.TraceInformation("generating-helper-values"); foreach (HelperValue helper in connectorRule.Helpers) { helper.Generate(); } } foreach (AttributeFlowBase attributeBase in connectorRule.InitialFlows) { attributeBase.Generate(ma, csentry, mventry, connectorRule); } } catch (Exception ex) { Tracer.TraceError("error {0}", ex.GetBaseException()); throw; } finally { Tracer.TraceInformation("exit-setupinitialvalues"); } }
public override void Generate(ConnectedMA ma, CSEntry csentry, MVEntry mventry, Rule rule) { Tracer.TraceInformation("enter-attributeflowguid"); base.Generate(ma, csentry, mventry, rule); try { Guid newGuid = Guid.NewGuid(); Tracer.TraceInformation("new-guid-'{0}'-to-'{1}'", newGuid.ToString(), this.Target); if (this.Target.Equals("[DN]", StringComparison.OrdinalIgnoreCase)) { csentry.DN = csentry.MA.CreateDN(newGuid.ToString()); } else { csentry[this.Target].Value = newGuid.ToString(); } } catch (Exception ex) { Tracer.TraceError("error {0}", ex.GetBaseException()); throw; } finally { Tracer.TraceInformation("exit-attributeflowguid"); } }
private void CreateConnector(ConnectedMA ma, MVEntry mventry, Rule rule) { Tracer.TraceInformation("enter-createconnector"); try { Tracer.TraceInformation("create-connector: MV: '{0}', MA: '{1}'", mventry.ObjectID, ma.Name); IList <string> additionalObjectClasses = this.GetAdditionalObjectClasses(mventry, rule); CSEntry csentry; if (additionalObjectClasses.Count > 0) { csentry = ma.Connectors.StartNewConnector(rule.TargetObject, additionalObjectClasses.ToArray()); } else { csentry = ma.Connectors.StartNewConnector(rule.TargetObject); } this.SetupInitialValues(ma, csentry, mventry, rule); csentry.CommitNewConnector(); } catch (Exception ex) { Tracer.TraceError("error {0}", ex.GetBaseException()); throw; } finally { Tracer.TraceInformation("exit-createconnector"); } }
public override bool Met(MVEntry mventry, CSEntry csentry) { ConnectedMA MA = mventry.ConnectedMAs[this.ManagementAgentName]; if (MA.Connectors.Count.Equals(0)) { Tracer.TraceInformation("Condition failed (Reason: Not connected to {0}) {1}", this.ManagementAgentName, this.Description); return(false); } return(true); }
public override void Generate(ConnectedMA ma, CSEntry csentry, MVEntry mventry, Rule rule) { Tracer.TraceInformation("enter-attributeflowmultivaluedconstant"); if (Target.Equals("[DN]", StringComparison.OrdinalIgnoreCase)) { throw new InvalidOperationException("Cannot use a multivalued constant flow on the DN of an object"); } if (this.Constants == null) { throw new ArgumentException("The <Constants> element must be present with one or more values when using a multivalued constant attribute flow rule"); } base.Generate(ma, csentry, mventry, rule); try { foreach (string constant in this.Constants) { string escapedCN = null; string replacedValue = null; replacedValue = constant.ReplaceWithHelperValuesOrBlank(rule.Helpers); if (string.IsNullOrEmpty(this.EscapedCN)) { Tracer.TraceInformation("no-CN-to-escape"); replacedValue = replacedValue.ReplaceWithMVValueOrBlank(mventry); } else { escapedCN = this.EscapedCN.ReplaceWithHelperValuesOrBlank(rule.Helpers); escapedCN = ma.EscapeDNComponent(this.EscapedCN.ReplaceWithMVValueOrBlank(mventry, "")).ToString(); Tracer.TraceInformation("escaped-cn '{0}'", escapedCN); replacedValue = replacedValue.ReplaceWithMVValueOrBlank(mventry, escapedCN); } Tracer.TraceInformation("flow-mv-constant-'{0}'-to-'{1}'", replacedValue, this.Target); csentry[(this.Target)].Values.Add(replacedValue); } } catch (Exception ex) { Tracer.TraceError("error {0}", ex.GetBaseException()); throw; } finally { Tracer.TraceInformation("exit-attributeflowmutlivaluedconstant"); } }
private void ConditionalRenameConnector(ConnectedMA ma, CSEntry csentry, MVEntry mventry, Rule connectorRule) { Tracer.TraceInformation("enter-conditionalrenameconnector"); try { if (connectorRule.ConditionalRename == null) { return; } string escapedCN = null; string replacedValue = null; if (string.IsNullOrEmpty(connectorRule.ConditionalRename.EscapedCN)) { Tracer.TraceInformation("no-cn-to-escape"); replacedValue = connectorRule.ConditionalRename.NewDNValue.ReplaceWithMVValueOrBlank(mventry); } else { escapedCN = ma.EscapeDNComponent(connectorRule.ConditionalRename.EscapedCN.ReplaceWithMVValueOrBlank(mventry, "")).ToString(); Tracer.TraceInformation("escaped-cn {0}", escapedCN); replacedValue = connectorRule.ConditionalRename.NewDNValue.ReplaceWithMVValueOrBlank(mventry, escapedCN); } ReferenceValue newdn = ma.CreateDN(replacedValue); ReferenceValue olddn = ma.CreateDN(csentry.DN.ToString()); Tracer.TraceInformation("old-dn '{0}'", olddn.ToString()); Tracer.TraceInformation("new-dn '{0}'", newdn.ToString()); if (this.AreDNsEqual(olddn, newdn, ma, connectorRule.ConditionalRename.StrictDNCompare)) { Tracer.TraceInformation("no-renaming-necessary"); } else { Tracer.TraceInformation("dn-rename-required"); csentry.DN = newdn; } } catch (Exception ex) { Tracer.TraceError("error {0}", ex.GetBaseException()); throw; } finally { Tracer.TraceInformation("exit-conditionalrenameconnector"); } }
private void DeprovisionConnector(ConnectedMA ma, CSEntry csentry, MVEntry mventry, Rule connectorRule) { Tracer.TraceInformation("enter-deprovisionconnector"); try { Tracer.TraceInformation("deprovision-connector: DN: '{0}', MA: '{1}'", csentry.DN, csentry.MA.Name); csentry.Deprovision(); } catch (Exception ex) { Tracer.TraceError("error {0}", ex.GetBaseException()); throw; } finally { Tracer.TraceInformation("exit-deprovisionconnector"); } }
private void ProvisionPerson(ConnectedMA agent, MVEntry mventry) { CSEntry csentry; ReferenceValue dn; string accountName; string basePath; string companyName; if (agent == null) { throw new ArgumentNullException(nameof(agent)); } if (mventry == null) { throw new ArgumentNullException(nameof(mventry)); } try { accountName = mventry["userPrincipalName"].Value.Split('@')[0]; basePath = $"{_users},OU={mventry["company"].Value},{_root}"; companyName = mventry["company"].Value.Replace(" ", string.Empty); dn = agent.CreateDN( $"CN={mventry["displayName"].Value},{basePath}"); csentry = agent.Connectors.StartNewConnector("user"); csentry.DN = dn; csentry["company"].Value = mventry["company"].Value; csentry["displayName"].Value = mventry["displayName"].Value; csentry["givenName"].Value = mventry["firstName"].Value; csentry["sAMAccountName"].Value = $"{accountName}_{companyName}"; csentry["sn"].Value = mventry["lastName"].Value; csentry["unicodePwd"].Value = _password; csentry["userAccountControl"].IntegerValue = ADS_UF_ACCOUNTDISABLE; csentry["userPrincipalName"].Value = mventry["userPrincipalName"].Value; csentry.CommitNewConnector(); } finally { csentry = null; dn = null; } }
public override void Generate(ConnectedMA ma, CSEntry csentry, MVEntry mventry, Rule rule) { Tracer.TraceInformation("enter-attributeflowconstant"); base.Generate(ma, csentry, mventry, rule); try { string escapedCN = null; string replacedValue = null; replacedValue = this.Constant.ReplaceWithHelperValuesOrBlank(rule.Helpers); if (string.IsNullOrEmpty(this.EscapedCN)) { Tracer.TraceInformation("no-CN-to-escape"); replacedValue = replacedValue.ReplaceWithMVValueOrBlank(mventry); } else { escapedCN = this.EscapedCN.ReplaceWithHelperValuesOrBlank(rule.Helpers); escapedCN = ma.EscapeDNComponent(this.EscapedCN.ReplaceWithMVValueOrBlank(mventry, "")).ToString(); Tracer.TraceInformation("escaped-cn '{0}'", escapedCN); replacedValue = replacedValue.ReplaceWithMVValueOrBlank(mventry, escapedCN); } Tracer.TraceInformation("flow-constant-'{0}'-to-'{1}'", replacedValue, this.Target); if (this.Target.Equals("[DN]", StringComparison.OrdinalIgnoreCase)) { csentry.DN = csentry.MA.CreateDN(replacedValue); } else { csentry[(this.Target)].Value = replacedValue; } } catch (Exception ex) { Tracer.TraceError("error {0}", ex.GetBaseException()); throw; } finally { Tracer.TraceInformation("exit-attributeflowconstant"); } }
private void ProvisionCustomer(ConnectedMA agent, MVEntry mventry) { CSEntry csentry; ReferenceValue dn; if (agent == null) { throw new ArgumentNullException(nameof(agent)); } if (mventry == null) { throw new ArgumentNullException(nameof(mventry)); } try { /* Define the appropriate provisioning logic here. */ } finally { csentry = null; dn = null; } }
void IMVSynchronization.Provision(MVEntry mventry) { //get our provisioning ma from the db string provisioningMAName = FIMConfiguration.GetProvisioningMA()["ma_name"].ToString(); XmlDocument xmldoc = FIMConfiguration.GetConfigXML(provisioningMAName, "private_configuration_xml"); XmlNodeList attributes = xmldoc.SelectNodes("//MAConfig/parameter-values/parameter"); //loop through each MA/object type selected foreach (XmlNode attrib in attributes) { string param = attrib.Attributes["name"].Value; string maName = param.Substring(0, param.LastIndexOf(" - ")); string objectType = param.Substring(param.LastIndexOf(" - ") + 3); //if enabled, provision it if (attrib.InnerText.Equals("1")) { //our ma has been enabled for provisioning, create a new csentry and add initial flows ConnectedMA ma = mventry.ConnectedMAs[maName]; if (ma.Connectors.Count == 0) { CSEntry csentry = ma.Connectors.StartNewConnector(objectType); //go and get the real anchor info, our provisioning ma //uses a generic anchor to ensure tha flows can be //defined for the actual anchor XmlDocument maSchemaConfig = FIMConfiguration.GetConfigXML(maName, "dn_construction_xml"); XmlNode maSchemaRoot = maSchemaConfig.FirstChild; //get dn for the object List <string> anchors = new List <string>(); if (maSchemaRoot.FirstChild.Name.Equals("attribute", StringComparison.InvariantCultureIgnoreCase)) { XmlNodeList anchorList = maSchemaConfig.SelectNodes("//dn-construction/attribute"); foreach (XmlNode anchor in anchorList) { anchors.Add(anchor.InnerText); } } else { XmlNodeList anchorList = maSchemaConfig.SelectNodes("//dn-construction/dn[@object-type='" + objectType + "']/attribute"); foreach (XmlNode anchor in anchorList) { anchors.Add(anchor.InnerText); } } //our export schema defines the initial attributes to flow XmlDocument xmlFlows = FIMConfiguration.GetConfigXML(provisioningMAName, "export_attribute_flow_xml"); XmlNodeList flows = xmlFlows.SelectNodes("//export-attribute-flow/export-flow-set[@cd-object-type='" + maName + "']/export-flow"); foreach (XmlNode flow in flows) { //get the mapping for each flow defined and provision an initial flow string csAttribName = flow.Attributes["cd-attribute"].Value; csAttribName = csAttribName.Substring(csAttribName.LastIndexOf(" - ") + 3); XmlNode mappingNode = flow.FirstChild; string mappingType = mappingNode.Name; string flowValue = null; ValueCollection flowValues = null; switch (mappingType) { case "direct-mapping": string mvAttribName = mappingNode.FirstChild.InnerText; if (mventry[mvAttribName].IsPresent) { if (mventry[mvAttribName].IsMultivalued) { flowValues = mventry[mvAttribName].Values; } else { //TODO: convert this to its proper type if necessary (i.e. int, boolean, etc) flowValue = mventry[mvAttribName].Value; } } break; case "constant-mapping": flowValue = mappingNode.FirstChild.InnerText; break; case "scripted-mapping": break; default: throw new Exception("Unexpected mapping type encountered. Only Direct, Constant and Advanced/Scripted flows are allowed. Check flow rules and try again."); } if (flowValue != null || flowValues != null) { //calc dn if necessary if (csAttribName.Equals("dn", StringComparison.InvariantCultureIgnoreCase)) { //are we safe to assume that if we are calculating dn, we must //be using flowValue and not flowValues? string rdn = flowValue.ToString(); ReferenceValue dn = ma.EscapeDNComponent(rdn); csentry.DN = dn; } else { try { if (flowValue != null) { csentry[csAttribName].Values.Add(flowValue); } else if (flowValues != null) { csentry[csAttribName].Values.Add(flowValues); } } catch (InvalidOperationException ex) { if (!ex.Message.Equals("attribute " + csAttribName + " is read-only", StringComparison.InvariantCultureIgnoreCase)) { throw; } else { //our anchor attribute is read only, set a temporary dn if (anchors.Contains(csAttribName)) { ReferenceValue dn = ma.EscapeDNComponent(Guid.NewGuid().ToString()); csentry.DN = dn; } } } } } } //do we want to throw an error now if any writeable anchor attributes have not been set?? //otherwise they will get one on export, we will leave it that way for now csentry.CommitNewConnector(); } } } }
public override void Generate(ConnectedMA ma, CSEntry csentry, MVEntry mventry, Rule rule) { Tracer.TraceInformation("enter-attributeflowattribute"); bool sourceIsMVObjectID = this.Source.Equals("[mvobjectid]", StringComparison.OrdinalIgnoreCase); bool targetIsDN = this.Target.Equals("[dn]", StringComparison.OrdinalIgnoreCase); AttributeType sourceType; AttributeType targetType; if (!sourceIsMVObjectID) { sourceType = mventry[this.Source].DataType; } else { sourceType = AttributeType.String; } if (!targetIsDN) { targetType = csentry[this.Target].DataType; } else { targetType = AttributeType.String; } if (sourceIsMVObjectID) { Tracer.TraceInformation("flow-source-value: '{0}'", mventry.ObjectID.ToString()); this.FlowMVObjectID(csentry, mventry, targetIsDN, targetType); return; } else { Tracer.TraceInformation("flow-source-value: '{0}'", mventry[this.Source].Value); } if (!mventry[this.Source].IsPresent) { return; } try { switch (sourceType) { case AttributeType.String: this.FlowStringAttribute(csentry, mventry, targetIsDN, targetType); break; case AttributeType.Integer: this.FlowIntegerAttribute(csentry, mventry, targetIsDN, targetType); break; case AttributeType.Reference: break; case AttributeType.Binary: this.FlowBinaryAttribute(csentry, mventry, targetIsDN, targetType); break; case AttributeType.Boolean: this.FlowBooleanAttribute(csentry, mventry, targetIsDN, targetType); break; default: break; } if (targetIsDN) { Tracer.TraceInformation("target-value: '{0}'", csentry.DN); } else { Tracer.TraceInformation("target-value: '{0}'", csentry[this.Target].Value); } } catch (Exception ex) { Tracer.TraceError("error {0}", ex.GetBaseException()); throw; } finally { Tracer.TraceInformation("exit-attributeflowattribute"); } }
void IMVSynchronization.Provision(MVEntry mventry) { switch (mventry.ObjectType.ToLower()) { //Person - MV Object type to scope provision of contoso users to the GALSync domain, as contact objects, under the "ExternalContacts" OU #region case "person": case "person": { bool bContactsConnected = false; // reset our boolean bool bProv = false; if (mventry["mail"].IsPresent) bProv = true; maContacts = mventry.ConnectedMAs["GALSync"]; //Declares MA to Provisions int iNumConnectorsContacts = maContacts.Connectors.Count; // count our connectors to this MA if (bProv) { if (iNumConnectorsContacts > 0) bContactsConnected = true; RDN = "CN=" + mventry["cn"].Value + ",OU=ExternalContacts" + ",DC=GALSync,DC=com"; targetDN = maContacts.CreateDN(RDN); //Created the CS DN if (!(bContactsConnected)) //If not found while iNumConnectorsContacts { CSEntry = maContacts.Connectors.StartNewConnector("contact"); //Starts a new connector CSEntry.DN = targetDN; //Sets the CS DN from targetDN CSEntry["targetAddress"].Value = mventry["mail"].Value; //flows mail attribute MV > CS CSEntry.CommitNewConnector(); //commits the connector to cs db } } break; } #endregion case "person" //GALSyncPerson - MV Obkect type to scope provision of external contacts from the GALSync.com domain to AD in Contoso under the "ExternalContacts" OU #region case "GalSyncPerson": case galsyncperson": { bool bContactsConnected = false; // reset our boolean bool bProv = false; if (mventry["mail"].IsPresent) bProv = true; maContacts = mventry.ConnectedMAs["AD MA"]; //Declares MA to Provisions int iNumConnectorsContacts = maContacts.Connectors.Count; // count our connectors to this MA if (bProv) { if (iNumConnectorsContacts > 0) bContactsConnected = true; RDN = "CN=" + mventry["cn"].Value + ",OU=ExternalContacts" + ",DC=Contoso,DC=com"; targetDN = maContacts.CreateDN(RDN); //Created the CS DN if (!(bContactsConnected)) //If not found while iNumConnectorsContacts { CSEntry = maContacts.Connectors.StartNewConnector("contact"); //Starts a new connector CSEntry.DN = targetDN; //Sets the CS DN from targetDN CSEntry["targetAddress"].Value = mventry["mail"].Value; //flows mail attribute MV > CS CSEntry.CommitNewConnector(); //commits the connector to cs db } } break; } #endregion case "GalSyncPerson" } }
public override void Generate(ConnectedMA ma, CSEntry csentry, MVEntry mventry, Rule rule) { Tracer.TraceInformation("enter-attributeflowconcatenate"); base.Generate(ma, csentry, mventry, rule); try { string concatValue = null; foreach (SourceExpressionBase sourceExpression in this.SourceExpressions) { if (sourceExpression.GetType() == typeof(SourceExpressionConstant)) { SourceExpressionConstant sourceExpr = (SourceExpressionConstant)sourceExpression; string replacedValue = sourceExpr.Source.ReplaceWithMVValueOrBlank(mventry); Tracer.TraceInformation("adding-constant-'{0}'", replacedValue); concatValue = concatValue + replacedValue; continue; } if (sourceExpression.GetType() == typeof(SourceExpressionRegexReplace)) { SourceExpressionRegexReplace sourceExpr = (SourceExpressionRegexReplace)sourceExpression; Tracer.TraceInformation("adding-regex-replacement-'{0}'", sourceExpr.Source); if (mventry[sourceExpr.Source].IsPresent) { concatValue = concatValue + Regex.Replace(mventry[sourceExpr.Source].Value, sourceExpr.Pattern, sourceExpr.Replacement); } else { Tracer.TraceError("attribute-'{0}'-is-not-present-in-metaverse", sourceExpr.Source); } continue; } if (sourceExpression.GetType() == typeof(SourceExpressionAttribute)) { SourceExpressionAttribute attr = (SourceExpressionAttribute)sourceExpression; if (mventry[attr.Source].IsPresent) { Tracer.TraceInformation("adding-value-from-MV::'{0}'-to-'{1}'", attr.Source, mventry[attr.Source].Value); concatValue = concatValue + mventry[attr.Source].Value.ToString(); } else { Tracer.TraceError("attribute-'{0}'-is-not-present-in-metaverse", attr.Source); } continue; } } Tracer.TraceInformation("flow-concatenated-attribute-value-'{0}'-to-'{1}'", concatValue, this.Target); if (this.Target.Equals("[DN]", StringComparison.OrdinalIgnoreCase)) { csentry.DN = csentry.MA.CreateDN(concatValue); } else { csentry[(this.Target)].Value = concatValue; } } catch (Exception ex) { Tracer.TraceError("error {0}", ex.GetBaseException()); throw; } finally { Tracer.TraceInformation("exit-attributeflowconcatenate"); } }
public void Provision(MVEntry mventry) { int i = 0; CSEntry MasterConnector = null; ConnectedMA MA = default(ConnectedMA); //LoggingCs.Log("Entering provisioning for " + mventry.ToString()); foreach (ConnectedMA ConnMA in mventry.ConnectedMAs) { //CSEntry csentry = default(CSEntry); foreach (CSEntry cseentry in ConnMA.Connectors) { if (cseentry.ConnectionRule == RuleType.Projection) { MasterConnector = cseentry; } } } // // For every MA, try to add a csentry, if there is not already one // for (i = 0; i <= galMAs.Length - 1; i++) { MA = mventry.ConnectedMAs[galMAs[i].MAName]; if (0 == MA.Connectors.Count) { // // If there were no connectors, then we are going to add one AddOrRenameConnector(ref MA, ref galMAs[i], mventry); } else if (1 == MA.Connectors.Count) { // // If there is one connector, // - if it is the master object connector then it is ok. // - if it is a replica object, then check for rename. // - if it is a join object outside the Synchronization // OU, then it is a problem, log it // CSEntry csentry = MA.Connectors.ByIndex[0]; if (IsInSynchronizationOU(csentry)) { AddOrRenameConnector(ref MA, ref galMAs[i], mventry, csentry); } else { if ((!object.ReferenceEquals(csentry, MasterConnector))) { // // This object has joined. // string LogString = "A contact for this object " + MasterConnector.ToString() + " called contact " + csentry.ToString() + " already exists in forest represented by MA " + MA.Name + ". If you would like to preserve this " + "contact and have us manage it, please " + "move the contact into Synchronization OU. " + "If you would like us to create " + "a new contact and manage it, " + "please delete this one."; //LoggingCs.Log(LogString); } } } else { // // We have more than one connectors undert the same MA, // print an error message. // CSEntry csentry = default(CSEntry); int index = 0; int countCsRemaining = 0; bool contactOutsideSyncOU = false; string LogString = "Multiple or outside-synchronizaiton-OU " + "connector(s) for the MV object " + MasterConnector.ToString() + "exist, they are: "; for (index = MA.Connectors.Count - 1; index >= 0; index += -1) { csentry = MA.Connectors.ByIndex[index]; if (csentry.ConnectionRule == RuleType.Provisioning) { //LoggingCs.Log("Disconnecting provisioned " + csentry.ToString() ); csentry.Deprovision(); } else { countCsRemaining = countCsRemaining + 1; LogString = LogString + csentry.ToString() + " lives in forest connected by " + MA.Name + " "; if (!IsInSynchronizationOU(csentry) && csentry.ObjectType == CONTACT) { contactOutsideSyncOU = true; } } } // // If we end up with more than one connector, or // any contact outside synchronization OU, // we want to log a warning message // if ((countCsRemaining > 1) || (true == contactOutsideSyncOU)) { LogString = LogString + ". Please refer to documentation " + "to resolve the conflict."; //LoggingCs.Log(LogString); } } } }
void ProvisionUPSA(MVEntry mventry, string MA_name) { var attr_map = new Dictionary <string, string>() { { "accountName", "AccountName" }, { "department", "Department" }, { "displayName", "UserName" }, { "mail", "WorkEmail" }, { "objectSid", "SID" }, { "lastName", "LastName" }, { "firstName", "FirstName" }, { "telephoneNumber", "WorkPhone" }, }; ConnectedMA ManagementAgent = mventry.ConnectedMAs[MA_name]; int Connectors = ManagementAgent.Connectors.Count; if (0 == Connectors && mventry.ObjectType.Equals("person", StringComparison.OrdinalIgnoreCase)) { if (mventry["accountName"].IsPresent) { string anchor = mventry["accountName"].Value; CSEntry csentry = ManagementAgent.Connectors.StartNewConnector("user"); AttributeNameEnumerator iter = mventry.GetEnumerator(); while (iter.MoveNext()) { string CS_AttrName; if (attr_map.TryGetValue(iter.Current, out CS_AttrName)) { csentry[CS_AttrName].Value = mventry[iter.Current].Value; } } csentry["Anchor"].Value = anchor; csentry.CommitNewConnector(); } } if (mventry.ObjectType.ToLower() == "group" && 0 == Connectors) { try { if (mventry["accountName"].IsPresent) { string anchor = mventry["accountName"].Value; CSEntry csentry = ManagementAgent.Connectors.StartNewConnector("group"); csentry["Anchor"].Value = anchor; csentry.CommitNewConnector(); } } catch (ObjectAlreadyExistsException) { // Suppress the exception when an object exists with same distinguished name in the connector space. // The object should join on the next inbound synchronization run } } if (mventry.ObjectType.ToLower() == "contact" && 0 == Connectors) { try { if (mventry["sAMAccountName"].IsPresent) { string anchor = mventry["sAMAccountName"].Value; CSEntry csentry = ManagementAgent.Connectors.StartNewConnector("contact"); csentry["Anchor"].Value = anchor; csentry.CommitNewConnector(); } } catch (ObjectAlreadyExistsException) { // Suppress the exception when an object exists with same distinguished name in the connector space. // The object should join on the next inbound synchronization run } } }
public virtual void Generate(ConnectedMA ma, CSEntry csentry, MVEntry mventry, Rule rule) { //intentionally left blank }
private void AddOrRenameConnector(ref ConnectedMA MA, ref GALMA MAConfig, MVEntry mventry, CSEntry csentry = null) { // // All objects are provisioned as contacts // string cn = null; int numberToAppend = 1; bool successful = false; bool extendedNameTried = false; string extendedName = null; string adminGroup = null; bool provisioningAdd = false; int cnLengthMax = 0; string validatedName = null; // // Add or Rename if only SynchronizationOU is defined // if ((MAConfig.SynchronizationOU == null) || MAConfig.SynchronizationOU.Equals("")) { return; } if (!mventry[COMMON_NAME].IsPresent || !mventry[MAIL_NICK_NAME].IsPresent || !mventry[TARGET_ADDRESS].IsPresent) { LogAndThrowUnexpectedDataException("Provisioning without cn, mailNickName or targetAddress"); } if (null == csentry) { provisioningAdd = true; } cn = mventry[COMMON_NAME].Value.ToString(); // // Active Directory does not distinguish CNs that differ only in use of diacritical marks (accents) etc. // whereas the sync service does. So force uniqueness by appending mailnickname to all CNs with extended // chars if doing so does not exceed CN max length. // IEnumerator cnEnum = cn.GetEnumerator(); while (cnEnum.MoveNext()) { if (Strings.AscW(cnEnum.Current.ToString()) > 127 && cn.Length + mventry[MAIL_NICK_NAME].Value.ToString().Length + 2 + RDN_TYPE.Length < AD_RDN_MAX_SIZE) { cn = cn + "(" + mventry[MAIL_NICK_NAME].Value.ToString() + ")"; break; // TODO: might not be correct. Was : Exit While } } do { try { // // Create a DN for the new object, need UPPER case "CN=..." // string rdn = RDN_TYPE + cn; ReferenceValue dn = MA.EscapeDNComponent(rdn).Concat(MAConfig.SynchronizationOU); if (rdn.Length > AD_RDN_MAX_SIZE + RDN_TYPE.Length) { LogAndThrowUnexpectedDataException("RDN too long: " + rdn); } if (csentry == null) { // // Try to add the object // //LoggingCs.Log("Adding " + dn.ToString()); csentry = ExchangeUtils.CreateMailEnabledContact(MA, dn, mventry[MAIL_NICK_NAME].Value.ToString(), mventry[TARGET_ADDRESS].Value.ToString()); adminGroup = GetAdminGroup(csentry); if ((adminGroup != null)) { // // LegacyExhangeDN = adminGroup/cn=mailnickname-guid // validatedName = ValidateLegacyExhangeDN(mventry[MAIL_NICK_NAME].Value.ToCharArray()); if ((validatedName == null)) { csentry[LEGACY_EXCHANGE_DN].Value = adminGroup + "/cn=" + System.Guid.NewGuid().ToString(); } else { csentry[LEGACY_EXCHANGE_DN].Value = adminGroup + "/cn=" + validatedName + "-" + System.Guid.NewGuid().ToString(); } } } else { // // Try to rename the object // if (!csentry.DN.Equals(dn)) { //LoggingCs.Log("Renaming " + dn.ToString()); csentry.DN = dn; } } successful = true; } catch (MissingParentObjectException ex) { // // Typically the admin has to perform a full/delta import // on the target CD, or disable provisioning until all // forests are imported. // //LoggingCs.Log("Target MA " + MA.Name + " is not imported yet. " + "Please disable provisioning until all forests " + "are imported."); throw ex; } catch (ObjectAlreadyExistsException ex) { // // If adding connector, throw away the instance to start over // if (provisioningAdd) { csentry = null; } // // There is a duplicate object in the target AD, // change the cn accordingly to avoid conflict. // if (!extendedNameTried) { extendedNameTried = true; try { if (mventry[DEPARTMENT].IsPresent) { extendedName = mventry[DEPARTMENT].Value; } } catch (NoSuchAttributeInObjectTypeException ex2) { } } cn = null; if (extendedName != null) { cn = mventry[COMMON_NAME].Value + " (" + extendedName + ")"; extendedName = null; if (cn.Length > AD_RDN_MAX_SIZE) { // // If too long, we'll try without it // cn = null; } } if (null == cn) { cn = mventry[COMMON_NAME].Value; // // To make sure that the number appended // will not be truncated. // The 2 spaces reserved is for "()" // cnLengthMax = AD_RDN_MAX_SIZE - (numberToAppend.ToString().Length + 2); // // If it's too long, we are going to truncate the // name and preserve the number appended. // if (cn.Length > cnLengthMax) { cn = cn.Substring(0, cnLengthMax); } cn = cn + "(" + numberToAppend.ToString() + ")"; numberToAppend = numberToAppend + 1; if (numberToAppend > RETRY_NUM_LIMIT) { LogAndThrowUnexpectedDataException("Retry for " + mventry[COMMON_NAME].Value + " exceeds limit " + numberToAppend.ToString()); } } } } while (!successful); }
public void Provision(MVEntry mventry) { Tracer.TraceInformation("enter-provision"); if (!this.EngineRules.ContainsKey(mventry.ObjectType)) { return; } try { HashSet <string> executedMAs = new HashSet <string>(StringComparer.OrdinalIgnoreCase); foreach (Rule rule in this.EngineRules[mventry.ObjectType]) { if (executedMAs.Contains(rule.TargetManagementAgentName)) { // skip rule as we have already executed something for this MA and connector continue; } Tracer.TraceInformation("start-rule '{0}' (MA: {1}, type: {2}, reference: {3})", rule.Name, rule.TargetManagementAgentName, rule.Type, rule.ExternalReferenceId); //Tracer.TraceInformation("{0}, displayname: {1}, mvguid: {2}", mventry.ObjectType, mventry["displayName"].IsPresent ? mventry["displayName"].Value : "n/a", mventry.ObjectID); Tracer.TraceInformation("{0}, mvguid: {1}", mventry.ObjectType, mventry.ObjectID); ConnectedMA ma = mventry.ConnectedMAs[rule.TargetManagementAgentName]; if (ma.Connectors.Count == 0) { // If we don't have any connectors, the only rule that can // apply is a provisioning rule if (rule.Action == RuleAction.Provision) { if (this.ConditionsApply(null, mventry, rule.Conditions)) { if (rule.Type == RuleType.Default) { this.CreateConnector(ma, mventry, rule); } else if (rule.Type == RuleType.External) { InvokeExternalMethod(rule.ExternalReferenceId, ExternalType.Provision, mventry, null); } // Don't need to process any more rules // as we have just newly provisioned executedMAs.Add(ma.Name); continue; } } else { // The rule isnt a provisioning rule, and there are no connectors // so there is nothing to do - skip to the next rule continue; } } else { // There is at least one connector, so lets see if we should // re-provision, deprovision, rename, or deprovision all if (rule.Action == RuleAction.Rename) { bool hasRenamed = false; foreach (CSEntry renameCandidate in ma.Connectors) { if (this.ConditionsApply(renameCandidate, mventry, rule.ConditionalRename.Conditions)) { if (rule.Type == RuleType.Default) { this.ConditionalRenameConnector(ma, renameCandidate, mventry, rule); } else if (rule.Type == RuleType.External) { InvokeExternalMethod(rule.ExternalReferenceId, ExternalType.Provision, mventry, null); } hasRenamed = true; } } if (hasRenamed) { executedMAs.Add(ma.Name); continue; } } else if (rule.Action == RuleAction.Provision) { // We already have a connector, so check if we need to re-provision if ((rule.Reprovision != null) && (rule.Reprovision.ReprovisionEnabled)) { Tracer.TraceInformation("check-reprovisioning-conditions"); if (rule.Reprovision.Conditions == null) { continue; } bool hasReproved = false; foreach (CSEntry reprovCandidate in ma.Connectors.OfType <CSEntry>().ToList()) { if (rule.Reprovision.Conditions.Met(mventry, reprovCandidate)) { if (rule.Type == RuleType.Default) { Tracer.TraceInformation("Reprovisioning '{0}' using rule id '{1}'", reprovCandidate.DN, rule); this.DeprovisionConnector(ma, reprovCandidate, mventry, rule); this.CreateConnector(ma, mventry, rule); } else if (rule.Type == RuleType.External) { InvokeExternalMethod(rule.ExternalReferenceId, ExternalType.Provision, mventry, null); } hasReproved = true; } } if (hasReproved) { executedMAs.Add(ma.Name); continue; } } } else if (rule.Action == RuleAction.Deprovision) { bool hasDeleted = false; foreach (CSEntry deprovCandidate in ma.Connectors.OfType <CSEntry>().ToList()) { if (!this.ConditionsApply(deprovCandidate, mventry, rule.Conditions)) { continue; } if (rule.Type == RuleType.Default) { this.DeprovisionConnector(ma, deprovCandidate, mventry, rule); } else if (rule.Type == RuleType.External) { InvokeExternalMethod(rule.ExternalReferenceId, ExternalType.Provision, mventry, null); } hasDeleted = true; } if (hasDeleted) { executedMAs.Add(ma.Name); continue; } } else if (rule.Action == RuleAction.DeprovisionAll) { foreach (CSEntry deprovCandidate in ma.Connectors.OfType <CSEntry>().ToList()) { if (!this.ConditionsApply(deprovCandidate, mventry, rule.Conditions)) { continue; } if (rule.Type == RuleType.Default) { mventry.ConnectedMAs.DeprovisionAll(); } else if (rule.Type == RuleType.External) { InvokeExternalMethod(rule.ExternalReferenceId, ExternalType.Provision, mventry, null); } break; } } else { Tracer.TraceError("invalid-action-specified {0}", rule.Action); } } Tracer.TraceInformation("end-rule {0}", rule.Name); } } catch (Exception ex) { Tracer.TraceError("error {0}", ex.GetBaseException()); throw; } finally { Tracer.TraceInformation("exit-provision"); } }