예제 #1
0
        /// <summary>
        /// Finds all Auxiliary classes.
        /// </summary>
        /// <param name="requiredObject">The required object.</param>
        /// <param name="isFirstTime">Whether is it the first time.</param>
        /// <param name="dcModel">The domain controller of model.</param>
        /// <returns>Returns a list of auxiliary classes.</returns>
        public List <string> GetAuxiliaryClassesList(ModelObject requiredObject, bool isFirstTime, ModelDomainController dcModel)
        {
            List <string> superClasses;

            //If it is first time, initialize all variables.
            if (isFirstTime)
            {
                auxiliaryClassLsit  = new List <string>();
                seenAuxiliarClasses = new List <string>();
            }
            //Collect all systemauxiliaryclass of this object.
            if (requiredObject.attributes.Keys.Contains("systemauxiliaryclass"))
            {
                foreach (string element in requiredObject.attributes["systemauxiliaryclass"].UnderlyingValues)
                {
                    auxiliaryClassLsit.Add(element);
                }
            }
            //Collect all auxiliaryclass of this object.
            if (requiredObject.attributes.Keys.Contains("auxiliaryclass"))
            {
                foreach (string element in requiredObject.attributes["auxiliaryclass"].UnderlyingValues)
                {
                    auxiliaryClassLsit.Add(element);
                }
            }
            //For auxiliary classes,
            if (auxiliaryClassLsit.Count != 0)
            {
                List <string> tempAuxiliaryClassLsit = new List <string>();
                foreach (string element in auxiliaryClassLsit)
                {
                    tempAuxiliaryClassLsit.Add(element);
                }

                //For all auxiliary classes, find out their auxiliaryClass and systemAuxiliaryClass values.
                foreach (string auxClass in tempAuxiliaryClassLsit)
                {
                    //If already we did not find the auxiliary and systemAuxiliary class for this class continue.
                    if (!seenAuxiliarClasses.Contains(auxClass.ToLower()))
                    {
                        //Add this auxClass name in seenAuxiliarClasses.
                        seenAuxiliarClasses.Add(auxClass.ToLower());

                        //Find this object in server.
                        ModelObject auxClassOfObject;
                        string      className = auxClass.Replace("-", String.Empty).ToLower();
                        if (dcModel.TryGetClass(className, out auxClassOfObject))
                        {
                            //Call AuxiliaryClasses method for this auxClass.
                            GetAuxiliaryClassesList(auxClassOfObject, false, dcModel);
                        }
                    }
                }
            }

            //Find superClasses of this object.
            superClasses = GetSuperClassesList(requiredObject, true, dcModel);
            //For each super class,
            foreach (string supClass in superClasses)
            {
                //If already we did not find the auxiliary and systemAuxiliary class for this class continue.
                if (!seenAuxiliarClasses.Contains(supClass.ToLower()))
                {
                    //Add this supClass name in seenAuxiliarClasses.
                    seenAuxiliarClasses.Add(supClass.ToLower());
                    //Find this object from server.
                    ModelObject supClassOfObject = null;
                    string      className        = supClass.Replace("-", String.Empty).ToLower();

                    dcModel.TryGetClass(className, out supClassOfObject);
                    //Remove the minus sign and retry
                    if (supClassOfObject == null)
                    {   //Modified to support Windows Server 2012
                        //Only class names in the format of, eg. msds-claimtype, can be found
                        if (className.Contains("msds"))
                        {
                            className = className.Insert(className.IndexOf("msds") + 4, "-");
                        }
                        else if (supClass.Contains("-"))
                        {
                            className = supClass.Remove(supClass.IndexOf('-'), 1);
                        }
                        dcModel.TryGetClass(className, out supClassOfObject);
                    }

                    //Call AuxiliaryClasses method for this supClass object.
                    GetAuxiliaryClassesList(supClassOfObject, false, dcModel);
                }
            }
            //Finally return auxiliary class list.
            return(auxiliaryClassLsit);
        }
 /// <summary>
 /// An internal attribute for a shorter version of the DN, leaving out the DC name.
 /// </summary>
 /// <param name="obj">A sequence of ModelObject.</param>
 /// <returns>Value of short name.</returns>
 public static Value ShortName(ModelObject obj)
 {
     return(new Value(Syntax.StringUnicode, ComputeName(StandardNames.shortName, obj)));
 }
