Example #1
0
        public static string GetRecipientType(ConnectorObject cobject)
        {
            long? recipientTypeDetails =
                ExchangeUtility.GetAttValue(ExchangeConnectorAttributes.AttMsExchRecipientTypeDetailsADName, cobject.GetAttributes()) as long?;
            switch (recipientTypeDetails) { // see http://blogs.technet.com/b/benw/archive/2007/04/05/exchange-2007-and-recipient-type-details.aspx

                case 1: return ExchangeConnectorAttributes.RcptTypeMailBox;
                case 128: return ExchangeConnectorAttributes.RcptTypeMailUser;

                case null:          // we are dealing with user accounts, so we can assume that an account without Exchange information is an ordinary User
                case 65536: return ExchangeConnectorAttributes.RcptTypeUser;

                default:
                    LOGGER.TraceEvent(TraceEventType.Information, CAT_DEFAULT, "Unknown recipientTypeDetails: {0} ({1})", recipientTypeDetails,
                        ExchangeUtility.GetAttValue(ExchangeConnectorAttributes.AttMsExchRecipientTypeDetailsADName, cobject.GetAttributes()));
                    return null;
            }
        }
 public void UpdateMergeTests()
 {
     ConnectorAttribute expected, actual;
     Configuration config = new MockConfiguration(false);
     ConnectorFacadeFactory factory = ConnectorFacadeFactory.GetInstance();
     SafeType<Connector> clazz = SafeType<Connector>.Get<MockUpdateConnector>();
     // **test only**
     APIConfiguration impl = TestHelpers.CreateTestConfiguration(clazz, config);
     impl.SetTimeout(SafeType<APIOperation>.Get<GetApiOp>(), APIConstants.NO_TIMEOUT);
     impl.SetTimeout(SafeType<APIOperation>.Get<UpdateApiOp>(), APIConstants.NO_TIMEOUT);
     impl.SetTimeout(SafeType<APIOperation>.Get<SearchApiOp>(), APIConstants.NO_TIMEOUT);
     ConnectorFacade facade = factory.NewInstance(impl);
     // sniff test to make sure we can get an object..
     ConnectorObject obj = facade.GetObject(ObjectClass.ACCOUNT, NewUid(1), null);
     Assert.AreEqual(NewUid(1), obj.Uid);
     // ok lets add an attribute that doesn't exist..
     String ADDED = "somthing to add to the object";
     String ATTR_NAME = "added";
     ICollection<ConnectorAttribute> addAttrSet;
     addAttrSet = CollectionUtil.NewSet((IEnumerable<ConnectorAttribute>)obj.GetAttributes());
     addAttrSet.Add(ConnectorAttributeBuilder.Build(ATTR_NAME, ADDED));
     Name name = obj.Name;
     addAttrSet.Remove(name);
     Uid uid = facade.AddAttributeValues(ObjectClass.ACCOUNT, obj.Uid, ConnectorAttributeUtil.FilterUid(addAttrSet), null);
     // get back the object and see if there are the same..
     addAttrSet.Add(name);
     ConnectorObject addO = new ConnectorObject(ObjectClass.ACCOUNT, addAttrSet);
     obj = facade.GetObject(ObjectClass.ACCOUNT, NewUid(1), null);
     Assert.AreEqual(addO, obj);
     // attempt to add on to an existing attribute..
     addAttrSet.Remove(name);
     uid = facade.AddAttributeValues(ObjectClass.ACCOUNT, obj.Uid, ConnectorAttributeUtil.FilterUid(addAttrSet), null);
     // get the object back out and check on it..
     obj = facade.GetObject(ObjectClass.ACCOUNT, uid, null);
     expected = ConnectorAttributeBuilder.Build(ATTR_NAME, ADDED, ADDED);
     actual = obj.GetAttributeByName(ATTR_NAME);
     Assert.AreEqual(expected, actual);
     // attempt to delete a value from an attribute..
     ICollection<ConnectorAttribute> deleteAttrs = CollectionUtil.NewSet((IEnumerable<ConnectorAttribute>)addO.GetAttributes());
     deleteAttrs.Remove(name);
     uid = facade.RemoveAttributeValues(ObjectClass.ACCOUNT, addO.Uid, ConnectorAttributeUtil.FilterUid(deleteAttrs), null);
     obj = facade.GetObject(ObjectClass.ACCOUNT, uid, null);
     expected = ConnectorAttributeBuilder.Build(ATTR_NAME, ADDED);
     actual = obj.GetAttributeByName(ATTR_NAME);
     Assert.AreEqual(expected, actual);
     // attempt to delete an attribute that doesn't exist..
     ICollection<ConnectorAttribute> nonExist = new HashSet<ConnectorAttribute>();
     nonExist.Add(NewUid(1));
     nonExist.Add(ConnectorAttributeBuilder.Build("does not exist", "asdfe"));
     uid = facade.RemoveAttributeValues(ObjectClass.ACCOUNT, addO.Uid, ConnectorAttributeUtil.FilterUid(nonExist), null);
     obj = facade.GetObject(ObjectClass.ACCOUNT, NewUid(1), null);
     Assert.IsTrue(obj.GetAttributeByName("does not exist") == null);
 }
