ad

package
v0.3.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 21, 2026 License: AGPL-3.0 Imports: 18 Imported by: 0

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

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

func Run(_ context.Context, j Job, dialer Dialer, secret SecretResolver) (map[string]any, error)

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

type Dialer interface {
	Dial(url, bindDN, bindPassword string, startTLS bool) (Conn, error)
}

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

type DirSyncResult struct {
	Entries []Entry
	Cookie  []byte
	More    bool
}

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

type Entry struct {
	DN         string
	Attributes map[string][]string
}

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.

func NewDialer

func NewDialer() GoDialer

NewDialer returns the production AD dialer.

func (GoDialer) Dial

func (GoDialer) Dial(rawURL, bindDN, bindPassword string, startTLS bool) (Conn, error)

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

type Mod struct {
	Op   modOp
	Attr string
	Vals []string
}

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

type SecretResolver func(ref string) string

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.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL