servicemfa

package
v0.0.0-...-8c930d8 Latest Latest
Warning

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

Go to latest
Published: Nov 11, 2026 License: Apache-2.0 Imports: 24 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

View Source
var ErrAccountAdministratorNotConfigured = errors.New("mfa account administrator is not configured")

ErrAccountAdministratorNotConfigured is returned by administrative MFA flows until the host application installs a real AccountAdministrator.

Functions

func GenerateTOTPBackupCodes

func GenerateTOTPBackupCodes() ([]string, error)

GenerateTOTPBackupCodes creates one-time recovery codes for a new TOTP device.

Each code is 16 characters drawn from an unambiguous Base32 alphabet, formatted in groups of four for manual entry. Callers return these raw codes only once to the user during device confirmation.

func HashTOTPBackupCodes

func HashTOTPBackupCodes(secret string, codes []string) ([]string, error)

HashTOTPBackupCodes normalizes and hashes recovery codes before storage, keyed by the owning device's TOTP secret.

Stored devices keep only HMAC-SHA256 digests of normalized recovery codes, so database reads never expose usable recovery credentials. A recovery code is an 80-bit high-entropy random string, not a human-chosen password, so a slow password hash would add cost without adding brute-force resistance; HMAC keyed per device with the secret the device already owns needs no new key management and keeps digests independent across devices.

func LoginSecondFactorVerifier

func LoginSecondFactorVerifier(ctx *gst.ServiceContext, userID string, factor authn.LoginSecondFactor) error

LoginSecondFactorVerifier enforces the MFA rules used during IAM login. It is the gate installed through authn.SetLoginSecondFactorVerifier: module/mfa installs it on the add path, and project-owned assembly code installs it on the copy path. Nothing here installs itself, so the gate is never armed by a package import alone.

Accounts without active TOTP devices pass untouched. Enrolled accounts must submit exactly one proof: a TOTP code, consumed against replay on success, or a recovery code, removed transactionally. Each proof first spends one attempt from the user's login budget, and a verified proof resets it. Per the authn contract the verifier owns the client-facing error shape, and clients branch on status plus message: the stable 401 authn.MsgSecondFactorRequired tells a login UI to prompt for the code, 401 with other messages reports an invalid proof, 400 reports both proofs arriving at once, and 429 reports a spent budget, which refuses even a correct proof until its window ends.

func SetAccountAdministrator

func SetAccountAdministrator(admin AccountAdministrator)

SetAccountAdministrator installs the host application's administrative authorizer. Call it during application/module initialization before serving requests. Passing nil restores the safe default that denies every administrative MFA call with ErrAccountAdministratorNotConfigured.

Types

type AccountAdministrator

type AccountAdministrator interface {
	// EnsureCanAdminister rejects the request unless the current actor may
	// administer the target account's MFA enrollment.
	EnsureCanAdminister(ctx *gst.ServiceContext, targetUserID string) error
}

AccountAdministrator authorizes administrative MFA operations on a target account. Implementations decide who may inspect or reset another account's enrollment; the built-in module adapter delegates to the framework IAM tenant-admin rules.

MFA intentionally does not own that authority model. Projects copied with `gg module copy mfa` install their implementation from a project-owned file outside service/mfa; until one is installed every administrative call is denied.

type AdminTOTPResetService

type AdminTOTPResetService struct {
	service.Base[*modelmfa.AdminTOTP, *model.Empty, *modelmfa.AdminTOTPResetRsp]
}

AdminTOTPResetService force-clears a target account's TOTP enrollment.

This is the rescue path for an account that lost both its authenticator device and its recovery codes: self-service unbind deliberately accepts no password, so only an administrator can switch MFA off for such an account. The reset hard-deletes every device — active or still staged — so no shared secret or recovery-code hash survives, and the account logs in without a second factor until it enrolls again. It also forgets the account's verification attempt budgets, so a lockout earned while the factor was lost does not follow the account into its new enrollment.

func (*AdminTOTPResetService) Delete

Delete removes every TOTP device of the target user on behalf of an administrator.

type AdminTOTPStatusService

type AdminTOTPStatusService struct {
	service.Base[*modelmfa.AdminTOTP, *model.Empty, *modelmfa.AdminTOTPStatusRsp]
}