Example #3
0
 /// <summary>
 /// Creates a new <code>SyncDeltaBuilder</code> whose
 /// values are initialized to those of the delta.
 /// </summary>
 /// <param name="delta">The original delta.</param>
 public SyncDeltaBuilder(SyncDelta delta)
 {
     _token = delta.Token;
     _deltaType = delta.DeltaType;
     _previousUid = delta.PreviousUid;
     _uid = delta.Uid;
     _object = delta.Object;
 }
Example #4
0
        /// <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="uid">The uid. Must not be null.</param>
        /// <param name="object">The object that has changed. May be null for delete.</param>
        internal SyncDelta(SyncToken token, SyncDeltaType deltaType,
            Uid previousUid, Uid uid,
            ConnectorObject obj)
        {
            Assertions.NullCheck(token, "token");
            Assertions.NullCheck(deltaType, "deltaType");
            Assertions.NullCheck(uid, "uid");

            //do not allow previous Uid for anything else than create or update
            if (previousUid != null && deltaType != SyncDeltaType.CREATE_OR_UPDATE)
            {
                throw new ArgumentException("The previous Uid can only be specified for create or update.");
            }

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

            _token = token;
            _deltaType = deltaType;
            _previousUid = previousUid;
            _uid = uid;
            _object = obj;
        }
Example #5
0
 // =======================================================================
 // Clone basically..
 // =======================================================================
 /// <summary>
 /// Takes all the attribute from a <see cref="ConnectorObject" /> and add/overwrite
 /// the current attributes.
 /// </summary>
 public ConnectorObjectBuilder Add(ConnectorObject obj)
 {
     // simply add all the attributes it will include (Uid, ObjectClass..)
     foreach (ConnectorAttribute attr in obj.GetAttributes())
     {
         AddAttribute(attr);
     }
     ObjectClass = obj.ObjectClass;
     return this;
 }
Example #6
0
 /// <summary>
 /// Determine if the password is expired for this object.
 /// </summary>
 /// <param name="obj">
 /// <see cref="ConnectorObject" /> that should contain a password expired
 /// attribute.</param>
 /// <returns>
 /// <code>null</code> if the attribute does not exist and the value
 /// of the <see cref="ConnectorAttribute" /> if it does.</returns>
 public static bool? IsPasswordExpired(ConnectorObject obj)
 {
     ConnectorAttribute pwd = obj.GetAttributeByName(OperationalAttributes.PASSWORD_EXPIRED_NAME);
     return (pwd == null) ? null : GetBooleanValue(pwd);
 }
Example #7
0
 /// <summary>
 /// Determine if the <see cref="ConnectorObject" /> is locked out.
 /// </summary>
 /// <remarks>
 /// By getting the
 /// value of the <see cref="OperationalAttributes.LOCK_OUT_NAME" />.
 /// </remarks>
 /// <param name="obj">
 /// <see cref="ConnectorObject" /> object to inspect.</param>
 /// <exception cref="NullReferenceException">iff the parameter 'obj' is <code>null</code>.</exception>
 /// <returns>
 /// <code>null</code> if the attribute does not exist otherwise to
 /// value of the <see cref="ConnectorAttribute" />.</returns>
 public static bool? IsLockedOut(ConnectorObject obj)
 {
     ConnectorAttribute attr = obj.GetAttributeByName(OperationalAttributes.LOCK_OUT_NAME);
     return (attr == null) ? null : GetBooleanValue(attr);
 }
