/// <summary> /// Updates an AD object (also called by create after object is created) /// </summary> /// <param name="oclass"></param> /// <param name="directoryEntry"></param> /// <param name="attributes"></param> /// <param name="type"></param> /// <param name="config"></param> internal void UpdateADObject(ObjectClass oclass, DirectoryEntry directoryEntry, ICollection<ConnectorAttribute> attributes, UpdateType type, ActiveDirectoryConfiguration config) { if(oclass.Equals(ObjectClass.ACCOUNT)) { // translate attribute passed in foreach (ConnectorAttribute attribute in attributes) { // encountered problems when processing change password at the same time // as setting expired. It would be set to expired, but the change would // clear that. So we must ensure that expired comes last. if (OperationalAttributes.PASSWORD_EXPIRED_NAME.Equals(attribute.Name)) { continue; } AddConnectorAttributeToADProperties(oclass, directoryEntry, attribute, type); // Uncommenting the next line is very helpful in // finding mysterious errors. // Trace.TraceInformation("Committing after setting attribute {0} to {1}", attribute.Name, attribute.Value); // directoryEntry.CommitChanges(); } directoryEntry.CommitChanges(); // now do the password change. This is handled separately, because // it might be a user changing his own password, or it might be an // administrative change. GuardedString gsNewPassword = ConnectorAttributeUtil.GetPasswordValue(attributes); if (gsNewPassword != null) { GuardedString gsCurrentPassword = ConnectorAttributeUtil.GetCurrentPasswordValue(attributes); PasswordChangeHandler changeHandler = new PasswordChangeHandler(_configuration); if (gsCurrentPassword == null) { // just a normal password change changeHandler.changePassword(directoryEntry, gsNewPassword); } else { changeHandler.changePassword(directoryEntry, gsCurrentPassword, gsNewPassword); } UserAccountControl.Set(directoryEntry.Properties[ActiveDirectoryConnector.ATT_USER_ACOUNT_CONTROL], UserAccountControl.PASSWD_NOTREQD, false); directoryEntry.CommitChanges(); } // see note in loop above for explaination of this ConnectorAttribute expirePasswordAttribute = ConnectorAttributeUtil.Find( OperationalAttributes.PASSWORD_EXPIRED_NAME, attributes); if (expirePasswordAttribute != null) { AddConnectorAttributeToADProperties(oclass, directoryEntry, expirePasswordAttribute, type); directoryEntry.CommitChanges(); } /* UserAccountControl.Set(directoryEntry.Properties[ActiveDirectoryConnector.ATT_USER_ACOUNT_CONTROL], UserAccountControl.PASSWD_NOTREQD, false); */ directoryEntry.CommitChanges(); HandleNameAndContainerChange(type, directoryEntry, attributes, config); } else if (oclass.Equals(ActiveDirectoryConnector.groupObjectClass)) { // translate attribute passed in foreach (ConnectorAttribute attribute in attributes) { // Temporary // Trace.TraceInformation(String.Format("Setting attribute {0} to {1}", // attribute.Name, attribute.Value)); AddConnectorAttributeToADProperties(oclass, directoryEntry, attribute, type); // Uncommenting the next line is very helpful in // finding mysterious errors. // directoryEntry.CommitChanges(); } directoryEntry.CommitChanges(); HandleNameAndContainerChange(type, directoryEntry, attributes, config); } else if (oclass.Equals(ActiveDirectoryConnector.ouObjectClass)) { // translate attribute passed in foreach (ConnectorAttribute attribute in attributes) { // Temporary // Trace.TraceInformation(String.Format("Setting attribute {0} to {1}", // attribute.Name, attribute.Value)); AddConnectorAttributeToADProperties(oclass, directoryEntry, attribute, type); // Uncommenting the next line is very helpful in // finding mysterious errors. // directoryEntry.CommitChanges(); } directoryEntry.CommitChanges(); HandleNameAndContainerChange(type, directoryEntry, attributes, config); } else { String objectClassName = GetADObjectClass(oclass); // translate attribute passed in foreach (ConnectorAttribute attribute in attributes) { // Temporary // Trace.TraceInformation(String.Format("Setting attribute {0} to {1}", // attribute.Name, attribute.Value)); AddConnectorAttributeToADProperties(oclass, directoryEntry, attribute, type); // Uncommenting the next line is very helpful in // finding mysterious errors. // directoryEntry.CommitChanges(); } directoryEntry.CommitChanges(); HandleNameAndContainerChange(type, directoryEntry, attributes, config); } }
/// <summary> /// Creates a SyncDelata /// </summary> /// <param name="token">The token. Must not be null.</param> /// <param name="deltaType">The delta. Must not be null.</param> /// <param name="previousUid">The previousUid. Can be null.</param> /// <param name="objectClass">The objectClass. Can be null.</param> /// <param name="uid">The uid. Must not be null.</param> /// <param name="obj">The object that has changed. May be null for delete.</param> internal SyncDelta(SyncToken token, SyncDeltaType deltaType, Uid previousUid, ObjectClass objectClass, Uid uid, ConnectorObject obj) { Assertions.NullCheck(token, "token"); Assertions.NullCheck(deltaType, "deltaType"); Assertions.NullCheck(objectClass, "objectClass"); Assertions.NullCheck(uid, "uid"); //do not allow previous Uid for anything else than create or update if (previousUid != null && (deltaType == SyncDeltaType.DELETE || deltaType == SyncDeltaType.CREATE)) { throw new ArgumentException("The previous Uid can only be specified for create_or_update or udate."); } //only allow null object for delete if (obj == null && deltaType != SyncDeltaType.DELETE) { throw new ArgumentException("ConnectorObject must be specified for anything other than delete."); } //if object not null, make sure its Uid //matches if (obj != null) { if (!uid.Equals(obj.Uid)) { throw new ArgumentException("Uid does not match that of the object."); } if (!objectClass.Equals(obj.ObjectClass)) { throw new ArgumentException("ObjectClass does not match that of the object."); } } _token = token; _deltaType = deltaType; _previousUid = previousUid; _objectClass = objectClass; _uid = uid; _object = obj; }
/// <summary> /// Returns the AD ObjectClass associated with a particular /// Connector ObjectClass /// </summary> /// <param name="oclass"></param> /// <returns></returns> internal String GetADObjectClass(ObjectClass oclass) { if (oclass.Equals(ObjectClass.ACCOUNT)) { return _configuration.ObjectClass; } else if (ActiveDirectoryConnector.groupObjectClass.Equals(oclass)) { return "Group"; } else if (ActiveDirectoryConnector.ouObjectClass.Equals(oclass)) { return "organizationalUnit"; } else { // It's not something I know about, so I'll consult the AD schema. // if it's there, fine, but if not throw an exception. //first check to see if we have seen it before. String objectClassName = oclass.GetObjectClassValue(); if(_knownObjectClasses.Contains(objectClassName)) { return objectClassName; } // if we havent seen it before, consult AD's schema ActiveDirectorySchema ADSchema = GetADSchema(); ActiveDirectorySchemaClass ADSchemaClass = null; try { ADSchemaClass = ADSchema.FindClass(objectClassName); _knownObjectClasses.Add(objectClassName); return objectClassName; } catch (ActiveDirectoryObjectNotFoundException exception) { String msg = _configuration.ConnectorMessages.Format( "ex_ObjectClassInvalidForConnector", "ObjectClass \'{0}\' is not valid for this connector", objectClassName); throw new ConnectorException(msg); } } }
private void RenameObjectAndVerify(ActiveDirectoryConnector connector, ObjectClass oc, ICollection<ConnectorAttribute> createAttributes) { Uid createdUid = null; Uid updatedUid = null; try { // create the objec createdUid = CreateAndVerifyObject(connector, oc, createAttributes); // update the name of the object var oldName = ConnectorAttributeUtil.GetNameFromAttributes(createAttributes); var newName = ActiveDirectoryUtils.GetRelativeName(oldName); newName = newName.Trim() + "_new, " + GetProperty(ConfigHelper.CONFIG_PROPERTY_CONTAINER); updatedUid = UpdateReplaceAndVerifyObject(connector, oc, createdUid, new List<ConnectorAttribute>() { ConnectorAttributeBuilder.Build(Name.NAME, newName) }); if (oc.Equals(ObjectClass.ACCOUNT)) { Assert.AreEqual(createdUid, updatedUid, "The Uid of an object of type ACCOUNT must not change."); } // test if the original object exists var nameFilter = FilterBuilder.EqualTo(ConnectorAttributeBuilder.Build(Name.NAME, oldName.Value)); var optionsBuilder = new OperationOptionsBuilder() { AttributesToGet = new[] { Name.NAME } }; var originalObjects = TestHelpers.SearchToList(connector, oc, nameFilter, optionsBuilder.Build()); Assert.AreEqual(0, originalObjects.Count, string.Format(System.Globalization.CultureInfo.InvariantCulture, "An object of type '{0}' with the original name exists.", oc)); } finally { if (createdUid != null) { DeleteAndVerifyObject(connector, oc, createdUid, false, false); } //make sure that the updated object is deleted as well if (updatedUid != null) { DeleteAndVerifyObject(connector, oc, updatedUid, false, false); } } }