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¶
- Create — construct a new EXTERNAL directory entry.
AddNewUserinstantiatesNew SAIF.DirectoryServices.clsUser("EXTERNAL")and immediately replaces it with the factory-produced object fromclsUser.FactoryGetObject(m_DirUser.m_DirEntry). - Update — locate the existing entry first.
- Switch active user context is invoked via
LoadThisUser(inUserStructure.userID)to resolve and bindm_DirUserto the account being updated. - If the user is not found:
UpdateUserreturnsFalseimmediately and performs no field mapping. - Map the shared field set onto
m_DirUser. Both methods copy the same fields fromUserStructureonto the directory entry:MailID,IDNumber,FirstName, thesn(last name) property directly onm_DirEntry,Title,Company,Email,PhoneNumber,FaxNumber, andStreetAddress. - Record the actor.
AddNewUsersetsDivisiontoinCreatedBy.UpdateUsersetsCommenttoinUpdatedBy.- Set the test-user flag. Both methods set
Descriptionto"Y"whenUserStructure.isTestUseris true, or"N"otherwise, so the flag is recoverable later through theTestUserproperty (BR-012). - Apply the password.
AddNewUseralways invokesDirectoryEntry.Invoke("SetPassword", .password)and commits, unconditionally setting the password on the new account.UpdateUseronly invokesSetPasswordand commits.password.Length > 0— an empty password on the input structure leaves the existing AD password untouched.- Commit the changes. Both methods call
m_DirUser.m_DirEntry.CommitChanges()after setting the password (inside the same conditional block forUpdateUser). - Return the outcome.
AddNewUserreturns the localisOkayvariable, which is declared but never assigned a value anywhere in the method body — it is alwaysFalseon the success path, regardless of whether the directory writes succeeded.*UpdateUserreturns theisOkayvalue produced by theLoadThisUsercall in step 2 —Truewhen the user was found and the subsequent field mapping executed,Falseonly 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¶
AddNewUseralways returnsFalsebecause itsisOkayresult 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.*AddNewUserperforms no existence check before creating a new directory entry, so calling it with aUserIDthat 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 emptypasswordfield 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.
Related documentation¶
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