Example #8
0
 /// <summary>
 /// Determine if the <see cref="ConnectorObject" /> is enable.
 /// </summary>
 /// <remarks>
 /// By getting the value
 /// of the <see cref="OperationalAttributes.ENABLE_NAME" />.
 /// </remarks>
 /// <param name="obj">
 /// <see cref="ConnectorObject" /> object to inspect.</param>
 /// <exception cref="IllegalStateException">if the object does not contain attribute in question.</exception>
 /// <exception cref="NullReferenceException">iff the parameter 'obj' is <code>null</code>.</exception>
 /// <returns>
 /// <code>null</code> if the attribute does not exist otherwise to
 /// value of the <see cref="ConnectorAttribute" />.</returns>
 public static bool? IsEnabled(ConnectorObject obj)
 {
     ConnectorAttribute attr = obj.GetAttributeByName(OperationalAttributes.ENABLE_NAME);
     return (attr == null) ? null : GetBooleanValue(attr);
 }
Example #9
0
 /// <summary>
 /// Retrieve the password expiration date from the <see cref="ConnectorObject" />.
 /// </summary>
 /// <param name="obj">
 /// <see cref="ConnectorObject" /> object to inspect.</param>
 /// <exception cref="IllegalStateException">if the object does not contain attribute in question.</exception>
 /// <exception cref="NullReferenceException">iff the parameter 'obj' is <code>null</code>.</exception>
 /// <returns>
 /// <code>null</code> if the <see cref="ConnectorAttribute" /> does not exist
 /// otherwise the value of the <see cref="ConnectorAttribute" />.</returns>
 public static DateTime? GetPasswordExpirationDate(ConnectorObject obj)
 {
     DateTime? ret = null;
     ConnectorAttribute attr = obj.GetAttributeByName(OperationalAttributes.PASSWORD_EXPIRATION_DATE_NAME);
     if (attr != null)
     {
         long? date = GetLongValue(attr);
         if (date != null)
         {
             ret = DateTime.FromFileTimeUtc(date.Value);
         }
     }
     return ret;
 }
        /// <summary>
        /// Finds the attributes in connector object and rename it according to input array of names, but only
        /// if the atribute name is in attributes to get
        /// </summary>
        /// <param name="cobject">ConnectorObject which attributes should be replaced</param>
        /// <param name="attsToGet">Attributes to get list</param>
        /// <param name="map">Replace mapping</param>
        /// <returns>ConnectorObject with replaced attributes</returns>        
        /// <exception cref="ArgumentNullException">If some of the params is null</exception>
        internal static ConnectorObject ReplaceAttributes(ConnectorObject cobject, ICollection<string> attsToGet, IDictionary<string, string> map)
        {
            Assertions.NullCheck(cobject, "cobject");
            Assertions.NullCheck(map, "map");
            if (attsToGet == null)
            {
                return cobject;
            }

            var attributes = cobject.GetAttributes();
            var builder = new ConnectorObjectBuilder();
            foreach (ConnectorAttribute attribute in attributes)
            {
                string newName;
                if (map.TryGetValue(attribute.Name, out newName) && attsToGet.Contains(newName))
                {
                    var newAttribute = RenameAttribute(attribute, newName);
                    builder.AddAttribute(newAttribute);
                    break;
                }

                builder.AddAttribute(attribute);
            }

            builder.AddAttributes(attributes);
            builder.ObjectClass = cobject.ObjectClass;
            builder.SetName(cobject.Name);
            builder.SetUid(cobject.Uid);
            return builder.Build();
        }
Example #11
0
 private static void copyAttribute(ConnectorObjectBuilder builder, ConnectorObject cobject, string src, string dest)
 {
     ConnectorAttribute srcAttr = cobject.GetAttributeByName(src);
     if (srcAttr != null)
     {
         builder.AddAttribute(RenameAttribute(srcAttr, dest));
     }
 }