AdminTOTPStatusService returns a target account's TOTP enrollment state to an administrator. Authorization is delegated to the installed AccountAdministrator before any enrollment data is read, and the response is the same sanitized view the self-service status endpoint renders: device metadata only, never secrets or recovery-code hashes.

func (*AdminTOTPStatusService) Get

Get loads the target user's TOTP enrollment view for an administrator.

type TOTPBindService

type TOTPBindService struct {
	service.Base[*modelmfa.TOTPBind, *model.Empty, *modelmfa.TOTPBindRsp]
}

TOTPBindService starts the TOTP binding flow for an authenticated account.

The service validates the current user and session, generates a new TOTP secret, renders the provisioning URL as a QR code, and stores the secret in a short-lived binding challenge tied to the current user and session. The response returns only the challenge ID and authenticator setup data, never the raw secret as a standalone field.

func (*TOTPBindService) Create

func (t *TOTPBindService) Create(ctx *gst.ServiceContext, req *model.Empty) (rsp *modelmfa.TOTPBindRsp, err error)

Create creates a pending TOTP binding challenge and returns setup metadata.

The method requires an authenticated account and session, generates a new server-held secret, stores it in the binding challenge, and returns the challenge ID with the provisioning URL and QR image for authenticator setup.

type TOTPConfirmService

type TOTPConfirmService struct {
	service.Base[*modelmfa.TOTPConfirm, *modelmfa.TOTPConfirmReq, *modelmfa.TOTPConfirmRsp]
}

TOTPConfirmService completes a pending TOTP binding flow.

The service loads the cached binding challenge, ensures it belongs to the current user and session, validates the submitted TOTP code against the server-held secret, consumes the challenge, and then creates the active device. It returns one-time recovery codes only in this response while storing HMAC digests in the device record. Consuming the challenge before any storage work means a failure can never leave an activated device whose recovery codes were generated but never delivered.

func (*TOTPConfirmService) Create

Create turns a valid binding challenge into an active TOTP device.

The method verifies challenge ownership, checks and consumes the submitted TOTP code, consumes the challenge, creates recovery codes, stores only their hashes, and persists the device. The (user_id, secret) unique index is the duplicate guard: a concurrent confirm of the same challenge loses on Create with a conflict.

type TOTPStatusService

type TOTPStatusService struct {
	service.Base[*modelmfa.TOTPStatus, *model.Empty, *modelmfa.TOTPStatusRsp]
}

TOTPStatusService returns the current authenticated account's TOTP enrollment state. The service keeps the status view scoped to ctx.UserID(), counts only active devices as enabling MFA, and returns device metadata without exposing secrets or recovery-code hashes.

The request type is *model.Empty to match the DSL: a List action that only declares a Result always parses with an empty payload, and the add path must register the same request type the copy path generates.

func (*TOTPStatusService) List

func (t *TOTPStatusService) List(ctx *gst.ServiceContext, req *model.Empty) (rsp *modelmfa.TOTPStatusRsp, err error)

List loads the current user's TOTP devices and builds the status response used by clients to render MFA settings. It requires an authenticated request, returns active devices only, and derives Enabled from the active device count.

type TOTPUnbindService

type TOTPUnbindService struct {
	service.Base[*modelmfa.TOTPUnbind, *modelmfa.TOTPUnbindReq, *modelmfa.TOTPUnbindRsp]
}

TOTPUnbindService removes an active TOTP device after fresh authentication.

The request must provide exactly one verification method: a TOTP code or a recovery code, both proving possession of the second factor itself — the password alone deliberately cannot switch MFA off. Verification runs against the current user's active devices; recovery-code removal and target-device deletion share the same transaction so the code is consumed only when the unbind operation succeeds.

Each well-formed request spends one attempt from the user's unbind budget before its proof is checked, and a verified proof resets the budget.

Failures answer through service errors like the rest of the module: 400 for malformed requests, 401 for failed fresh authentication, 404 for a missing target device, 429 once the unbind budget is spent. Credentials are always judged before the target device is looked up, so an unauthenticated caller cannot probe device existence.

func (*TOTPUnbindService) Create

Create validates fresh authentication, removes the target device, and returns the remaining active count.

Jump to

Keyboard shortcuts

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