Documentation
¶
Overview ¶
Package ad integrates Active Directory as a service-task connector: a BPMN AD connector task performs an AD-specific provisioning operation — create a user, set a password, enable or disable an account, or add/remove a group member — against a model-authored server through the job path (ADR-0166), the same seam the ldap package uses (ADR-0154). AD speaks LDAP, so this connector dials and binds exactly like the generic LDAP connector; it exists because AD expresses those operations through mechanisms the generic connector cannot: a password is the binary `unicodePwd` attribute (UTF-16LE, quote-wrapped, LDAPS only), an account's enabled/disabled state is a bit in `userAccountControl` (a read-modify-write), and group membership is an *incremental* add/delete of a `member` value rather than a whole-attribute replace.
It inherits the job protocol's durability and non-blocking properties (ADR-0007): the processor creates a job carrying compiler.AdJobType and never talks to AD itself; the in-process Handler pulls the job, dials/binds/operates/closes off the run loop and after fsync, and completes it. The server URL and DNs live in the model as literal-or-FEEL values; the bind password is a server-side secret reference (ADR-0041). Every call is bounded by the shared connector budget (nettimeout.Default, ADR-0149). Delivery is at-least-once, so an operation must tolerate a replay.
Index ¶
- func Handler(store state.Reader, lookup ProcessLookup, dialer Dialer, secret SecretResolver) job.OutputHandler
- func Run(_ context.Context, j Job, dialer Dialer, secret SecretResolver) (map[string]any, error)
- type Conn
- type Dialer
- type DirSyncRequest
- type DirSyncResult
- type Entry
- type GoDialer
- type Job
- type Mod
- type ProcessLookup
- type SecretResolver
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func Handler ¶
func Handler(store state.Reader, lookup ProcessLookup, dialer Dialer, secret SecretResolver) job.OutputHandler
Handler builds a job handler that performs an Active Directory connector task. Register it with a job.Runner under the reserved compiler.AdJobTypeIndex via HandleWithOutput; the runner then pulls activatable AD jobs, and for each the handler resolves the task's url / bind DN / operation / DNs from the compiled process, dials and binds through dialer — evaluating any FEEL values over the instance's variables (ADR-0067) and resolving the bind password from a secret reference (ADR-0041) — and performs the operation. Returning an error fails the job (retry, then an incident, ADR-0061); the runner completes it only on success.
func Run ¶
Run performs a resolved job: it resolves the bind password from the caller's own secret store, dials and binds, performs the operation, and closes. It is the whole of the worker's half, and the in-process path calls it too, so there is one definition of what a resolved AD task means rather than two that drift.
Types ¶
type Conn ¶
type Conn interface {
// Add creates an entry with the given attributes.
Add(dn string, attrs map[string][]string) error
// Modify applies the change operations to an existing entry.
Modify(dn string, mods []Mod) error
// ReadAttr returns one attribute's values for an entry (a base-object read), used
// for the userAccountControl read-modify-write. Missing → an empty slice, no error.
ReadAttr(dn, attr string) ([]string, error)
// ModifyDN moves and/or renames an entry. In a directory those are one operation:
// an entry's place in the tree *is* its name, so a mover is a DN change.
ModifyDN(dn, newRDN, newSuperior string) error
// Delete removes an entry. AD refuses to delete a container that still has
// children, which is the behaviour a leaver process wants.
Delete(dn string) error
// DirSync reads what changed under a naming context since a cookie. It is the one
// read this connector does — search stays with the generic LDAP connector — and it
// is here because DirSync is Active Directory's own mechanism, not LDAP's.
DirSync(req DirSyncRequest) (DirSyncResult, error)
Close() error
}
Conn is a bound AD connection the worker operates over and then closes. It is an interface so the worker is testable without a live directory.
type Dialer ¶
Dialer opens and binds an AD connection. It is an interface so the worker is testable without a live server.
type DirSyncRequest ¶
type DirSyncRequest struct {
BaseDN string
Filter string
Attributes []string
Cookie []byte
Flags int64
MaxEntries int32
}
DirSyncRequest asks Active Directory for everything that changed under a naming context since a cookie (MS-ADTS LDAP_SERVER_DIRSYNC_OID).
Cookie is opaque and belongs to the server: empty asks for a full pass, and the cookie a pass returns is the only correct input to the next one. Flags carries the DirSync flags; MaxEntries caps one pass, which costs nothing because a pass is resumable by construction.
type DirSyncResult ¶
DirSyncResult is one pass: the entries that changed, the cookie the next pass must present, and whether the server has more waiting right now.
type Entry ¶
Entry is one directory entry a delta returns: its DN and its multi-valued attributes keyed by attribute name.
type GoDialer ¶
type GoDialer struct{}
GoDialer dials a real AD server through github.com/go-ldap/ldap, bounded by the shared connector call budget (nettimeout.Default), like the LDAP connector.
type Job ¶
type Job struct {
URL string `json:"url"`
BindDN string `json:"bindDN,omitempty"`
BindSecret string `json:"bindSecretRef,omitempty"`
StartTLS bool `json:"startTLS,omitempty"`
Operation string `json:"operation"`
DN string `json:"dn"`
MemberDN string `json:"memberDN,omitempty"`
NewDN string `json:"newDN,omitempty"`
// NewPassword is the password a set-password writes. It is the operation's own
// data and always was a process variable (ADR-0166), so it travels — and a worker
// leasing the job already receives the task's variables regardless, which is why
// carrying it here adds no exposure that the lease did not already have.
NewPassword string `json:"newPassword,omitempty"`
// Attributes is the resolved entry for create-user, create-group and
// update-attributes.
Attributes map[string][]string `json:"attributes,omitempty"`
// The sync operation's own fields. Cookie is base64 of the server's opaque resume
// token, because a process variable holds text and the token is binary.
// CookieVariable is where the *new* cookie is written back, which is what lets a
// reconciliation loop carry itself forward without any state in the connector.
BaseDN string `json:"baseDN,omitempty"`
Filter string `json:"filter,omitempty"`
Cookie string `json:"cookie,omitempty"`
CookieVariable string `json:"cookieVariable,omitempty"`
MaxEntries int `json:"maxEntries,omitempty"`
ObjectSecurity bool `json:"objectSecurity,omitempty"`
ResultVariable string `json:"resultVariable,omitempty"`
}
Job is an AD task with everything the engine can evaluate already evaluated: the server, the operation, and its operands.
BindSecret is a *reference*, not a password — the same reference the model authored (ADR-0041). Whoever runs the job resolves it against whatever secret store it has.
func Resolve ¶
func Resolve(store state.Reader, cp *compiler.CompiledProcess, detail *compiler.ConnectorTaskDetail, ei *model.ElementInstanceValue, elementInstanceKey uint64) (Job, error)
Resolve turns a compiled AD connector task into a Job: the authored values evaluated against the instance's variables, and the attribute object read out of the named variable. It is engine work by necessity — FEEL is compiled at deploy (ADR-0008/0015) and only the engine has the scope.
type Mod ¶
Mod is one attribute change in a modify: an operation, the attribute, and the values the operation applies.
type ProcessLookup ¶
type ProcessLookup func(defKey uint64) *compiler.CompiledProcess
ProcessLookup resolves a process-definition key to its compiled process.
type SecretResolver ¶
SecretResolver returns the secret value for a reference name, or "" if unknown. The worker uses it to turn an AD task's bind-password *reference* into the credential at call time (ADR-0041), so the password never lives in the model.