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"); } }
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"); } }
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(); } } } }
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); }