public Schema GetSchema(System.Collections.ObjectModel.KeyedCollection <string, ConfigParameter> configParameters) { Schema schema = Schema.Create(); Microsoft.MetadirectoryServices.SchemaType type; //we want to fetch schema for all MAs, that way configuration wont get lost if an item is //unselected, and the checkbox can become simply an activate/deactivate switch DataSet mas = FIMConfiguration.GetManagementAgents(null); foreach (DataRow ma in mas.Tables["Config"].Rows) { string maName = ma["ma_name"].ToString(); string maType = ma["ma_type"].ToString(); string maList = ma["ma_listname"].ToString(); if (maType.Equals("FIM", StringComparison.InvariantCultureIgnoreCase) || maList.Equals("Provisioning Management Agent (Insight)", StringComparison.InvariantCultureIgnoreCase)) { continue; } //create a new schema type based on the ma type = Microsoft.MetadirectoryServices.SchemaType.Create(maName, false); //add a generic Anchor Attribute to allow user to add flows for the actual anchor type.Attributes.Add(SchemaAttribute.CreateAnchorAttribute("Anchor", AttributeType.String)); //we must preface each attribute with the MA name to make it unique across the schema allowing for //an attribute in two different MAs with different data types, etc. //our data will come back as XML data, we will need to parse it for what we need XmlDocument xmldoc = FIMConfiguration.GetConfigXML(maName, "ma_schema_xml"); XmlNamespaceManager xmlnsManager = new XmlNamespaceManager(xmldoc.NameTable); xmlnsManager.AddNamespace("dsml", "http://www.dsml.org/DSML"); xmlnsManager.AddNamespace("ms-dsml", "http://www.microsoft.com/MMS/DSML"); XmlNodeList attributes = xmldoc.SelectNodes("//dsml:directory-schema/dsml:attribute-type", xmlnsManager); //add each attribute found to the schema foreach (XmlNode attrib in attributes) { string oid = attrib.SelectSingleNode("./dsml:syntax", xmlnsManager).InnerText; type.Attributes.Add(SchemaAttribute.CreateSingleValuedAttribute(maName + " - " + attrib.Attributes["id"].Value, FIMConfiguration.GetDataType(oid))); } schema.Types.Add(type); } return(schema); }
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 System.Collections.Generic.IList <ConfigParameterDefinition> GetConfigParameters(System.Collections.ObjectModel.KeyedCollection <string, ConfigParameter> configParameters, ConfigParameterPage page) { List <ConfigParameterDefinition> configParametersDefinitions = new List <ConfigParameterDefinition>(); switch (page) { case ConfigParameterPage.Connectivity: //we have to configure the MAs being seletected in the Connectivity page so that the information //will be available to us when fetching the schema for the items selected configParametersDefinitions.Add(ConfigParameterDefinition.CreateLabelParameter("Enable provisioning for the following types:")); //look up MAs and list them as check boxes for provisioning enablement DataSet mas = FIMConfiguration.GetManagementAgents(null); foreach (DataRow ma in mas.Tables["Config"].Rows) { string maName = ma["ma_name"].ToString(); string maType = ma["ma_type"].ToString(); string maList = ma["ma_listname"].ToString(); if (maType.Equals("FIM", StringComparison.InvariantCultureIgnoreCase) || maList.Equals("Provisioning Management Agent (Insight)", StringComparison.InvariantCultureIgnoreCase)) { continue; } //our data will come back as XML data, we will need to parse it for what we need XmlDocument xmldoc = FIMConfiguration.GetConfigXML(maName, "ma_schema_xml"); XmlNamespaceManager xmlnsManager = new XmlNamespaceManager(xmldoc.NameTable); xmlnsManager.AddNamespace("dsml", "http://www.dsml.org/DSML"); xmlnsManager.AddNamespace("ms-dsml", "http://www.microsoft.com/MMS/DSML"); //TODO: what happens when a sql column defines the object type? XmlNodeList objectTypes = xmldoc.SelectNodes("//dsml:directory-schema/dsml:class", xmlnsManager); foreach (XmlNode ot in objectTypes) { //add the object type as a selection ConfigParameterDefinition conf = ConfigParameterDefinition.CreateCheckBoxParameter(maName + " - " + ot.Attributes["id"].Value.Replace(" - ", " _ ")); configParametersDefinitions.Add(conf); } //TODO: what happens to the UI when we have a alot of entries? configParametersDefinitions.Add(ConfigParameterDefinition.CreateDividerParameter()); } break; case ConfigParameterPage.Global: break; case ConfigParameterPage.Partition: break; case ConfigParameterPage.RunStep: break; } return(configParametersDefinitions); }