Example #12
0
        /// <summary>
        /// Finds the attributes in connector object and rename it according to input array of names, but only
        /// if the atribute name is in attributes to get
        /// </summary>
        /// <param name="cobject">ConnectorObject which attributes should be replaced</param>
        /// <param name="map">Replace mapping</param>
        /// <returns>ConnectorObject with replaced attributes</returns>        
        /// <exception cref="ArgumentNullException">If some of the params is null</exception>
        internal static ConnectorObject ConvertAdAttributesToExchange(ConnectorObject cobject)
        {
            Assertions.NullCheck(cobject, "cobject");

            var attributes = cobject.GetAttributes();
            var builder = new ConnectorObjectBuilder();

            bool emailAddressPolicyEnabled = true;
            foreach (ConnectorAttribute attribute in attributes)
            {
                string newName;
                if (attribute.Is(ExchangeConnectorAttributes.AttMsExchPoliciesExcludedADName))
                {
                    if (attribute.Value != null && attribute.Value.Contains("{26491cfc-9e50-4857-861b-0cb8df22b5d7}"))
                    {
                        emailAddressPolicyEnabled = false;
                    }
                }
                else if (attribute.Is(ExchangeConnectorAttributes.AttAddressBookPolicyADName))
                {
                    var newAttribute = ExtractCommonName(attribute, ExchangeConnectorAttributes.AttAddressBookPolicy);
                    builder.AddAttribute(newAttribute);
                    builder.AddAttribute(attribute);        // keep the original one as well
                }
                else if (attribute.Is(ExchangeConnectorAttributes.AttOfflineAddressBookADName))
                {
                    var newAttribute = ExtractCommonName(attribute, ExchangeConnectorAttributes.AttOfflineAddressBook);
                    builder.AddAttribute(newAttribute);
                    builder.AddAttribute(attribute);        // keep the original one as well
                }
                else if (ExchangeConnectorAttributes.AttMapFromAD.TryGetValue(attribute.Name, out newName))
                {
                    var newAttribute = RenameAttribute(attribute, newName);
                    builder.AddAttribute(newAttribute);
                }
                else
                {
                    builder.AddAttribute(attribute);
                }
            }

            builder.AddAttribute(ConnectorAttributeBuilder.Build(ExchangeConnectorAttributes.AttEmailAddressPolicyEnabled, emailAddressPolicyEnabled));

            copyAttribute(builder, cobject, ExchangeConnectorAttributes.AttPrimarySmtpAddressADName, ExchangeConnectorAttributes.AttPrimarySmtpAddress);

            // derive recipient type
            string recipientType = GetRecipientType(cobject);
            if (recipientType != null)
            {
                builder.AddAttribute(ConnectorAttributeBuilder.Build(ExchangeConnectorAttributes.AttRecipientType, new string[] { recipientType }));
            }

            builder.ObjectClass = cobject.ObjectClass;
            builder.SetName(cobject.Name);
            builder.SetUid(cobject.Uid);
            return builder.Build();
        }
