public Uid Create(ObjectClass objectClass, ICollection <ConnectorAttribute> createAttributes, OperationOptions options) { ConnectorAttributesAccessor accessor = new ConnectorAttributesAccessor(createAttributes); if (accessor.HasAttribute("fail")) { throw new ConnectorException("Test Exception"); } else if (accessor.HasAttribute("exist") && accessor.FindBoolean("exist") == true) { throw new AlreadyExistsException(accessor.GetName().GetNameValue()); } else if (accessor.HasAttribute("emails")) { object value = ConnectorAttributeUtil.GetSingleValue(accessor.Find("emails")); if (value is IDictionary) { return(new Uid((string)((IDictionary)value)["email"])); } else { throw new InvalidAttributeValueException("Expecting Map"); } } return(new Uid(_config.Guid.ToString())); }
public virtual ConnectorAttribute NormalizeAttribute(ObjectClass oclass, ConnectorAttribute attribute) { if (ConnectorAttributeUtil.NamesEqual(attribute.Name, Uid.NAME)) { return(new Uid(ConnectorAttributeUtil.GetStringValue(attribute).ToLower())); } return(attribute); }
public void Create(CreateOpContext context) { ExchangeConnector exconn = (ExchangeConnector)context.Connector; Command cmdNew = ExchangeUtility.GetCommand( new PSExchangeConnector.CommandInfo(GetNewCommandName()), context.Attributes, exconn.Configuration); try { context.Uid = _helper.InvokePipelineAndGetGuid(exconn, cmdNew); } catch (ProxyAddressExistsException e) { // This is a tricky exception. Sometimes when creating an object that is already there (e.g. DistributionGroup), // PowerShell reports "ProxyAddressExists" instead of something like "ObjectExists" :( // So we have to distinguish these situations somehow... Name nameAttribute = ConnectorAttributeUtil.GetNameFromAttributes(context.Attributes); if (nameAttribute == null || nameAttribute.Value == null || nameAttribute.Value.Count() != 1) { LOGGER.TraceEvent(TraceEventType.Information, CAT_DEFAULT, "ProxyAddressExistsException reported; but no single-valued NAME attribute present -- reporting as is"); throw new ConnectorException(e.Message, e); } String name = (String)nameAttribute.Value[0]; LOGGER.TraceEvent(TraceEventType.Information, CAT_DEFAULT, "ProxyAddressExistsException reported; trying to see if object named " + name + " exists"); Command cmdGet = ExchangeUtility.GetCommand( new PSExchangeConnector.CommandInfo(GetGetCommandName()), exconn.Configuration); cmdGet.Parameters.Add("Identity", name); ICollection <PSObject> objects; try { objects = _helper.InvokePipeline(exconn, cmdGet); } catch (ObjectNotFoundException e1) { objects = null; } if (objects == null || objects.Count == 0) { LOGGER.TraceEvent(TraceEventType.Information, CAT_DEFAULT, "...it does not -- reporting as is"); throw new ConnectorException(e.Message, e); } else { LOGGER.TraceEvent(TraceEventType.Information, CAT_DEFAULT, "...it exists -- reporting as AlreadyExistsException"); throw new AlreadyExistsException(e.Message, e); } } if (ExecuteSetAfterNew()) { Command cmdSet = ExchangeUtility.GetCommand( new PSExchangeConnector.CommandInfo(GetSetCommandName()), context.Attributes, context.Uid, exconn.Configuration); try { _helper.InvokePipeline(exconn, cmdSet); } catch { // TODO rollback // rethrow original exception throw; } } }
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); * } */ }
public ConnectorAttribute NormalizeAttribute(ObjectClass oclass, ConnectorAttribute attribute) { if (attribute.Is("foo")) { String val = ConnectorAttributeUtil.GetStringValue(attribute); return(ConnectorAttributeBuilder.Build("foo", val.Trim())); } else { return(attribute); } }
protected Uid ExecuteCreate(String scriptName, ObjectClass objectClass, ICollection <ConnectorAttribute> createAttributes, OperationOptions options) { var result = new MsPowerShellUidHandler(); var arguments = new Dictionary <String, Object> { { Result, result } }; if (ConnectorAttributeUtil.GetNameFromAttributes(createAttributes) != null) { arguments.Add(Id, ConnectorAttributeUtil.GetNameFromAttributes(createAttributes).GetNameValue()); } ExecuteScript(GetScript(scriptName), CreateBinding(arguments, OperationType.CREATE, objectClass, null, createAttributes, options)); return(result.Uid.GetUidValue() != null ? result.Uid : null); }
public void TestCaseInsensitiveMap() { HashSet <ConnectorAttribute> set = new HashSet <ConnectorAttribute>(); set.Add(ConnectorAttributeBuilder.Build("foo1")); set.Add(ConnectorAttributeBuilder.Build("foo2")); IDictionary <String, ConnectorAttribute> map = ConnectorAttributeUtil.ToMap(set); Assert.IsTrue(map.ContainsKey("Foo1")); Assert.IsTrue(map.ContainsKey("Foo2")); IDictionary <String, object> map2 = (IDictionary <String, object>)CloneObject(map); Assert.IsTrue(map2.ContainsKey("Foo1")); Assert.IsTrue(map2.ContainsKey("Foo2")); }
/// <summary> /// Helper method: Gets attribute value from the attribute collection /// </summary> /// <param name="attName">attribute name</param> /// <param name="attributes">collection of attribute</param> /// <returns>Attribute value as object, null if not found</returns> /// <exception cref="ArgumentNullException">If some of the params is null</exception> internal static object GetAttValue(string attName, ICollection <ConnectorAttribute> attributes) { Assertions.NullCheck(attName, "attName"); Assertions.NullCheck(attributes, "attributes"); object value = null; ConnectorAttribute attribute = ConnectorAttributeUtil.Find(attName, attributes); if (attribute != null) { value = ConnectorAttributeUtil.GetSingleValue(attribute) ?? string.Empty; } return(value); }
/// <summary> /// This will do a basic replace. /// </summary> /// /// <seealso cref="UpdateOp.Update"/> /// public Uid Update(ObjectClass objclass, Uid uid, ICollection <ConnectorAttribute> attrs, OperationOptions options) { string val = ConnectorAttributeUtil.GetAsStringValue(uid); int idx = Convert.ToInt32(val); //.Get out the object.. ConnectorObject baseObject = objects[idx]; ConnectorObjectBuilder bld = new ConnectorObjectBuilder(); bld.Add(baseObject); bld.AddAttributes(attrs); ConnectorObject obj = bld.Build(); objects[idx] = obj; return(obj.Uid); }
private IList <object> GetValuesSorted(ConnectorObject resource, string field) { ConnectorAttribute value = ConnectorAttributeUtil.Find(field, resource.GetAttributes()); if (value == null || value.Value == null || value.Value.Count == 0) { return(CollectionUtil.NullAsEmpty <object>(null)); } if (value.Value.Count > 1) { var results = new List <object>(value.Value); results.Sort(ValueComparator); return(results); } return(value.Value); }
/// <summary> /// Helper method: Sets attribute value in the attribute collection /// </summary> /// <param name="attName">attribute name</param> /// <param name="attValue">attribute value (if null, we will remove the attribute from the collection)</param> /// <param name="attributes">collection of attribute</param> /// <exception cref="ArgumentNullException">If some of the params is null</exception> internal static void SetAttValue(string attName, object attValue, ICollection <ConnectorAttribute> attributes) { Assertions.NullCheck(attName, "attName"); Assertions.NullCheck(attributes, "attributes"); ConnectorAttribute attribute = ConnectorAttributeUtil.Find(attName, attributes); if (attribute != null) { attributes.Remove(attribute); } if (attValue != null) { attributes.Add(ConnectorAttributeBuilder.Build(attName, new object[] { attValue })); } }
private static IDictionary <String, Object> CreateFilter(String operation, AttributeFilter filter, bool not) { IDictionary <String, Object> dic = new Dictionary <String, Object>(); var name = filter.GetAttribute().Name; var value = ConnectorAttributeUtil.GetStringValue(filter.GetAttribute()); if (StringUtil.IsBlank(value)) { return(null); } dic.Add(Not, not); dic.Add(Operation, operation); dic.Add(Left, name); dic.Add(Right, value); return(dic); }
/// <summary> /// This does not work ... for now, don't handle container changes /// </summary> /// <param name="type"></param> /// <param name="directoryEntry"></param> /// <param name="attributes"></param> /// <param name="config"></param> private static void HandleContainerChange(UpdateType type, DirectoryEntry directoryEntry, ICollection <ConnectorAttribute> attributes, ActiveDirectoryConfiguration config) { Name nameAttribute = ConnectorAttributeUtil.GetNameFromAttributes(attributes); if (nameAttribute == null) { // no name, so must not be a container change return; } if (!type.Equals(UpdateType.REPLACE)) { // this only make sense for replace. you can't // add a name or delete a name return; } String oldContainer = GetParentDn(directoryEntry.Path); String newContainer = GetParentDn(nameAttribute.GetNameValue()); if (!NormalizeLdapString(oldContainer).Equals(NormalizeLdapString(newContainer))) { if (newContainer != null) { try { if (!NormalizeLdapString(oldContainer).Equals( NormalizeLdapString(newContainer))) { String newContainerLdapPath = ActiveDirectoryUtils.GetLDAPPath( config.LDAPHostName, newContainer); DirectoryEntry newContainerDe = new DirectoryEntry(newContainerLdapPath, config.DirectoryAdminName, config.DirectoryAdminPassword); directoryEntry.MoveTo(newContainerDe); } } catch (Exception e) { throw e; } } } }
public virtual Uid Create(ObjectClass objectClass, ICollection <ConnectorAttribute> createAttributes, OperationOptions options) { if (ObjectClass.ACCOUNT.Equals(objectClass) || ObjectClass.GROUP.Equals(objectClass)) { Name name = ConnectorAttributeUtil.GetNameFromAttributes(createAttributes); if (name != null) { // do real create here return(new Uid(ConnectorAttributeUtil.GetStringValue(name).ToLower())); } throw new InvalidAttributeValueException("Name attribute is required"); } Trace.TraceWarning("Delete of type {0} is not supported", _configuration.ConnectorMessages.Format(objectClass.GetDisplayNameKey(), objectClass.GetObjectClassValue())); throw new NotSupportedException("Delete of type" + objectClass.GetObjectClassValue() + " is not supported"); }
public virtual void TestSearch2() { ConnectorFacade search = GetFacade(); for (int i = 0; i < 100; i++) { ICollection <ConnectorAttribute> co = GetTestCreateConnectorObject(string.Format("TEST{0:D5}", i)); co.Add(ConnectorAttributeBuilder.Build("sortKey", i)); search.Create(ObjectClass.ACCOUNT, co, null); } OperationOptionsBuilder builder = new OperationOptionsBuilder { PageSize = 10, SortKeys = new[] { new SortKey("sortKey", false) } }; SearchResult result = null; ICollection <ConnectorObject> resultSet = new HashSet <ConnectorObject>(); int pageIndex = 0; int index = 101; while ((result = search.Search(ObjectClass.ACCOUNT, FilterBuilder.StartsWith(ConnectorAttributeBuilder.Build(Name.NAME, "TEST")), new ResultsHandler() { Handle = connectorObject => { int?idx = ConnectorAttributeUtil.GetIntegerValue(connectorObject.GetAttributeByName("sortKey")); Assert.IsTrue(idx < index); if (idx != null) { index = (int)idx; } resultSet.Add(connectorObject); return(true); } }, builder.Build())).PagedResultsCookie != null) { builder = new OperationOptionsBuilder(builder.Build()) { PagedResultsCookie = result.PagedResultsCookie }; Assert.AreEqual(10 * ++pageIndex, resultSet.Count); } Assert.AreEqual(9, pageIndex); Assert.AreEqual(100, resultSet.Count); }
public void TestGetSingleValue() { object TEST_VALUE = 1L; ConnectorAttribute attr = ConnectorAttributeBuilder.Build("long", TEST_VALUE); object value = ConnectorAttributeUtil.GetSingleValue(attr); Assert.AreEqual(TEST_VALUE, value); // test null attr = ConnectorAttributeBuilder.Build("long"); value = ConnectorAttributeUtil.GetSingleValue(attr); Assert.IsNull(value); // test empty attr = ConnectorAttributeBuilder.Build("long", new List <object>()); value = ConnectorAttributeUtil.GetSingleValue(attr); Assert.IsNull(value); // test illegal argument exception ConnectorAttributeUtil.GetSingleValue(ConnectorAttributeBuilder.Build("bob", 1, 2, 3)); }
/// <summary> /// Helper method: Gets attribute values from the attribute collection /// </summary> /// <param name="attName">attribute name</param> /// <param name="attributes">collection of attribute</param> /// <returns>Attribute value as collection of objects, null if not found</returns> /// <exception cref="ArgumentNullException">If some of the params is null</exception> internal static IList <object> GetAttValues(string attName, ICollection <ConnectorAttribute> attributes) { Assertions.NullCheck(attName, "attName"); if (attributes == null) { return(null); } ConnectorAttribute attribute = ConnectorAttributeUtil.Find(attName, attributes); if (attribute != null) { return(attribute.Value); } else { return(null); } }
private static void HandleNameChange(UpdateType type, DirectoryEntry directoryEntry, ICollection <ConnectorAttribute> attributes) { Name nameAttribute = ConnectorAttributeUtil.GetNameFromAttributes(attributes); if (nameAttribute != null) { // this only make sense for replace. you can't // add a name or delete a name if (type.Equals(UpdateType.REPLACE)) { String oldName = directoryEntry.Name; String newName = GetRelativeName(nameAttribute); if (!NormalizeLdapString(oldName).Equals(NormalizeLdapString(newName))) { directoryEntry.Rename(newName); } } } }
/** * Get the LDAP name or names for a given connector attribute used in a * search filter. * * @param attr The connector attribute used in a search filter. * * @return The name or names of the corresponding LDAP attribute. * Returns null if the attribute cannot be specified in an LDAP * filter. */ protected virtual String[] GetLdapNamesForAttribute(ConnectorAttribute attr) { // Special processing for certain connector attributes. String[] attrNames = null; if (attr is Uid) { /* * attrNames = new String[] { * configCache.getConfiguration().getUuidAttribute() }; */ attrNames = new String[] { "objectGUID" }; } else if (attr is Name) { /* * attrNames = configCache.getNamingAttributes(); */ attrNames = new String [] { "distinguishedName" }; } else if (attr.Is(OperationalAttributes.PASSWORD_NAME)) { /* * attrNames = new String[] { * configCache.getConfiguration().getPasswordAttribute() * }; */ attrNames = new String[] { "userPassword" }; } else if (ConnectorAttributeUtil.IsSpecial(attr)) { return(null); } else { attrNames = new String[] { attr.Name }; } return(attrNames); }
public Uid Create(ObjectClass objClass, ICollection <ConnectorAttribute> attrs, OperationOptions options) { StringBuilder sb = new StringBuilder(); ConnectorAttribute NameAttribute = ConnectorAttributeUtil.Find(Name.NAME, attrs); if (NameAttribute == null) { throw new ConnectorException("The name operational attribute cannot be null"); } string parameter = ConnectorAttributeUtil.GetAsStringValue(NameAttribute); string[] login = parameter.Split('@'); PowerShell PowerShellInstance = PowerShell.Create(); PowerShellInstance.AddCommand(this.config.createScript + "create.ps1"); PowerShellInstance.AddArgument(login[0]); Collection <PSObject> results; Collection <ErrorRecord> errors; results = PowerShellInstance.Invoke(); errors = PowerShellInstance.Streams.Error.ReadAll(); if (errors.Count > 0) { foreach (ErrorRecord error in errors) { sb.AppendLine(error.ToString()); } throw new ConnectorException(sb.ToString()); } else { return(new Uid(ConnectorAttributeUtil.GetAsStringValue(NameAttribute))); } }
public void TestAttributeTypeMap() { ConnectorPoolManager.Dispose(); ConnectorInfoManager manager = GetConnectorInfoManager(); ConnectorInfo info1 = FindConnectorInfo(manager, "1.0.0.0", "org.identityconnectors.testconnector.TstStatefulConnector"); Assert.IsNotNull(info1); APIConfiguration config = info1.CreateDefaultAPIConfiguration(); config.ConnectorPoolConfiguration.MinIdle = 0; config.ConnectorPoolConfiguration.MaxIdle = 0; ConnectorFacade facade = ConnectorFacadeFactory.GetInstance().NewInstance(config); HashSet <ConnectorAttribute> createAttributes = new HashSet <ConnectorAttribute>(); IDictionary <string, object> mapAttribute = new Dictionary <string, object>(); mapAttribute["email"] = "*****@*****.**"; mapAttribute["primary"] = true; mapAttribute["usage"] = new List <String>() { "home", "work" }; createAttributes.Add(ConnectorAttributeBuilder.Build("emails", mapAttribute)); Uid uid = facade.Create(ObjectClass.ACCOUNT, createAttributes, null); Assert.AreEqual(uid.GetUidValue(), "*****@*****.**"); ConnectorObject co = facade.GetObject(ObjectClass.ACCOUNT, new Uid("0"), null); object value = ConnectorAttributeUtil.GetSingleValue(co.GetAttributeByName("emails")); Assert.IsTrue(value is IDictionary); Assert.IsTrue(((IDictionary)value)["usage"] is IList); }
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 command based on the commanf info, reading the calues from attributes /// </summary> /// <param name="cmdInfo">Command defition</param> /// <param name="attributes">Attribute values - UID in these is ignored! It should be passed as a separate parameter</param> /// <param name="config">Configuration object</param> /// <returns> /// Ready to execute Command /// </returns> /// <exception cref="ArgumentNullException">if some of the param is null</exception> internal static Command GetCommand(PSExchangeConnector.CommandInfo cmdInfo, ICollection <ConnectorAttribute> attributes, Uid uidAttribute, Name nameAttribute, ExchangeConfiguration config) { Assertions.NullCheck(cmdInfo, "cmdInfo"); LOG.Trace("GetCommand: cmdInfo name = {0}", cmdInfo.Name); ISet <string> parametersSet = new HashSet <string>(); // create command Command cmd = new Command(cmdInfo.Name); if (!string.IsNullOrEmpty(cmdInfo.UidParameter) && !parametersSet.Contains(cmdInfo.UidParameter)) { Uid uidAttr = uidAttribute != null ? uidAttribute : ConnectorAttributeUtil.GetUidAttribute(attributes); string uid = uidAttr != null?uidAttr.GetUidValue() : null; if (uid != null) { cmd.Parameters.Add(cmdInfo.UidParameter, ActiveDirectoryUtils.ConvertADGUIDtoObjectGUID(uid)); parametersSet.Add(cmdInfo.UidParameter); } } // map name attribute, if mapping specified if (!string.IsNullOrEmpty(cmdInfo.NameParameter) && !parametersSet.Contains(cmdInfo.NameParameter)) { Name nameAttr = nameAttribute != null ? nameAttribute : ConnectorAttributeUtil.GetNameFromAttributes(attributes); string name = nameAttr != null?nameAttr.GetNameValue() : null;; if (name != null) { cmd.Parameters.Add(cmdInfo.NameParameter, name); parametersSet.Add(cmdInfo.NameParameter); } } if (cmdInfo.UsesConfirm) { cmd.Parameters.Add("confirm", false); parametersSet.Add("confirm"); } if (cmdInfo.UsesDomainController) { cmd.Parameters.Add("DomainController", ActiveDirectoryUtils.GetDomainControllerName(config)); parametersSet.Add("DomainController"); } // TODO check this only for user-related operations bool emailAddressesPresent = GetAttValues(ExchangeConnectorAttributes.AttEmailAddresses, attributes) != null; bool primarySmtpAddressPresent = GetAttValues(ExchangeConnectorAttributes.AttPrimarySmtpAddress, attributes) != null; if (emailAddressesPresent && primarySmtpAddressPresent) { throw new ArgumentException(ExchangeConnectorAttributes.AttEmailAddresses + " and " + ExchangeConnectorAttributes.AttPrimarySmtpAddress + " cannot be both set."); } if (attributes != null) { foreach (string attName in cmdInfo.Parameters) { object valueToSet = null; ConnectorAttribute attribute = ConnectorAttributeUtil.Find(attName, attributes); if (attribute != null) { if (attribute.Value != null && attribute.Value.Count > 1) { List <string> stringValues = new List <string>(); foreach (object val in attribute.Value) { stringValues.Add(val.ToString()); } valueToSet = stringValues.ToArray(); } else { valueToSet = ConnectorAttributeUtil.GetSingleValue(attribute); } if (parametersSet.Contains(attName)) { throw new InvalidOperationException("Parameter " + attName + " is already defined for command " + cmdInfo.Name); } cmd.Parameters.Add(attName, valueToSet); parametersSet.Add(attName); } } } LOG.Trace("GetCommand exit: cmdInfo name = {0}", cmdInfo.Name); return(cmd); }
/// <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> /// </summary> /// <param name="type"></param> /// <param name="directoryEntry"></param> /// <param name="attributes"></param> /// <param name="config"></param> private static void HandleNameAndContainerChange(UpdateType type, DirectoryEntry directoryEntry, ICollection <ConnectorAttribute> attributes, ActiveDirectoryConfiguration config) { Name nameAttribute = ConnectorAttributeUtil.GetNameFromAttributes(attributes); if (nameAttribute == null) { // no name, so must not be a container change return; } if (!type.Equals(UpdateType.REPLACE)) { // this only make sense for replace. you can't // add a name or delete a name return; } String oldName = directoryEntry.Name; String newName = GetRelativeName(nameAttribute); bool nameChanged = !NormalizeLdapString(oldName).Equals(NormalizeLdapString(newName), StringComparison.OrdinalIgnoreCase); String oldContainer = GetParentDn(directoryEntry.Path); String newContainer = GetParentDn(nameAttribute.GetNameValue()); bool containerChanged = !NormalizeLdapString(oldContainer).Equals(NormalizeLdapString(newContainer), StringComparison.OrdinalIgnoreCase); if (!nameChanged && !containerChanged) { return; } if (nameChanged && !containerChanged) // rename without moving { LOGGER.TraceEvent(TraceEventType.Verbose, CAT_DEFAULT, "Renaming {0} to {1}", oldName, newName); directoryEntry.Rename(newName); LOGGER.TraceEvent(TraceEventType.Verbose, CAT_DEFAULT, "Rename OK"); return; } // so this is move with or without rename // step 1: if WITH rename, we have to rename the entry to a temporary name first String temporaryName = null; if (nameChanged) { temporaryName = oldName + "-" + RandomStr(); LOGGER.TraceEvent(TraceEventType.Verbose, CAT_DEFAULT, "Renaming {0} to a temporary name of {1}", oldName, temporaryName); directoryEntry.Rename(temporaryName); LOGGER.TraceEvent(TraceEventType.Verbose, CAT_DEFAULT, "Rename OK"); } // step 2: do the move try { String newContainerLdapPath = ActiveDirectoryUtils.GetLDAPPath(config.LDAPHostName, newContainer); DirectoryEntry newContainerDe = new DirectoryEntry(newContainerLdapPath, config.DirectoryAdminName, config.DirectoryAdminPassword); LOGGER.TraceEvent(TraceEventType.Verbose, CAT_DEFAULT, "Moving from {0} to {1} ({2})", oldContainer, newContainer, newContainerLdapPath); directoryEntry.MoveTo(newContainerDe); LOGGER.TraceEvent(TraceEventType.Verbose, CAT_DEFAULT, "Move OK"); newContainerDe.Dispose(); } catch (Exception e) { LOGGER.TraceEvent(TraceEventType.Information, CAT_DEFAULT, "Exception caught when moving: {0}", e); if (nameChanged) { LOGGER.TraceEvent(TraceEventType.Information, CAT_DEFAULT, "Renaming back from temporary name of {0} to {1}", temporaryName, oldName); directoryEntry.Rename(oldName); LOGGER.TraceEvent(TraceEventType.Verbose, CAT_DEFAULT, "Rename OK"); } throw e; } // step 3: if WITH rename, then rename from temporary name to the new name if (nameChanged) { LOGGER.TraceEvent(TraceEventType.Verbose, CAT_DEFAULT, "Renaming from temporary name of {0} to a new name of {1}", temporaryName, newName); directoryEntry.Rename(newName); LOGGER.TraceEvent(TraceEventType.Verbose, CAT_DEFAULT, "Rename OK"); } }
public void TestNamesEqual() { Assert.IsTrue(ConnectorAttributeUtil.NamesEqual("givenName", "givenname")); }
/// <summary> /// DeduplicatesEmailAddresses. /// - on REPLACE (i.e. update/replace or create) the situation is easy: we just remove duplicate entries (SMTP:x & smtp:x result in SMTP:x) /// - on DELETE we currently do nothing /// - on ADD we have one additional rule: /// "If we are adding SMTP:x, we first convert all SMTP:y in existing records to smtp:y because we see the intent of having x to be a new primary" /// /// </summary> /// <param name="context"></param> /// <param name="attributes">these are attributes to be set (already resolved if we have update of type ADD or DELETE)</param> /// <returns></returns> private ICollection <ConnectorAttribute> DeduplicateEmailAddresses(CreateUpdateOpContext context, ICollection <ConnectorAttribute> attributes) { // trivial cases if (context is UpdateOpContext && ((UpdateOpContext)context).UpdateType == UpdateType.DELETE) { return(attributes); } ConnectorAttribute attribute = ConnectorAttributeUtil.Find(ExchangeConnectorAttributes.AttEmailAddresses, attributes); if (attribute == null || attribute.Value == null) { return(attributes); // missing or empty EmailAddresses - nothing to deduplicate } ConnectorAttribute attributeDelta = ConnectorAttributeUtil.Find(ExchangeConnectorAttributes.AttEmailAddresses, context.Attributes); if (attributeDelta == null || attributeDelta.Value == null) { return(attributes); // missing or empty changed EmailAddresses - nothing to deduplicate } // now the main part IList <string> valuesToDeduplicate = new List <string>(); foreach (object o in attribute.Value) { if (o != null) { valuesToDeduplicate.Add(o.ToString()); } } bool changed = false; // special rule: if ADD with SMTP:, let us change all other "SMTP:x" to "smtp:x" Boolean isUpdateAdd = context is UpdateOpContext && ((UpdateOpContext)context).UpdateType == UpdateType.ADD; if (isUpdateAdd) { string newPrimary = null; foreach (object o in attributeDelta.Value) { if (((string)o).StartsWith("SMTP:")) { newPrimary = (string)o; break; } } if (newPrimary != null) { foreach (string address in new List <string>(valuesToDeduplicate)) // to eliminate concurrent access { if (address.StartsWith("SMTP:") && !address.Equals(newPrimary)) { string replacement = "smtp:" + address.Substring(5); LOGGER.TraceEvent(TraceEventType.Information, CAT_DEFAULT, "Changing duplicate primary-candidate address {0} to {1}", address, replacement); valuesToDeduplicate.Remove(address); valuesToDeduplicate.Add(replacement); changed = true; } } } } IDictionary <string, string> values = new Dictionary <string, string>(); // normalized->most-recent-original e.g. SMTP:[email protected] -> SMTP:[email protected] (if primary is present) foreach (object v in valuesToDeduplicate) { string address = (string)v; string normalized = address.ToUpper(); if (values.ContainsKey(normalized)) { changed = true; string existing = values[normalized]; if (address.StartsWith("SMTP:") && existing.StartsWith("smtp:")) { LOGGER.TraceEvent(TraceEventType.Information, CAT_DEFAULT, "Removing redundant address {0}, keeping {1}", existing, address); values[normalized] = address; } else { LOGGER.TraceEvent(TraceEventType.Information, CAT_DEFAULT, "Removing redundant address {0}, keeping {1}", address, existing); } } else { values.Add(normalized, address); } } if (changed) { ConnectorAttributeBuilder cab = new ConnectorAttributeBuilder(); cab.Name = ExchangeConnectorAttributes.AttEmailAddresses; foreach (string value in values.Values) { cab.AddValue(value); } ICollection <ConnectorAttribute> rv = new List <ConnectorAttribute>(attributes); // the original is (sometimes) a read-only collection rv.Remove(attribute); rv.Add(cab.Build()); return(rv); } else { return(attributes); } }
public Uid Update(ObjectClass objclass, Uid uid, ICollection <ConnectorAttribute> replaceAttributes, OperationOptions options) { StringBuilder sb = new StringBuilder(); PowerShell PowerShellInstance = PowerShell.Create(); ConnectorAttribute StatusAttribute = ConnectorAttributeUtil.Find(OperationalAttributes.ENABLE_NAME, replaceAttributes); String enable = ConnectorAttributeUtil.GetAsStringValue(StatusAttribute).ToLower(); string parameter = ConnectorAttributeUtil.GetAsStringValue(uid); string[] login = parameter.Split('@'); if (enable.Equals("false")) { PowerShellInstance.AddCommand(this.config.createScript + "disable.ps1"); PowerShellInstance.AddArgument(login[0]); Collection <PSObject> results; Collection <ErrorRecord> errors; results = PowerShellInstance.Invoke(); errors = PowerShellInstance.Streams.Error.ReadAll(); if (errors.Count > 0) { foreach (ErrorRecord error in errors) { sb.AppendLine(error.ToString()); } throw new ConnectorException(sb.ToString()); } else { return(uid); } } else if (enable.Equals("true")) { PowerShellInstance.AddCommand(this.config.createScript + "enable.ps1"); PowerShellInstance.AddArgument(login[0]); Collection <PSObject> results; Collection <ErrorRecord> errors; results = PowerShellInstance.Invoke(); errors = PowerShellInstance.Streams.Error.ReadAll(); if (errors.Count > 0) { foreach (ErrorRecord error in errors) { sb.AppendLine(error.ToString()); } throw new ConnectorException(sb.ToString()); } else { return(uid); } } else { return(uid); } }
public void Create(CreateOpContext context) { context.Attributes = DeduplicateEmailAddresses(context, context.Attributes); // get recipient type string rcptType = ExchangeUtility.GetAttValue(ExchangeConnectorAttributes.AttRecipientType, context.Attributes) as string; if (rcptType == null || rcptType.Equals("")) { rcptType = ExchangeConnectorAttributes.RcptTypeUser; } ExchangeConnector exconn = (ExchangeConnector)context.Connector; ActiveDirectoryConnector adconn = exconn.ActiveDirectoryConnector; PSExchangeConnector.CommandInfo cmdInfoEnable = null; PSExchangeConnector.CommandInfo cmdInfoSet = null; switch (rcptType) { case ExchangeConnectorAttributes.RcptTypeMailBox: cmdInfoEnable = PSExchangeConnector.CommandInfo.EnableMailbox; cmdInfoSet = PSExchangeConnector.CommandInfo.SetMailbox; break; case ExchangeConnectorAttributes.RcptTypeMailUser: cmdInfoEnable = PSExchangeConnector.CommandInfo.EnableMailUser; cmdInfoSet = PSExchangeConnector.CommandInfo.SetMailUser; break; case ExchangeConnectorAttributes.RcptTypeUser: break; default: throw new ArgumentException( context.ConnectorConfiguration.ConnectorMessages.Format( "ex_bad_rcpt", "Recipient type [{0}] is not supported", rcptType)); } // first create the object in AD ICollection <ConnectorAttribute> adAttributes = ExchangeUtility.FilterOut(context.Attributes, PSExchangeConnector.CommandInfo.EnableMailbox, PSExchangeConnector.CommandInfo.SetMailbox, PSExchangeConnector.CommandInfo.EnableMailUser, PSExchangeConnector.CommandInfo.SetMailUser); Uid uid = adconn.Create(context.ObjectClass, adAttributes, context.Options); if (rcptType == ExchangeConnectorAttributes.RcptTypeUser) { // AD account only, we do nothing context.Uid = uid; return; } // add a empty "EmailAddresses" attribute if needed (address policy is disabled and no addresses are provided) ICollection <ConnectorAttribute> enhancedAttributes; ConnectorAttribute policyEnabledAttribute = ConnectorAttributeUtil.Find(ExchangeConnectorAttributes.AttEmailAddressPolicyEnabled, context.Attributes); if (policyEnabledAttribute != null && ConnectorAttributeUtil.GetBooleanValue(policyEnabledAttribute).HasValue&& ConnectorAttributeUtil.GetBooleanValue(policyEnabledAttribute).Value == false && ConnectorAttributeUtil.Find(ExchangeConnectorAttributes.AttPrimarySmtpAddress, context.Attributes) == null && ConnectorAttributeUtil.Find(ExchangeConnectorAttributes.AttEmailAddresses, context.Attributes) == null) { enhancedAttributes = new HashSet <ConnectorAttribute>(context.Attributes); enhancedAttributes.Add(ConnectorAttributeBuilder.Build(ExchangeConnectorAttributes.AttEmailAddresses)); LOGGER.TraceEvent(TraceEventType.Verbose, CAT_DEFAULT, "Added empty EmailAddresses attribute because address policy use is disabled and no addresses were provided"); } else { enhancedAttributes = context.Attributes; // no change } // prepare the command Command cmdEnable = ExchangeUtility.GetCommand(cmdInfoEnable, enhancedAttributes, uid, (ExchangeConfiguration)context.ConnectorConfiguration); Command cmdSet = ExchangeUtility.GetCommand(cmdInfoSet, enhancedAttributes, uid, (ExchangeConfiguration)context.ConnectorConfiguration); try { _helper.InvokePipeline(exconn, cmdEnable); _helper.InvokePipeline(exconn, cmdSet); } catch { LOGGER.TraceEvent(TraceEventType.Information, CAT_DEFAULT, "Rolling back AD create for UID: " + uid.GetUidValue()); // rollback AD create try { adconn.Delete(context.ObjectClass, uid, context.Options); } catch { LOGGER.TraceEvent(TraceEventType.Warning, CAT_DEFAULT, "Not able to rollback AD create for UID: " + uid.GetUidValue()); // note: this is not perfect, we hide the original exception throw; } // rethrow original exception throw; } context.Uid = uid; }