예제 #3
0
        /// <summary>
        /// This method validates the requirements under
        /// LDSConsistencyRules Scenario.
        /// </summary>
        public void ValidateLDSConsistencyRules()
        {
            #region MS-ADTS-Schema_R73

            //The objectClass attribute of the attributeSchema equals the sequence [top, attributeSchema ]
            //Expected Sequence setting...
            List <object>  actualSeq        = new List <object>();
            List <object>  expectedSeq      = new List <object>();
            ModelObject    objectFromModel  = null;
            string         requiredObjectDN = String.Empty;
            DirectoryEntry serverObject;
            expectedSeq.Add("top".ToLower());
            expectedSeq.Add("classSchema".ToLower());

            //Get attributeSchema from Server.
            requiredObjectDN = "CN=Attribute-Schema,CN=Schema,CN=Configuration," + adAdapter.LDSRootObjectName;
            if (!adAdapter.GetLdsObjectByDN(requiredObjectDN, out serverObject))
            {
                DataSchemaSite.Assume.IsTrue(false, requiredObjectDN + " Object is not found in server");
            }
            actualSeq = new List <object>();
            foreach (string valueString in serverObject.Properties[StandardNames.objectClass.ToLower()])
            {
                actualSeq.Add(valueString.ToLower());
            }
            //MS-ADTS-Schema_R73.
            CollectionAssert.AreEquivalent(
                expectedSeq,
                actualSeq,
                "The objectClass attribute of the attributeSchema equals the sequence [top, classSchema ]. MS-ADTS-Schema_R73");
            #endregion

            #region MS-ADTS-Schema_R157
            //The objectClass attribute of the classSchema equals the sequence [top, classSchema ].
            //Expected Sequence setting...
            expectedSeq = new List <object>();
            expectedSeq.Add("top".ToLower());
            expectedSeq.Add("classSchema".ToLower());

            //Get classSchema from Server.
            requiredObjectDN = "CN=Class-Schema,CN=Schema,CN=Configuration," + adAdapter.LDSRootObjectName;
            if (!adAdapter.GetLdsObjectByDN(requiredObjectDN, out serverObject))
            {
                DataSchemaSite.Assume.IsTrue(false, requiredObjectDN + " Object is not found in server");
            }
            actualSeq = new List <object>();
            foreach (string valueString in serverObject.Properties[StandardNames.objectClass.ToLower()])
            {
                actualSeq.Add(valueString.ToLower());
            }

            //MS-ADTS-Schema_R157.
            CollectionAssert.AreEquivalent(
                expectedSeq,
                actualSeq,
                "The objectClass attribute of the classSchema equals the sequence [top, classSchema ]. MS-ADTS-Schema_R157");

            #endregion

            #region MS-ADTS-Schema_R169

            //The subClassOf attribute of the classSchema Specifies governsID of the superclass of the class.
            //Get classSchema from Model.
            objectFromModel = adamModel.GetClass("classSchema");
            if (objectFromModel == null)
            {
                DataSchemaSite.Assume.IsNotNull(objectFromModel, "Class classSchema is not existing in Model");
            }
            string expectedValue = (string)objectFromModel[StandardNames.subClassOf].UnderlyingValues.ToArray()[0];

            #endregion

            #region MS-ADTS-Schema_R129-142,179

            //Inheritance requirements
            IEnumerable <IObjectOnServer> serverObjects = (IEnumerable <IObjectOnServer>)adAdapter.GetAllLdsSchemaClasses();
            if (serverObjects == null)
            {
                DataSchemaSite.Assume.IsNotNull(serverObjects, "Class objects are not existing in Model");
            }

            //This method will validate the requirements MS-ADTS-Schema_R129-142,179
            ValidateInheritanceRequirements(serverObjects, false);

            serverObjects = null;

            #endregion

            #region MS-ADTS-Schema_R143-146

            //Covering ObjectClass requirements
            //Get domain NC for validation.
            DirectoryEntry domainEntry;
            if (!adAdapter.GetLdsObjectByDN("CN=Configuration," + adAdapter.LDSRootObjectName, out domainEntry))
            {
                DataSchemaSite.Assume.IsTrue(
                    false,
                    "CN=Configuration,"
                    + adAdapter.LDSRootObjectName
                    + " Object is not found in server");
            }

            //This method validates teh requirements MS-ADTS-Schema_R143-146
            ValidateObjectClassRequirements(domainEntry.Children, false);
            domainEntry = null;

            #endregion

            #region MS-ADTS-Schema_R149,175

            //Coverring StructureRule requirements
            serverObjects = adAdapter.GetAllLdsSchemaClasses();
            if (serverObjects == null)
            {
                DataSchemaSite.Assume.IsNotNull(serverObjects, "Class objects are not existing in Model");
            }

            //This method validates the requirements MS-ADTS-Schema_R149,175
            ValidateStructureRulesRequirements(serverObjects, false);

            #endregion

            #region MS-ADTS-Schema_R152,153
            //Covering ContentRule requirements

            //Get the domain NC objects.
            if (!adAdapter.GetLdsObjectByDN("CN=Configuration," + adAdapter.LDSRootObjectName, out domainEntry))
            {
                DataSchemaSite.Assert.IsTrue(false, "Configuration Object is not found in server");
            }

            //This method validates the requirements MS-ADTS-Schema_R152,153.
            ValidateContentRulesRequirements(domainEntry.Children, serverObjects);

            #endregion

            #region MS-ADTS-Schema_R177
            //The systemAuxiliaryClass attribute of the classSchema Specifies governsIDs of the classes that can
            //be parents of the class within an NC tree, where the parent-child relationships are required for
            //system operation.

            DirectoryEntry classSchemaObj;
            bool           isAuxiliary         = false;
            List <string>  auxiliaryClassValue = new List <string>();

            //Get class-schema class from server.
            if (!adAdapter.GetLdsObjectByDN(
                    "CN=Class-Schema,CN=Schema,CN=Configuration," + adAdapter.LDSRootObjectName,
                    out classSchemaObj))
            {
                DataSchemaSite.Assume.IsTrue(
                    false,
                    "CN=Class-Schema,CN=Schema,CN=Configuration,"
                    + adAdapter.rootDomainDN
                    + " Object is not found in server");
            }

            //Collect its auxiliary class value.
            if (classSchemaObj.Properties.Contains("auxiliaryclass"))
            {
                //auxiliaryClassValue.Add
                foreach (string value in classSchemaObj.Properties["auxiliaryclass"])
                {
                    auxiliaryClassValue.Add(value);
                }
            }

            //Collect its system auxiliary class value.
            if (classSchemaObj.Properties.Contains("systemauxiliaryclass"))
            {
                //AuxiliaryClassValue.Add
                foreach (string value in classSchemaObj.Properties["systemauxiliaryclass"])
                {
                    auxiliaryClassValue.Add(value);
                }
            }

            if (auxiliaryClassValue.Count != 0)
            {
                //For each auxiliary class...
                foreach (string auxClass in auxiliaryClassValue)
                {
                    isAuxiliary = false;
                    foreach (IObjectOnServer serverObj in serverObjects)
                    {
                        //Get it from server.
                        if (serverObj.Name.Equals(auxClass))
                        {
                            //Get server object governsID.
                            string governsID = (string)serverObj.Properties[StandardNames.governsId.ToLower()][0];

                            //It should be eqal to the auxiliary class name of the class.
                            if (governsID.Equals(auxClass))
                            {
                                isAuxiliary = true;
                                continue;
                            }
                        }
                    }
                    if (isAuxiliary)
                    {
                        continue;
                    }
                    else
                    {
                        break;
                    }
                }
            }

            #endregion
        }
 /// <summary>
 /// Computes the distinguished name of an object.
 /// </summary>
 /// <param name="obj">A sequence of ModelObject.</param>
 /// <returns>Value of distinguised name.</returns>
 public static Value DistinguishedName(ModelObject obj)
 {
     return(new Value(Syntax.StringUnicode, ComputeName(StandardNames.distinguishedName, obj)));
 }
        /// <summary>
        /// This method is used to get the possible inferiors of the particula object.
        /// </summary>
        /// <param name="ldapDisplayName">LDAP display name of the particular object.</param>
        /// <param name="dcModel">System Model object</param>
        /// <returns>On success it returns the List of allowed attributes, else null.</returns>
        public static List <string> GetPossibleInferiors(string ldapDisplayName, ModelDomainController dcModel)
        {
            List <string> testPossInferiors = new List <string>();
            ModelObject   reqEntry          = null;

            //Get the model object corresponding to ldapDisplayName passed to this method.
            while (reqEntry == null)
            {
                dcModel.TryGetClass(ldapDisplayName, out reqEntry);
            }


            //First condition, take all entries in SchemaNC.
            IDictionary <string, ModelObject> allSchemaEntries = dcModel.schemaReplica.root.childs;

            foreach (KeyValuePair <string, ModelObject> schemaEntry in allSchemaEntries)
            {
                ModelObject entry = schemaEntry.Value;
                testPossInferiors.Add((string)entry.attributes["ldapdisplayname"].UnderlyingValues.ElementAt(0));
            }

            //Get required entry's class name.
            string className = (string)reqEntry.attributes["ldapdisplayname"].UnderlyingValues.ElementAt(0);

            //All Conditions
            foreach (KeyValuePair <string, ModelObject> schemaEntry in allSchemaEntries)
            {
                ModelObject entry        = schemaEntry.Value;
                string      tempLdapName = (string)entry.attributes["ldapdisplayname"].UnderlyingValues.ElementAt(0);

                #region 2. objectClass value must be classSchema.

                object[] objectClassValues   = entry.attributes["objectclass"].UnderlyingValues.ToArray();
                string   structuralClassName = (string)objectClassValues[objectClassValues.Length - 1];

                if (!structuralClassName.ToLower().Equals("classschema"))
                {
                    if (testPossInferiors.Contains(tempLdapName))
                    {
                        testPossInferiors.Remove(tempLdapName);
                        continue;
                    }
                }
                #endregion

                #region 3. entry must not systemOnly.

                if (entry.attributes.Keys.Contains("systemonly"))
                {
                    bool isSystemOnly = (bool)entry.attributes["systemonly"].UnderlyingValues.ElementAt(0);

                    if (isSystemOnly)
                    {
                        if (testPossInferiors.Contains(tempLdapName))
                        {
                            testPossInferiors.Remove(tempLdapName);
                            continue;
                        }
                    }
                }

                #endregion

                #region 4. objectClassCategory must not be 2 or 3.
                if (entry.attributes.Keys.Contains("objectclasscategory"))
                {
                    int value = (int)entry.attributes["objectclasscategory"].UnderlyingValues.ElementAt(0);

                    if (value == 2 || value == 3)
                    {
                        if (testPossInferiors.Contains(tempLdapName))
                        {
                            testPossInferiors.Remove(tempLdapName);
                            continue;
                        }
                    }
                }

                #endregion

                #region 5. entry's class name must be in POSSSUPERIORS(allSchemaNCObjects).

                if (entry.attributes.Keys.Contains("governsid"))
                {
                    ConstructedAttributeHelper helper = new ConstructedAttributeHelper();
                    helper.possSuperiorList = new List <string>();
                    //helper.AuxiliaryClasses(entry, true, dcModel);
                    List <string> possSuperiors = helper.GetPossSuperiorsList(entry, dcModel);

                    if (possSuperiors.Contains(className.ToLower()))
                    {
                        continue;
                    }
                    else
                    {
                        if (testPossInferiors.Contains(tempLdapName))
                        {
                            testPossInferiors.Remove(tempLdapName);
                        }
                        continue;
                    }
                }
                #endregion
            }
            return(testPossInferiors);
        }
        /// <summary>
        /// If it is a structural object class, then the objectClass attribute of objects of the class does not contain
        /// the name of the auxiliary class aux.
        /// </summary>
        /// <param name="obj">The object of model.</param>
        public static void CheckStructure(ModelObject obj)
        {
            //Collect possSuperiors.
            List <object> possSuperiors = new List <object>();
            //Get current class name.
            string className = obj[StandardNames.ldapDisplayName].UnderlyingValues.ElementAt(0).ToString();
            //Get super class list.
            List <string> superClassList = GetSuperClassList(obj.dc, className);

            //For each super class
            foreach (string superClass in superClassList)
            {
                //Get class object of this class name.
                ModelObject classObject = obj.dc.GetClass(superClass);

                //Get possSuperiors.
                if (classObject[StandardNames.possSuperiors] != null)
                {
                    possSuperiors.AddRange(classObject[StandardNames.possSuperiors].UnderlyingValues);
                }

                //Get systemPossSuperiors.
                if (classObject[StandardNames.systemPossSuperiors] != null)
                {
                    possSuperiors.AddRange(classObject[StandardNames.systemPossSuperiors].UnderlyingValues);
                }
            }

            //For each poss superior class name...
            foreach (string possSuperior in possSuperiors)
            {
                #region two

                //Get the poss superior object and possibleInferiors attribute.
                ModelObject superiorObj = obj.dc.GetClass(possSuperior);
                ModelObject attrObject  = superiorObj.dc.GetAttribute(StandardNames.possibleInferiors);

                if (superiorObj != null)
                {
                    AttributeContext parsingContext = obj.dc.GetAttributeContext(StandardNames.possibleInferiors);

                    //If this class alrady contains the possibleInferiors...
                    if (superiorObj[StandardNames.possibleInferiors] != null)
                    {
                        string valueString = String.Empty;
                        foreach (object val in superiorObj[StandardNames.possibleInferiors].UnderlyingValues)
                        {
                            valueString = valueString + val.ToString() + ";";
                        }

                        //Append the current class name with already existing possibleInferiors attribute.
                        valueString = valueString + className;
                        superiorObj[StandardNames.possibleInferiors] = parsingContext.Parse(valueString);
                    }
                    else
                    {
                        //Create a new possibleInferiors attribute with the cureent class name.
                        superiorObj[StandardNames.possibleInferiors] = parsingContext.Parse(className);
                    }
                }
                else
                {
                    Checks.Fail(
                        "{0} class's possSuperior {1} is not in Schema NC.",
                        className,
                        superiorObj.attributes[StandardNames.cn].UnderlyingValues.ElementAt(0).ToString());
                }

                #endregion
            }
        }
        /// <summary>
        /// This method is used to get allowed attributes of a particular object.
        /// </summary>
        /// <param name="ldapDisplayName">LDAP display name of the particular object.</param>
        /// <param name="dcModel">System Model object</param>
        /// <returns>On success it returns the List of allowed attributes, else null.</returns>
        public static List <string> GetAllowedAttributes(string ldapDisplayName, ModelDomainController dcModel)
        {
            List <string>      testAllowedAttributes     = new List <string>();
            List <ModelObject> reqEntryObjectClassValues = new List <ModelObject>();
            ModelObject        reqEntry = null;

            //Get the model object corresponding to ldapDisplayName passed to this method.
            while (reqEntry == null)
            {
                dcModel.TryGetClass(ldapDisplayName, out reqEntry);
                if (reqEntry == null)
                {
                    dcModel.TryGetAttribute(ldapDisplayName, out reqEntry);
                }
            }

            if (reqEntry.attributes.Keys.Contains("objectclass"))
            {
                foreach (string value in reqEntry.attributes["objectclass"].UnderlyingValues)
                {
                    ModelObject tempObject = null;

                    while (tempObject == null)
                    {
                        dcModel.TryGetClass(value, out tempObject);
                    }
                    reqEntryObjectClassValues.Add(tempObject);
                }
            }

            //First condition, take all entries in SchemaNC.
            IDictionary <string, ModelObject> allSchemaEntries = dcModel.schemaReplica.root.childs;

            foreach (KeyValuePair <string, ModelObject> schemaEntry in allSchemaEntries)
            {
                ModelObject entry = schemaEntry.Value;

                testAllowedAttributes.Add((string)entry.attributes["ldapdisplayname"].UnderlyingValues.ElementAt(0));
            }



            //All Conditions
            foreach (KeyValuePair <string, ModelObject> schemaEntry in allSchemaEntries)
            {
                ModelObject entry        = schemaEntry.Value;
                string      tempLdapName = (string)entry.attributes["ldapdisplayname"].UnderlyingValues.ElementAt(0);

                #region 2. objectClass value must be attributeSchema.

                object[] objectClassValues   = entry.attributes["objectclass"].UnderlyingValues.ToArray();
                string   structuralClassName = (string)objectClassValues[objectClassValues.Length - 1];

                if (!structuralClassName.ToLower().Equals("attributeschema"))
                {
                    if (testAllowedAttributes.Contains(tempLdapName))
                    {
                        testAllowedAttributes.Remove(tempLdapName);
                        continue;
                    }
                }
                #endregion

                #region 3. Link id is even or it should not be present

                #endregion

                #region 4. SystemFlag bit 0X4 should not be set.

                #endregion

                #region 5. there exists C in TO!objectClass such that O is in CLASSATTS(C)).

                ConstructedAttributeHelper helper = new ConstructedAttributeHelper();
                bool isExist = true;

                foreach (ModelObject classObj in reqEntryObjectClassValues)
                {
                    helper.classAttributesList = new List <string>();
                    List <string> attributeList = helper.ClassAttributes(classObj, dcModel);
                    if (attributeList.Contains(tempLdapName.ToLower()))
                    {
                        isExist = true;
                        break;
                    }
                    else
                    {
                        isExist = false;
                    }
                }
                if (!isExist && testAllowedAttributes.Contains(tempLdapName))
                {
                    testAllowedAttributes.Remove(tempLdapName);
                }

                #endregion
            }

            return(testAllowedAttributes);
        }
 /// <summary>
 /// Determines match of object against filter.
 /// </summary>
 /// <param name="obj">The object of model.</param>
 /// <returns>Returns whether match of object against filter.</returns>
 public abstract bool Match(ModelObject obj);
 /// <summary>
 /// Justify whether the object matches the present attribute.
 /// </summary>
 /// <param name="obj">The object of model.</param>
 /// <returns>Returns true if the object matches.</returns>
 public override bool Match(ModelObject obj)
 {
     return(obj[attributePresence] != null);
 }