Example #13
0
 public bool Handle(ConnectorObject obj)
 {
     return _target.Handle(obj);
 }
        private static void VerifyObject(ICollection<ConnectorAttribute> requestedAttributes,
            ConnectorObject returnedObject)
        {
            // verify guid is in the proper format.  This is important for IDM.
            if (returnedObject.ObjectClass.Equals(ObjectClass.ACCOUNT))
            {

                Uid uid = returnedObject.Uid;
                String uidValue = uid.GetUidValue();
                Assert.That(uidValue.StartsWith(("<GUID=")), "GUID for user objects must start with <GUID=");
                Assert.That(uidValue.EndsWith(">"), "GUID for account objects must end with >");
                Assert.That(uidValue.ToLower().Replace("guid", "GUID").Equals(uidValue),
                    "GUID for account objects must have lowercase hex strings");
            }

            // for now, skipping values that are very difficult to
            // determine equality ... or they are not returned like
            // 'userPassword'.
            ICollection<String> skipAttributeNames = new List<String>();
            skipAttributeNames.Add("USERPASSWORD");
            skipAttributeNames.Add(OperationalAttributes.PASSWORD_NAME);
            skipAttributeNames.Add(OperationalAttributes.CURRENT_PASSWORD_NAME);
            skipAttributeNames.Add(Uid.NAME);
            // have to ignore the password expire attribute.  It will not come
            // back EXACTLY the same as it was set.  It seems like may ad rounds
            // off to the nearest second, or minute, or something.
            skipAttributeNames.Add(OperationalAttributes.PASSWORD_EXPIRATION_DATE_NAME);

            ICollection<String> ldapStringAttributes = new List<String>();
            ldapStringAttributes.Add("AD_CONTAINER");
            ldapStringAttributes.Add(Name.NAME);
            ldapStringAttributes.Add(PredefinedAttributes.GROUPS_NAME);
            ldapStringAttributes.Add(ActiveDirectoryConnector.ATT_ACCOUNTS);

            // for each attribute in the connector object ...
            foreach (ConnectorAttribute attribute in requestedAttributes)
            {
                ConnectorAttribute returnedAttribute = returnedObject.GetAttributeByName(
                    attribute.Name);

                if (skipAttributeNames.Contains(attribute.Name.ToUpper()))
                {
                    Trace.TraceWarning("Skipping comparison of attribute {0}",
                        attribute.Name);
                    Trace.TraceWarning("requested values were:");
                    foreach (Object requestedValueObject in attribute.Value)
                    {
                        Trace.TraceWarning(requestedValueObject.ToString());
                    }
                    if (returnedAttribute == null)
                    {
                        Trace.TraceWarning("<null> no {0} attribute was returned",
                            attribute.Name);
                    }
                    else
                    {
                        Trace.TraceWarning("returned values were:");
                        foreach (Object returnedValueObject in returnedAttribute.Value)
                        {
                            Trace.TraceWarning(returnedValueObject.ToString());
                        }
                    }
                    continue;
                }

                Assert.IsNotNull(returnedAttribute);

                // for each value in the attribute ...
                foreach (Object requestedValueObject in attribute.Value)
                {
                    // order of multivalue attributes is not gauranted, so check
                    // all values of the returned object against the value
                    // also attributes like the ldap 'objectclass' might return
                    // more values than I set ... (set User, return user, top, inetorgperson)
                    Boolean foundValue = false;
                    foreach (Object returnedValueObject in returnedAttribute.Value)
                    {
                        Object lhs = requestedValueObject;
                        Object rhs = returnedValueObject;

                        // if its an ldap string, put it in a standard form
                        if (ldapStringAttributes.Contains(attribute.Name.ToUpper()))
                        {
                            Assert.That(requestedValueObject is String);
                            Assert.That(returnedValueObject is String);
                            lhs = ActiveDirectoryUtils.NormalizeLdapString((String)requestedValueObject);
                            rhs = ActiveDirectoryUtils.NormalizeLdapString((String)returnedValueObject);
                            /*
                            // if either of them start with a server name, take it off
                            // it's not important to the comparison
                            string []lhsParts = ((string)lhs).Split('/');
                            Assert.LessOrEqual(lhsParts.Length, 2);
                            lhs = (lhsParts.Length) == 1 ? lhsParts[0] : lhsParts[1];
                            string[] rhsParts = ((string)rhs).Split('/');
                            Assert.LessOrEqual(rhsParts.Length, 2);
                            lhs = (rhsParts.Length) == 1 ? rhsParts[0] : rhsParts[1];
                            */
                        }

                        if (lhs.Equals(rhs))
                        {
                            foundValue = true;
                            break;
                        }
                    }
                    Assert.IsTrue(foundValue,
                        String.Format("Could not find value {0} for attribute named {1}",
                        requestedValueObject, attribute.Name));
                }
            }
        }
