Skip to content

Create or update an external user

AddNewUser and UpdateUser are the library's two account-CRUD writers. Both map the same UserStructure fields onto a clsUser directory entry, both derive the AD Description attribute from the test-user flag, and both optionally push a new password through DirectoryEntry.Invoke("SetPassword", ...). They are documented together because they share this field-mapping and test-user-flag logic and are governed by the same rule; AddNewUser additionally constructs a brand-new EXTERNAL-domain directory entry first, and UpdateUser additionally locates the existing entry first and only changes the password when one was supplied.

Field Value
Operation ID OP-SU-04
Trigger AddNewUser(inUserStructure, inCreatedBy) for a new account; UpdateUser(inUserStructure, inUpdatedBy) for an existing account
Inputs UserStructure (user ID, password, ID number, first/last name, company, job title, phone, fax, email, address, test-user flag); actor ID (inCreatedBy / inUpdatedBy)
Outputs Boolean result; created or updated AD directory entry with mapped attributes and optional new password
Primary components clsSystemUser.AddNewUser(...), clsSystemUser.UpdateUser(...), clsSystemUser.LoadThisUser(...)
Entry point Business\SAIF.Business.Security.SystemUser\clsSystemUser.vb

Steps

  1. Create — construct a new EXTERNAL directory entry. AddNewUser instantiates New SAIF.DirectoryServices.clsUser("EXTERNAL") and immediately replaces it with the factory-produced object from clsUser.FactoryGetObject(m_DirUser.m_DirEntry).
  2. Update — locate the existing entry first.
  3. Switch active user context is invoked via LoadThisUser(inUserStructure.userID) to resolve and bind m_DirUser to the account being updated.
  4. If the user is not found: UpdateUser returns False immediately and performs no field mapping.
  5. Map the shared field set onto m_DirUser. Both methods copy the same fields from UserStructure onto the directory entry: MailID, IDNumber, FirstName, the sn (last name) property directly on m_DirEntry, Title, Company, Email, PhoneNumber, FaxNumber, and StreetAddress.
  6. Record the actor.
  7. AddNewUser sets Division to inCreatedBy.
  8. UpdateUser sets Comment to inUpdatedBy.
  9. Set the test-user flag. Both methods set Description to "Y" when UserStructure.isTestUser is true, or "N" otherwise, so the flag is recoverable later through the TestUser property (BR-012).
  10. Apply the password.
  11. AddNewUser always invokes DirectoryEntry.Invoke("SetPassword", .password) and commits, unconditionally setting the password on the new account.
  12. UpdateUser only invokes SetPassword and commits .password.Length > 0 — an empty password on the input structure leaves the existing AD password untouched.
  13. Commit the changes. Both methods call m_DirUser.m_DirEntry.CommitChanges() after setting the password (inside the same conditional block for UpdateUser).
  14. Return the outcome.
  15. AddNewUser returns the local isOkay variable, which is declared but never assigned a value anywhere in the method body — it is always False on the success path, regardless of whether the directory writes succeeded.*
  16. UpdateUser returns the isOkay value produced by the LoadThisUser call in step 2 — True when the user was found and the subsequent field mapping executed, False only when the user lookup failed.

Process flow

The following diagram visualizes this operation's control flow across both entry points.

flowchart TD
    Start([Caller invokes AddNewUser or UpdateUser]) --> Which{Which entry point?}
    Which -->|AddNewUser| NewEntry[Construct new EXTERNAL clsUser via factory]
    Which -->|UpdateUser| Load[LoadThisUser by UserStructure.userID]
    Load --> Found{User found?}
    Found -->|No| Fail([Return False; no mapping applied])
    Found -->|Yes| Map
    NewEntry --> Map[Map shared UserStructure fields onto m_DirUser]
    Map --> Actor[Record actor: Division or Comment]
    Actor --> TestFlag[Set Description from isTestUser flag]
    TestFlag --> PwdCheck{Password supplied?}
    PwdCheck -->|AddNewUser: always| SetPwd[Invoke SetPassword]
    PwdCheck -->|UpdateUser: only if length > 0| SetPwd
    PwdCheck -->|UpdateUser: empty password| Commit
    SetPwd --> Commit[CommitChanges]
    Commit --> ReturnAdd{Which entry point?}
    ReturnAdd -->|AddNewUser| RetFalse([Return isOkay - always False*])
    ReturnAdd -->|UpdateUser| RetTrue([Return isOkay - True])

Failure and edge-case behavior

  • AddNewUser always returns False because its isOkay result variable is never assigned on any path; callers relying on the return value cannot distinguish a successful account creation from a failed one through this method's result alone.*
  • AddNewUser performs no existence check before creating a new directory entry, so calling it with a UserID that already exists depends entirely on how the underlying AD write and factory call behave for a duplicate — no explicit duplicate-detection logic exists in this method.*
  • UpdateUser's password branch means submitting an update with an empty password field is the supported way to leave the AD password unchanged; there is no separate "don't touch the password" flag.
  • Neither method validates the mapped field values (e.g., email format, phone format) before writing them to Active Directory.

Note: Statements marked with * were inferred from code structure, naming conventions, or contextual evidence where direct confirmation was not available in source artifacts.

Sources

  • Business\SAIF.Business.Security.SystemUser\clsSystemUser.vb