internal ConnectorObject GetCurrentObject(UpdateOpContext context, string query) { ConnectorObject currentObject = null; LOG.Trace("Fetching object using query {0}", query); ResultsHandler handler = new ResultsHandler() { Handle = cobject => { //LOGGER.TraceEvent(TraceEventType.Verbose, CAT_DEFAULT, "Object-to-be-modified: {0}", CommonUtils.DumpConnectorAttributes(cobject.GetAttributes())); if (currentObject != null) { throw new InvalidOperationException("More than one object complying with " + query + " was found"); } currentObject = cobject; return(true); } }; ((ExchangeConnector)context.Connector).ExecuteQuery(context.ObjectClass, query, handler, null); if (currentObject == null) { throw new ObjectNotFoundException("Object with UID " + context.Uid.GetUidValue() + " was not found"); } return(currentObject); }
public void Update(UpdateOpContext context) { ExchangeConnector exconn = (ExchangeConnector)context.Connector; ActiveDirectoryConnector adconn = exconn.ActiveDirectoryConnector; adconn.Update(context.UpdateType, context.ObjectClass, context.Uid, context.Attributes, context.Options); }
public void UpdateMain(UpdateOpContext context) { Stopwatch stopWatch = new Stopwatch(); stopWatch.Start(); GetHandler(context).Update(context); LOG.Info("Exchange.Update method exiting, took {0} ms", stopWatch.ElapsedMilliseconds); }
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 void UpdateMain(UpdateOpContext context) { Stopwatch stopWatch = new Stopwatch(); stopWatch.Start(); GetHandler(context).Update(context); LOGGER_API.TraceEvent(TraceEventType.Information, CAT_DEFAULT, "Exchange.Update method exiting, took {0} ms", stopWatch.ElapsedMilliseconds); }
public Uid Update(UpdateType updateType, ObjectClass oclass, Uid uid, ICollection <ConnectorAttribute> attributes, OperationOptions options) { const string operation = "Update"; ExchangeUtility.NullCheck(updateType, "updateType", this._configuration); ExchangeUtility.NullCheck(oclass, "oclass", this._configuration); ExchangeUtility.NullCheck(uid, "uid", this._configuration); ExchangeUtility.NullCheck(attributes, "attributes", this._configuration); LOG.Info("Exchange.Update method; oclass = {0}, uid = {1}, type = {2}, attributes:\n{3}", oclass, uid, updateType, CommonUtils.DumpConnectorAttributes(attributes)); if (attributes == null || attributes.Count == 0) { LOG.Info("Returning immediately, as there are no attributes to modify."); return(uid); } String database = (String)ExchangeUtility.GetAttValue("Database", attributes); LOG.Info("Database attribute before plugins call: " + database); plugins.OnBeforeUpdate(oclass, uid, attributes, options, _configuration); database = (String)ExchangeUtility.GetAttValue("Database", attributes); LOG.Info("Database attribute after plugins call: " + database); UpdateOpContext context = new UpdateOpContext() { UpdateType = updateType, Attributes = attributes, Connector = this, ConnectorConfiguration = this._configuration, ObjectClass = oclass, OperationName = operation, Options = options, Uid = uid }; try { _scripting.ExecutePowerShell(context, Scripting.Position.BeforeMain); if (!_scripting.ExecutePowerShell(context, Scripting.Position.InsteadOfMain)) { UpdateMain(context); } _scripting.ExecutePowerShell(context, Scripting.Position.AfterMain); return(context.Uid); } catch (Exception e) { LOG.Error(e, "Exception while executing Update operation: {0}"); throw; } }
public ICollection <ConnectorAttribute> DetermineNewAttributeValues(UpdateOpContext context, string query) { ConnectorObject originalObject; if (context.UpdateType != UpdateType.REPLACE) { originalObject = GetCurrentObject(context, query); } else { originalObject = null; // not necessary here } return(DetermineNewAttributeValues(context, originalObject)); }
public void Update(UpdateOpContext context) { ExchangeConnector exconn = (ExchangeConnector)context.Connector; ICollection <ConnectorAttribute> attributesForReplace = _helper.DetermineNewAttributeValues(context, context.Uid.GetUidValue()); // query string is the UID value! Command cmdSet = ExchangeUtility.GetCommand( new PSExchangeConnector.CommandInfo(GetSetCommandName()), attributesForReplace, context.Uid, exconn.Configuration); try { _helper.InvokePipeline(exconn, cmdSet); } catch (ObjectNotFoundException e) { throw new UnknownUidException("Object with UID " + context.Uid.GetUidValue() + " couldn't be modified", e); } }
public Uid Update(UpdateType updateType, ObjectClass oclass, Uid uid, ICollection <ConnectorAttribute> attributes, OperationOptions options) { const string operation = "Update"; ExchangeUtility.NullCheck(updateType, "updateType", this._configuration); ExchangeUtility.NullCheck(oclass, "oclass", this._configuration); ExchangeUtility.NullCheck(uid, "uid", this._configuration); ExchangeUtility.NullCheck(attributes, "attributes", this._configuration); LOGGER_API.TraceEvent(TraceEventType.Information, CAT_DEFAULT, "Exchange.Update method; oclass = {0}, uid = {1}, type = {2}, attributes:\n{3}", oclass, uid, updateType, CommonUtils.DumpConnectorAttributes(attributes)); if (attributes == null || attributes.Count == 0) { LOGGER_API.TraceEvent(TraceEventType.Information, CAT_DEFAULT, "Returning immediately, as there are no attributes to modify."); return(uid); } UpdateOpContext context = new UpdateOpContext() { UpdateType = updateType, Attributes = attributes, Connector = this, ConnectorConfiguration = this._configuration, ObjectClass = oclass, OperationName = operation, Options = options, Uid = uid }; try { _scripting.ExecutePowerShell(context, Scripting.Position.BeforeMain); if (!_scripting.ExecutePowerShell(context, Scripting.Position.InsteadOfMain)) { UpdateMain(context); } _scripting.ExecutePowerShell(context, Scripting.Position.AfterMain); return(context.Uid); } catch (Exception e) { LOGGER.TraceEvent(TraceEventType.Error, CAT_DEFAULT, "Exception while executing Update operation: {0}", e); throw; } }
// 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)) { LOG.Warn("Trying to add value from " + attribute.Name + " that is already there: " + item); } else { newValues.Add(item); changed = true; } } else { if (!newValues.Contains(item)) { LOG.Warn("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 void Update(UpdateOpContext context) { ExchangeConnector exconn = (ExchangeConnector)context.Connector; ActiveDirectoryConnector adconn = exconn.ActiveDirectoryConnector; // update in AD first var filtered = ExchangeUtility.FilterOut( context.Attributes, PSExchangeConnector.CommandInfo.EnableMailbox, PSExchangeConnector.CommandInfo.EnableMailUser, PSExchangeConnector.CommandInfo.SetMailbox, PSExchangeConnector.CommandInfo.SetMailUser); adconn.Update(context.UpdateType, context.ObjectClass, context.Uid, filtered, context.Options); // retrieve Exchange-related information about the user string query = "(objectGUID=" + ActiveDirectoryUtils.ConvertUIDToSearchString(context.Uid) + ")"; ConnectorObject currentObject = _helper.GetCurrentObject(context, query); ICollection <ConnectorAttribute> attributesForReplace = _helper.DetermineNewAttributeValues(context, currentObject); attributesForReplace = DeduplicateEmailAddresses(context, attributesForReplace); string origRcptType; var newRcptType = _helper.DetermineOrigAndNewAttributeValue(context, currentObject, attributesForReplace, ExchangeConnectorAttributes.AttRecipientType, out origRcptType); if (newRcptType == null) { newRcptType = ExchangeConnectorAttributes.RcptTypeUser; } string origDatabase; var newDatabase = _helper.DetermineOrigAndNewAttributeValue(context, currentObject, attributesForReplace, ExchangeConnectorAttributes.AttDatabase, out origDatabase); // PART 1 - DEALING WITH MailUser CASE if (ExchangeConnectorAttributes.RcptTypeMailUser.Equals(newRcptType)) { // disabling Mailbox if needed if (ExchangeConnectorAttributes.RcptTypeMailBox.Equals(origRcptType)) { Command cmdDisable = ExchangeUtility.GetCommand(PSExchangeConnector.CommandInfo.DisableMailbox, attributesForReplace, context.Uid, exconn.Configuration); cmdDisable.Parameters.Add("Confirm", false); _helper.InvokePipeline(exconn, cmdDisable); } // enabling MailUser if needed if (!ExchangeConnectorAttributes.RcptTypeMailUser.Equals(origRcptType)) { // Enable-MailUser needs the value of ExternalEmailAddress, so we have to get it string origExternalEmailAddress; var newExternalEmailAddress = _helper.DetermineOrigAndNewAttributeValue(context, currentObject, attributesForReplace, ExchangeConnectorAttributes.AttExternalEmailAddress, out origExternalEmailAddress); if (String.IsNullOrEmpty(newExternalEmailAddress)) { throw new InvalidOperationException("Missing ExternalEmailAddress value, which is required for a MailUser"); } ExchangeUtility.SetAttValue(ExchangeConnectorAttributes.AttExternalEmailAddress, newExternalEmailAddress, attributesForReplace); // now execute the Enable-MailUser command Command cmdEnable = ExchangeUtility.GetCommand( PSExchangeConnector.CommandInfo.EnableMailUser, attributesForReplace, context.Uid, exconn.Configuration); _helper.InvokePipeline(exconn, cmdEnable); } // setting MailUser attributes Command cmdSet = ExchangeUtility.GetCommand(PSExchangeConnector.CommandInfo.SetMailUser, attributesForReplace, context.Uid, exconn.Configuration); _helper.InvokePipeline(exconn, cmdSet); } // PART 2 - DEALING WITH UserMailbox CASE else if (ExchangeConnectorAttributes.RcptTypeMailBox.Equals(newRcptType)) { // enable mailbox if necessary // we should execute something like this here: // get-user -identity id|?{$_.RecipientType -eq "User"}|enable-mailbox -database "db" // unfortunately I was not able to get it working with the pipeline... that's why there are two commands // executed :-( // alternatively there can be something like: // get-user -identity id -RecipientTypeDetails User|enable-mailbox -database "db", but we have then trouble // with detecting attempt to change the database attribute if (!ExchangeConnectorAttributes.RcptTypeMailBox.Equals(origRcptType)) { Command cmdEnable = ExchangeUtility.GetCommand(PSExchangeConnector.CommandInfo.EnableMailbox, attributesForReplace, context.Uid, exconn.Configuration); _helper.InvokePipeline(exconn, cmdEnable); } else { // are we trying to update the database? if (newDatabase != null && origDatabase != null && !newDatabase.Equals(origDatabase)) { throw new ArgumentException( context.ConnectorConfiguration.ConnectorMessages.Format( "ex_not_updatable", "Update of [{0}] attribute is not supported", ExchangeConnectorAttributes.AttDatabase)); } } Command cmdSet = ExchangeUtility.GetCommand(PSExchangeConnector.CommandInfo.SetMailbox, attributesForReplace, context.Uid, exconn.Configuration); _helper.InvokePipeline(exconn, cmdSet); } // PART 3 - DEALING WITH User CASE else if (ExchangeConnectorAttributes.RcptTypeUser.Equals(newRcptType)) { if (ExchangeConnectorAttributes.RcptTypeMailBox.Equals(origRcptType)) { Command cmdDisable = ExchangeUtility.GetCommand(PSExchangeConnector.CommandInfo.DisableMailbox, attributesForReplace, context.Uid, exconn.Configuration); cmdDisable.Parameters.Add("Confirm", false); _helper.InvokePipeline(exconn, cmdDisable); } else if (ExchangeConnectorAttributes.RcptTypeMailUser.Equals(origRcptType)) { Command cmdDisable = ExchangeUtility.GetCommand(PSExchangeConnector.CommandInfo.DisableMailUser, attributesForReplace, context.Uid, exconn.Configuration); cmdDisable.Parameters.Add("Confirm", false); _helper.InvokePipeline(exconn, cmdDisable); } else if (ExchangeConnectorAttributes.RcptTypeUser.Equals(origRcptType)) { // if orig is User, there is no need to disable anything } else { throw new InvalidOperationException("Invalid original recipient type: " + origRcptType); } Command cmdSet = ExchangeUtility.GetCommand(PSExchangeConnector.CommandInfo.SetUser, attributesForReplace, context.Uid, exconn.Configuration); _helper.InvokePipeline(exconn, cmdSet); } else { // unsupported rcpt type throw new ArgumentException( context.ConnectorConfiguration.ConnectorMessages.Format( "ex_bad_rcpt", "Recipient type [{0}] is not supported", newRcptType)); } }