Example #15
0
        // creates a collection of attributes that correspond to the original ones, but resolves ADD/DELETE using existing values of psuser
        public ICollection<ConnectorAttribute> DetermineNewAttributeValues(UpdateOpContext context, ConnectorObject originalObject)
        {
            if (context.UpdateType == UpdateType.REPLACE)
            {
                // TODO check multivaluedness and updateability (as below)
                return new List<ConnectorAttribute>(context.Attributes);
            }
            else
            {
                Boolean add;
                if (context.UpdateType == UpdateType.ADD)
                {
                    add = true;
                }
                else if (context.UpdateType == UpdateType.DELETE)
                {
                    add = false;
                }
                else
                {
                    throw new ArgumentException("Unsupported update type: " + context.UpdateType);
                }

                Schema schema = null;
                ICollection<ConnectorAttribute> rv = new List<ConnectorAttribute>(context.Attributes.Count);
                foreach (ConnectorAttribute attribute in context.Attributes)
                {
                    ConnectorAttribute originalAttribute = originalObject.GetAttributeByName(attribute.Name);
                    IList<object> newValues = originalAttribute != null && originalAttribute.Value != null ? new List<object>(originalAttribute.Value) : new List<object>();
                    Boolean changed = false;
                    if (attribute.Value != null)
                    {
                        foreach (object item in attribute.Value)
                        {
                            if (add)
                            {
                                if (newValues.Contains(item))
                                {
                                    LOGGER.TraceEvent(TraceEventType.Warning, CAT_DEFAULT, "Trying to add value from " + attribute.Name + " that is already there: " + item);
                                }
                                else
                                {
                                    newValues.Add(item);
                                    changed = true;
                                }
                            }
                            else
                            {
                                if (!newValues.Contains(item))
                                {
                                    LOGGER.TraceEvent(TraceEventType.Warning, CAT_DEFAULT, "Trying to remove value from " + attribute.Name + " that is not there: " + item);
                                }
                                else
                                {
                                    newValues.Remove(item);
                                    changed = true;
                                }
                            }
                        }
                    }
                    if (changed)
                    {
                        ConnectorAttributeBuilder b = new ConnectorAttributeBuilder();
                        b.Name = attribute.Name;
                        b.AddValue(newValues);
                        ConnectorAttribute modified = b.Build();

                        if (schema == null)
                        {
                            ExchangeConnector connector = (ExchangeConnector)context.Connector;
                            schema = connector.Schema();
                        }
                        ObjectClassInfo oci = schema.FindObjectClassInfo(context.ObjectClass.Type);
                        if (oci == null)
                        {
                            throw new InvalidOperationException("No object class info for " + context.ObjectClass.Type + " in the schema");
                        }
                        var cai = ConnectorAttributeInfoUtil.Find(attribute.Name, oci.ConnectorAttributeInfos);
                        if (cai == null)
                        {
                            throw new InvalidOperationException("No connector attribute info for " + context.ObjectClass.Type + " in the schema");
                        }

                        if (!cai.IsUpdateable)
                        {
                            throw new ConnectorSecurityException("Attempt to update a non-updateable attribute (" + attribute.Name + "): " +
                                CollectionUtil.Dump(newValues));
                        }

                        if (newValues.Count > 1 && !cai.IsMultiValued)
                        {
                            throw new InvalidAttributeValueException("More than one value in a single-valued attribute (" + attribute.Name + "): " +
                                    CollectionUtil.Dump(newValues));
                        }
                        rv.Add(modified);
                    }
                }
                return rv;
            }
        }
Example #16
0
        public string DetermineOrigAndNewAttributeValue(UpdateOpContext context, ConnectorObject origObject, ICollection<ConnectorAttribute> attributesForReplace, string attributeName, out string origAttributeValue)
        {
            ConnectorAttribute originalAttribute = origObject.GetAttributeByName(attributeName);
            if (originalAttribute != null)
            {
                origAttributeValue = ConnectorAttributeUtil.GetAsStringValue(originalAttribute);
            }
            else
            {
                origAttributeValue = null;
            }

            ConnectorAttribute newAttribute = ConnectorAttributeUtil.Find(attributeName, attributesForReplace);
            if (newAttribute != null)
            {
                return ConnectorAttributeUtil.GetAsStringValue(newAttribute);
            }
            else
            {
                return origAttributeValue;
            }

            /*
            string deltaValue = ConnectorAttributeUtil.GetAsStringValue(attribute);
            if (attribute == null) {
                return origAttributeValue;
            }
            switch (context.UpdateType) {
                case UpdateType.ADD:
                    if (deltaValue == null) {
                        return origAttributeValue;
                    }
                    if (origAttributeValue != null && !origAttributeValue.Equals(deltaValue)) {
                        throw new ArgumentException("Multiple values for " + attribute.Name + " are not allowed: existing = " + origAttributeValue + ", one being added = " + deltaValue);
                    } else {
                        return deltaValue;
                    }
                case UpdateType.REPLACE:
                    return deltaValue;
                case UpdateType.DELETE:
                    if (deltaValue == null) {
                        return origAttributeValue;
                    }
                    if (origAttributeValue == null || !origAttributeValue.Equals(deltaValue)) {
                        LOGGER.TraceEvent(TraceEventType.Warning, CAT_DEFAULT, "Trying to remove value from " + attribute.Name + " that is not there: " + deltaValue);
                        return origAttributeValue;
                    } else {
                        return null;
                    }
                default:
                    throw new ArgumentException("Invalid update type: " + context.UpdateType);
            } */
        }