예제 #10
0
        /// <summary>
        /// CompareObjects method is used to compare the objects from server and the model.
        /// </summary>
        /// <param name="modelObject">Model Object</param>
        /// <param name="serverObject">Server Object</param>
        /// <param name="hasErrors">Error tracking variable</param>
        /// <returns>Void</returns>
        void CompareObjects(ModelObject modelObject, IObjectOnServer serverObject, ref bool hasErrors)
        {
            foreach (string attr in modelObject.attributes.Keys)
            {
                //SDs for DomainDNS and SamDomain differ because of an ACE that is added during DCPromo using the expanded binary SID instead of its string representation of “RO” to maintain compatibility with downlevel OS’s.
                //Because of this, the SDs represented in the TD will be logically consistent with the SD in the server but will never be 100% identical.
                if ((attr == "defaultsecuritydescriptor") &&
                    ((serverObject.Name == "domainDNS") ||
                     (serverObject.Name == "msSPP-ActivationObject") ||
                     (serverObject.Name == "msSPP-ActivationObjectsContainer") ||
                     (serverObject.Name == "samDomain")))
                {
                    continue;
                }

                //skip possibleinferiors temporarily since the calculation of possibleinferiors seems wrong
                if (attr == "possibleinferiors")
                {
                    continue;
                }

                Value value = modelObject[attr];
                if (!serverObject.Properties.ContainsKey(attr))
                {
                    DataSchemaSite.Log.Add(LogEntryKind.Warning, "attribute '{0}' must be in server object '{1}'", attr, serverObject.Name);
                    hasErrors = true;
                    //TDI 67172 is identified as a product bug and will be fixed in Blue+1
                    if (!adAdapter.TDI67172Fixed)
                    {
                        if ((serverObject.Name == "msDS-GeoCoordinatesAltitude") ||
                            (serverObject.Name == "msDS-GeoCoordinatesLatitude") ||
                            (serverObject.Name == "msDS-GeoCoordinatesLongitude"))
                        {
                            hasErrors = false;
                        }
                    }
                    continue;
                }
                AttributeContext context;
                if (!dcModel.TryGetAttributeContext(attr, out context))
                {
                    // Inconsistency should be already reported
                    continue;
                }

                //Remove the line break in the value of defaultsecuritydescriptor and defaultobjectcategory
                if ((attr == "defaultsecuritydescriptor") ||
                    (attr == "defaultobjectcategory"))
                {
                    value = new Value(context.syntax, value.UnderlyingValues[0].ToString().Replace("\r", String.Empty));
                }
                Value serverValue = new Value(context.syntax, serverObject.Properties[attr]);
                if (!context.Equals(value, serverValue))
                {
                    if (modelObject[StandardNames.attributeID] != null)
                    {
                        DataSchemaSite.Log.Add(
                            LogEntryKind.Warning,
                            "In Attribute {4} attribute '{0}' (syntax {3}) has different value '{1}' on server than in model '{2}'",
                            attr,
                            context.Unparse(serverValue),
                            context.Unparse(value),
                            context.syntax.Name,
                            modelObject[StandardNames.cn]);
                    }
                    else
                    {
                        DataSchemaSite.Log.Add(
                            LogEntryKind.Warning,
                            "In Class {4} attribute '{0}' (syntax {3}) has different value '{1}' on server than in model '{2}'",
                            attr,
                            context.Unparse(serverValue),
                            context.Unparse(value),
                            context.syntax.Name,
                            modelObject[StandardNames.cn]);
                    }
                    hasErrors = true;
                }
            }
        }
 /// <summary>
 /// Mathc method.
 /// </summary>
 /// <param name="obj">The second value.</param>
 /// <returns>On success it returns true.</returns>
 public override bool Match(ModelObject obj)
 {
     return(!operandsNot.Match(obj));
 }
        /// <summary>
        /// Content rules determine the mandatory and optional attributes of the class instances that are stored
        /// in the directory.
        /// </summary>
        /// <param name="obj">The object of model.</param>
        public static void CheckContent(ModelObject obj)
        {
            List <string> mustContain = new List <string>();
            List <string> mayContain  = new List <string>();

            string[] ExcludeAttributes = { "instancetype", "ntsecuritydescriptor", "objectcategory", "objectsid" };
            // Compute sets of may/must attribute
            string        className      = (string)obj[StandardNames.objectClass].UnderlyingValues.Last();
            List <string> superClassList = GetSuperClassList(obj.dc, className);

            foreach (string classId in superClassList)
            {
                ModelObject classObj;
                if (!obj.dc.TryGetClass(classId, out classObj))
                {
                    // will be reported in a different checker
                    continue;
                }
                mustContain.AddRange(GetAttributeSet(classObj, StandardNames.mustContain));
                mustContain.AddRange(GetAttributeSet(classObj, StandardNames.systemMustContain));
                mayContain.AddRange(GetAttributeSet(classObj, StandardNames.mayContain));
                mayContain.AddRange(GetAttributeSet(classObj, StandardNames.systemMayContain));
            }

            //Removing default excluded attributes from this list.
            foreach (string attr in ExcludeAttributes)
            {
                if (mustContain.Contains(attr))
                {
                    mustContain.Remove(attr);
                }
            }
            // Check for all attributes
            string dn = (string)obj[StandardNames.shortName];

            //For each attribute
            foreach (string attr in obj.attributes.Keys)
            {
                if (!ExcludeAttributes.Contains(attr))
                {
                    //This attribute is in must contain list.
                    if (mustContain.Contains(attr))
                    {
                        mustContain.Remove(attr);
                    }
                    //This attribute is not in must and may contian list.
                    else if (!mayContain.Contains(attr))
                    {
                        Checks.Fail("'{0}' must not contain attribute '{1}'", dn, attr);
                    }
                }
            }

            //If must contain list is not empty, this object does not contain some must contain attributes.
            if (mustContain.Count > 0)
            {
                Checks.Fail(
                    "'{0}' does not contain required attributes '{1}'",
                    dn,
                    String.Join(",", mustContain.ToArray()));
            }
        }
        /// <summary>
        ///  Check objectClass.
        /// </summary>
        /// <param name="obj">ModelObject.</param>
        public static void CheckObjectClass(ModelObject obj)
        {
            string dn          = (string)obj[StandardNames.shortName];
            Value  objectClass = obj[StandardNames.objectClass];

            if (objectClass == null)
            {
                Checks.Fail("'{0}' must have object class", dn);

                return;
            }

            // Check for resolution and last/first element compliance
            int           count     = 0;
            List <string> classes   = obj.GetAllClassIds().ToList();
            bool          resolveOk = true;

            foreach (string classId in classes)
            {
                ModelObject classObject;
                //The object must be present in Schema NC.
                if (!obj.dc.TryGetClass(classId, out classObject))
                {
                    Checks.Fail("'{0}' has undefined object class '{1}'", dn, classId);
                    resolveOk = false;
                    continue;
                }
                //Checking for the first class is Top
                if (count == 0 && classId != StandardNames.top)
                {
                    Checks.Fail("'{0}' first object class must be top", dn);
                    resolveOk = false;
                }
                //Checking for the last class is Structural class.
                if (count == objectClass.UnderlyingValues.Count - 1)
                {
                    ObjectClassCategory category = (ObjectClassCategory)(int)classObject[StandardNames.objectClassCategory];

                    if (category != ObjectClassCategory.StructuralClass)
                    {
                        Checks.Fail("'{0}' last object class must be structural");
                        resolveOk = false;
                    }
                }
                count++;
            }
            if (!resolveOk)
            {
                return;
            }

            // Check for superclass chaining
            // Checks that if the value of object class is [top,ac_1,...,ac_n,sc_1,...,sc_n],
            // then sc_n is the most specific structural class, sc_1...scn_(n-1) is the super class chain of sc_n (excluding top),
            // and ac_n is the next auxilary class before that, where ac_1...acn(n-1) is that classes chain excluding classes
            // which have been seen already before (where there can be a number of ac anchors here).
            List <string> includedClasses = new List <string>();
            int           i = classes.Count - 1;

            while (i > 0)
            {
                string classId = classes[i--];
                if (includedClasses.Contains(classId))
                {
                    Checks.Fail("'{0}' object class contains repeated entries", dn);
                    break;
                }
                includedClasses.Add(classId);
                ObjectClassCategory category = (ObjectClassCategory)(int)obj.dc.GetClass(classId)[StandardNames.objectClassCategory];
                if (i == classes.Count - 2)
                {
                    // Most specific class must be structural
                    if (category != ObjectClassCategory.StructuralClass)
                    {
                        Checks.Fail("'{0}' object class most specific class must be structural", dn);
                    }
                }

                //If the server is Pre Windows 2003.
                foreach (string clId in GetSuperClassChain(obj.dc, classId))
                {
                    if (includedClasses.Contains(clId))
                    {
                        // Already included in a previous chain
                        continue;
                    }
                    includedClasses.Add(clId);
                    if (i <= 0)
                    {
                        Checks.Fail(
                            "'{0}' object class does not contain chain of super classes of '{1}' (classes missing)",
                            dn,
                            classId);
                        break;
                    }
                    if (classes[i--] != clId)
                    {
                        Checks.Fail(
                            "'{0}' object class does not contain chain of super classes '{1}' (found unexpected '{2}')",
                            dn,
                            classId,
                            classes[i + 1]);
                        break;
                    }
                }
            }
        }
        /// <summary>
        /// Inheritance is the ability to build new classes from existing classes.
        /// </summary>
        /// <param name="obj">The object of model.</param>
        public static void CheckInheritance(ModelObject obj)
        {
            string dn = (string)obj[StandardNames.shortName];
            //Get super class id.
            string superClassId = (string)obj[StandardNames.subClassOf];

            if (superClassId == null)
            {
                Checks.Fail("'{0}' must have a super class", dn);
            }
            else
            {
                ModelObject superClass;
                if (!obj.dc.TryGetClass(superClassId, out superClass))
                {
                    Checks.Fail("'{0}' has undefined super class '{1}'", dn, superClassId);
                }
                else
                {
                    string thisClassId = (string)obj[StandardNames.governsId];

                    if (thisClassId != StandardNames.topGovernsId && thisClassId == superClassId)
                    {
                        Checks.Fail("{0} cannot inherit from itself", dn);
                    }

                    //Get super class and current class category.
                    ObjectClassCategory thisCategory  = (ObjectClassCategory)(int)obj[StandardNames.objectClassCategory];
                    ObjectClassCategory superCategory = (ObjectClassCategory)(int)superClass[StandardNames.objectClassCategory];
                    bool categoryOk;

                    switch (thisCategory)
                    {
                    //Abstract Class must be inherited from Abstract Class.
                    case ObjectClassCategory.AbstractClass:
                        categoryOk = superCategory == ObjectClassCategory.AbstractClass;
                        break;

                    //Auxiliary Class must not be inherited from Structural Class
                    case ObjectClassCategory.AuxiliaryClass:
                        categoryOk = superCategory != ObjectClassCategory.StructuralClass;
                        break;

                    //Structural Class must not be inherited from Auxiliary Class
                    case ObjectClassCategory.StructuralClass:
                        categoryOk = superCategory != ObjectClassCategory.AuxiliaryClass;
                        break;

                    //Default.
                    default:
                        categoryOk = true;
                        break;
                    }

                    if (!categoryOk)
                    {
                        Checks.Fail("{0} must have object class category which is compatible with its super class", dn);
                    }
                }
            }
        }
