Architecture¶
ADUserServices is a single-class, single-layer ASMX service: the codebehind is simultaneously the transport contract, the authorization gate, and the Active Directory data-access layer. There is no domain layer, no repository, no service/handler class, and no interface anywhere in the project.
Hosting model¶
The web service runs in IIS. The clsADUserServices.asmx marker file names the codebehind class ADUserServices.clsADUserServices, which inherits System.Web.Services.WebService; ASP.NET creates an instance per request. The marker-file detail is on Activation and hosting; this page covers what happens once a request is dispatched.
| Aspect | Finding |
|---|---|
| Host | IIS (ASP.NET System.Web.Services) |
| Application class | None — no Global.asax exists anywhere in the repository |
| Startup work | None |
| Service base class | System.Web.Services.WebService |
| Instance lifetime | One instance per request (ASP.NET default) |
| Target framework | .NET Framework v4.6.2 |
| Language | VB.NET |
There is no constructor in the codebehind, so no per-request side work runs at instantiation — no log file is opened, no configuration is read, nothing is cached. log4net 2.0.5 is referenced by the project but never initialized or called anywhere in source (a dead reference).
Request path¶
The following diagram visualizes how a caller reaches an operation.
flowchart TD
CALLER["SOAP caller"] --> IIS["IIS + ASP.NET"]
IIS --> ASMX["clsADUserServices.asmx<br>WebService directive"]
ASMX --> CTOR["clsADUserServices constructed<br>per request, no constructor work"]
CTOR --> OPER["WebMethod invoked<br>clsADUserServices.OperationName"]
OPER --> GATE{"IP allow-list gate<br>CheckAccess / mutating ops only"}
GATE -->|"8 mutating operations"| MUT["Mutating AD operation"]
GATE -->|"11 read operations<br>bypass the gate"| READ["Read-only AD query"]
ENV["WebEnvironmentService<br>environment settings store"] --> GATE
MUT --> ADEXT["Active Directory<br>external.saif.com writes"]
READ --> ADEXT2["Active Directory<br>external.saif.com reads"]
READ --> ADINT["Active Directory<br>corp.saif.com reads"]
MUT --> DS["System.DirectoryServices /<br>System.DirectoryServices.AccountManagement"]
READ --> DS
Layer responsibilities¶
| Layer | Type | Responsibility |
|---|---|---|
clsADUserServices.asmx |
@WebService directive |
Maps the request address to the codebehind class |
ADUserServices.clsADUserServices |
System.Web.Services.WebService |
Message handling, authorization gating, and direct Active Directory access — all in one class |
No helper/manager, repository/DAO, or embedded library exists; all directory access is concentrated in three private helpers (GetContext, GetUserPrincipal, GetGroupPrincipal) called from every operation, which is the one consistent seam in the design.
Service declaration¶
| Service class | Attribute | Value |
|---|---|---|
clsADUserServices |
<WebService(Namespace:="http://tempuri.org/")> |
http://tempuri.org/ |
clsADUserServices |
<WebServiceBinding(ConformsTo:=WsiProfiles.BasicProfile1_1)> |
WsiProfiles.BasicProfile1_1 |
clsADUserServices |
<ToolboxItem(False)> |
Present |
clsADUserServices |
<System.Web.Script.Services.ScriptService()> |
Commented out (not active) |
clsADUserServices |
Inherits |
System.Web.Services.WebService |
Shared process state¶
No process-wide shared or Shared/static state exists on this class. Only four per-request private instance fields are declared, none of which is Shared: m_CredUserId and m_CredPass are declared but never assigned or read anywhere in the codebehind (dead fields); m_FoundUser is written once (in DoesUserHaveResource) and never subsequently read; m_LastMessage captures directory-failure detail inside the private helpers (GetContext, GetUserPrincipal, GetGroupPrincipal) but is never returned to a caller or logged. Because every field is per-request instance state, no data survives between requests, no state is shared across concurrent callers, and nothing is lost on an application-pool recycle beyond the current in-flight request. This is recorded as a positive finding: there is no unsynchronized shared-state correctness or capacity risk of the kind seen in other ASMX hosts.
Design constraints¶
- Every mutating operation hard-wires the external domain (
inExternalDomain = Trueimplicitly, via the repeated authored comment'Assume external domain - NetSec will NOT use this); there is no parameter to target the internal domain for writes. GetUserPrinterhard-wires the internal domain for its single read (authored comment'Assume internal domain) and offers no domain parameter.- Three operations deviate from the
ADServiceResponsesentinel convention used by the rest of the contract:HelloWorldreturns a bareString,DoesUserExistreturns a bareBoolean, andGetUserGroups/GetUserResourcesreturn an untypedArrayList— so the contract carries four different response shapes for what is otherwise one pattern. - The declared
WsiProfiles.BasicProfile1_1conformance sits uncomfortably with the untypedArrayListreturns (serialized as unconstrainedanyTypearrays) and with thePublic Structuremessage types whose fields, not properties, form the message body.
Integration points¶
| System | Type | Purpose |
|---|---|---|
Active Directory (external.saif.com, container DC=external,DC=saif,DC=com) |
Directory service | External-domain account provisioning, deletion, unlock, group membership, and attribute reads, via System.DirectoryServices/System.DirectoryServices.AccountManagement |
Active Directory (corp.saif.com, container DC=corp,DC=saif,DC=com) |
Directory service | Internal-domain attribute and membership reads only; the container constant is declared but never passed to GetContext, so internal-domain contexts are always built without a container |
WebEnvironmentService (SAIF.Framework.Security, from SAIF.BOF.Framework) |
Configuration/environment service | Reads the aduserservices.allowedips setting consumed by the CheckAccess gate |
No database, message queue, or downstream SOAP service is integrated anywhere in this codebase.
Related documentation¶
- Service index
- Overview
- Activation and hosting
- Operations
- Faults and error pipeline
- Authentication and authorization
- Dependencies
- Configuration
- Operations and processes
- Business rules
- Operational runbook
- Tech debt
Sources¶
src\ADUserServices\clsADUserServices.asmx.vb.saifdocgen\state\runs\20260922-101326-aduserservices\analysis\aduserservices-analysis.md