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); }
/// <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; }
/// <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; }
// ======================================================================= // 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; }
/// <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); }
/// <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); }
/// <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); }
/// <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(); }
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)); } }
/// <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(); }
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)); } } }
// 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; } }
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); } */ }