예제 #15
0
        /// <summary>
        /// Finds possSuperiors of a given object.
        /// </summary>
        /// <param name="requiredObject">The required object.</param>
        /// <param name="dcModel">The domain controller of model.</param>
        /// <returns>Returns a list of poss superior.</returns>
        public List <string> GetPossSuperiorsList(ModelObject requiredObject, ModelDomainController dcModel)
        {
            //DirectoryEntry serverObj = null;
            List <string> superClasses;
            List <string> auxiliaryClasses;

            //Collect all systemPossSuperiors value of this object.
            if (requiredObject.attributes.Keys.Contains("systemposssuperiors"))
            {
                foreach (string element in requiredObject.attributes["systemposssuperiors"].UnderlyingValues)
                {
                    possSuperiorList.Add(element);
                }
            }

            //Collect all possSuperiors value of this object.
            if (requiredObject.attributes.Keys.Contains("posssuperiors"))
            {
                foreach (string element in requiredObject.attributes["posssuperiors"].UnderlyingValues)
                {
                    possSuperiorList.Add(element);
                }
            }

            //Collect this object's super class List.
            superClasses = GetSuperClassesList(requiredObject, true, dcModel);

            //For each super class,
            foreach (string supClass in superClasses)
            {
                //Get the object from server.
                ModelObject supClassOfObject = null;
                string      className        = supClass.Replace("-", String.Empty).ToLower();

                dcModel.TryGetClass(className, out supClassOfObject);
                //Remove the minus sign and retry
                if (supClassOfObject == null)
                {   //Modified to support Windows Server 2012
                    //Only class names in the format of, eg. msds-claimtype, can be found
                    if (className.Contains("msds"))
                    {
                        className = className.Insert(className.IndexOf("msds") + 4, "-");
                    }
                    else if (supClass.Contains("-"))
                    {
                        className = supClass.Remove(supClass.IndexOf('-'), 1);
                    }
                    dcModel.TryGetClass(className, out supClassOfObject);
                }

                //Call PossSuperiors method with this super class object.
                GetPossSuperiorsList(supClassOfObject, dcModel);
            }

            //Collect auxiliary classes of this object.
            auxiliaryClasses = GetAuxiliaryClassesList(requiredObject, true, dcModel);

            //For each auxiliary class,
            foreach (string auxClass in auxiliaryClasses)
            {
                //Get the object from server.
                ModelObject auxClassOfObject;
                dcModel.TryGetClass(auxClass, out auxClassOfObject);

                //Call PossSuperiors method with this auxiliary class object.
                GetPossSuperiorsList(auxClassOfObject, dcModel);
            }
            //Finally return the possSuperior list.
            return(possSuperiorList);
        }
 /// <summary>
 /// Registers all constructed attributes.
 /// </summary>
 public static void Install()
 {
     ModelObject.RegisterConstructedAttribute(StandardNames.distinguishedName, DistinguishedName);
     ModelObject.RegisterConstructedAttribute(StandardNames.parent, Parent);
     ModelObject.RegisterConstructedAttribute(StandardNames.shortName, ShortName);
 }
        /// <summary>
        /// Adds a set of object definitions to the schema. The format of the schema
        /// is a sequence of lines where objects are separated by empty lines.
        /// Each line of an object definition is a pair of an attribute display name and an
        /// attribute value, separated by ':'. Takes care of "bootstrapping" the contents of
        /// the schema, resolving cyclic dependencies between attribute definitions and objects. 
        /// </summary>
        /// <param name="schema">The schema, represented as explained above.</param>
        /// <param name="valueSubstitution">A substitution of strings which should be applied to each value in the 
        /// schema. For example, may map '&lt;rootdomaindn&gt;' as used in schemas to represent the root name of the 
        /// current DC to an actual value</param>
        /// <param name="serverVersion">Specify the OS version of the server</param>
        /// <returns>Result of the Load Schema method.</returns>
        public ModelResult LoadSchema(IEnumerable<string> schema, Map<string, string> valueSubstitution, OSVersion serverVersion)
        {
            SequenceContainer<ModelObject> newObjects = new SequenceContainer<ModelObject>();
            UnresolvedSyntax unresolvedSyntax = new UnresolvedSyntax();

            #region Pass 1: read in objects resolving only builtin attributes
            // We need this phase for bootstrapping, as we don't have the
            // attributes available which are used in the objects. Thus
            // in this phase, we just parse attribute values of a certain set
            // of builting attributes which are required to get attribute syntax
            // definitions.
            InitializeBuiltinAttributes();
            ModelObject tempobj = null;
            ModelObject obj = null;
            
            foreach (string rawLine in schema)
            {
                string line = (rawLine == null)?null:rawLine.Trim();

                if (String.IsNullOrEmpty(line))
                {
                    // Object ends here
                    if (obj != null)
                    {
                        if (obj[StandardNames.attributeID] == null && obj[StandardNames.governsId] == null)
                        {
                            if (obj.attributes.Count == 1)
                            {
                                // If the server is Windows 2000
                                if (serverVersion == OSVersion.WinSvr2000)
                                {
                                    string attr = obj.attributes.Keys.ElementAt(0);

                                    if (tempobj.attributes.Keys.Contains(attr))
                                    {
                                        tempobj.attributes.Keys.Remove(attr);
                                        tempobj.attributes.Add(obj.attributes.ElementAt(0));
                                    }
                                    else
                                    {
                                        tempobj.attributes.Add(obj.attributes.ElementAt(0));
                                    }
                                    newObjects.RemoveAt(newObjects.Count - 1);
                                    newObjects.Add(tempobj);
                                }
                            }
                            else
                            {
                                Checks.Fail("attributeId/governsId is mandatory for each object {0}.", obj[StandardNames.cn]);
                            }
                        }
                        else if (obj[StandardNames.attributeID] != null)
                        {
                            AddAttribute(obj);
                            newObjects.Add(obj);
                        }
                        else if (obj[StandardNames.governsId] != null)
                        {
                            // This is a class definition. Fill in class map.
                            AddClass(obj);
                            newObjects.Add(obj);
                        }
                        tempobj = obj;
                        obj = null;
                    }
                }
                else
                {
                    if (obj == null)
                    {
                        obj = new ModelObject();
                    }
                    obj.dc = this;

                    string attr, valueString;
                    string[] splits = line.Split(new char[] { ':' }, 2);

                    if (splits == null || splits.Length != 2)
                    {
                        Checks.Fail("invalid schema line '{0}'", line);
                        continue;
                    }
                    attr = splits[0].Trim().ToLower();
                    valueString = Substitute(valueSubstitution, splits[1].Trim());
                    AttributeContext parsingContext;

                    if (!builtinAttributeSyntax.TryGetValue(attr, out parsingContext))
                    {
                        parsingContext = new AttributeContext(this, attr, unresolvedSyntax);
                    }
                    obj[attr] = parsingContext.Parse(valueString);
                }
            }
            #endregion

            #region Pass 2: resolve syntax of all new objects
            // As we have now attribute definitions which map to the syntax, we can parse
            // All values in the new objects.
            foreach (ModelObject newObj in newObjects)
            {
                foreach (string attr in newObj.attributes.Keys)
                {
                    AttributeContext parsingContext = GetAttributeContext(attr);
                    Value value = newObj[attr];

                    if (value.Syntax is UnresolvedSyntax)
                    {
                        newObj[attr] = parsingContext.Parse((string)value);
                    }
                    else
                    {
                        Checks.IsTrue(
                            parsingContext.syntax == value.Syntax,
                            "bultin syntax assignment of '{0}' must match syntax declared in schema", 
                            attr);
                    }
                }
            }
            #endregion

            #region Pass 3: add objects
            // Now all definitions are complete. Add them to schema replica root.
            foreach (ModelObject newObj in newObjects)
            {
                AddChild(schemaReplica.root, newObj);
            }
            #endregion

            #region Pass 4: check consistency
            // The tree is finally setup. Now check for consistency
            Consistency.Check(newObjects.ToSequence());
            #endregion

            if (Checks.HasDiagnostics)
            {
                return new ModelResult(ResultCode.ConstraintViolation, Checks.GetAndClearLog(), Checks.GetAndClearDiagnostics());
            }
            else
            {
                //return Result.Success;
                ModelResult tempRes = new ModelResult(ResultCode.Success);
                tempRes.logMessage = Checks.GetAndClearLog();
                return tempRes;
            }

        }
        /// <summary>
        /// Adds an object to DC at parent location.
        /// The objects content is specified by a sequence of strings where each string
        /// consists of a pair of attribute name and value.
        /// </summary>
        /// <param name="parentDN">The DN of parent.</param>
        /// <param name="attributes">All attributes of model object.</param>
        public ModelResult Add(string parentDN, params string[] attributes)
        {
            ModelObject parent = TryFindObject(parentDN);

            if (parent == null)
            {
                return(new ModelResult(ResultCode.NoSuchObject, "cannot find '{0}'", parentDN));
            }

            ModelObject obj = new ModelObject();

            obj.dc = this;

            foreach (string line in attributes)
            {
                string   attr, valueString;
                string[] splits = line.Split(new char[] { ':' }, 2);
                if (splits == null || splits.Length != 2)
                {
                    return(new ModelResult(ResultCode.InvalidAttributeSyntax));
                }
                attr        = splits[0].Trim();
                valueString = splits[1].Trim();
                ModelObject attrObj;

                if (!TryGetAttribute(splits[0], out attrObj))
                {
                    return(new ModelResult(ResultCode.NoSuchAttribute, attr));
                }

                AttributeContext parsingContext = GetAttributeContext(attr);
                obj[attr] = parsingContext.Parse(valueString);

                if (Checks.HasDiagnostics)
                {
                    return(new ModelResult(ResultCode.InvalidAttributeSyntax, Checks.GetAndClearDiagnostics()));
                }
            }
            string rdnName = GetRDNAttributeName(obj);

            if (rdnName != null)
            {
                string rdn = (string)obj[rdnName];
                if (parent.childs.ContainsKey(rdn))
                {
                    return(new ModelResult(ResultCode.EntryAlreadyExists));
                }
                AddChild(parent, obj);
                Consistency.Check(new List <ModelObject> {
                    obj
                });
            }
            if (Checks.HasDiagnostics)
            {
                return(new ModelResult(ResultCode.ConstraintViolation, Checks.GetAndClearDiagnostics()));
            }
            else
            {
                return(ModelResult.Success);
            }
        }