Documentation
¶
Overview ¶
Package operator is the operator-surface authentication domain (ADR-0021): the single operator's password, browser sessions, and operator tokens. It is transport-agnostic; the command line and the REST façade are two callers of the same functions. Persistence is behind Store, implemented with hand-written SQL in internal/store (ADR-0006).
Version 1 has one operator and binary authorization: a caller is authenticated or it is not. Both credential forms (a session from a password login, or a bearer token) resolve to the same principal (authn.Principal), and nothing downstream can tell which one was presented.
Index ¶
- Constants
- Variables
- func HashEqual(a, b []byte) bool
- func HashPassword(password string) (string, error)
- func HashSessionID(plaintext string) ([]byte, error)
- func HashToken(plaintext string) ([]byte, error)
- func NewAuthenticator(s *Service) *authn.Chain
- func NewSessionID() (plaintext string, hash []byte, err error)
- func NewToken() (plaintext string, hash []byte, prefix string, err error)
- func VerifyPassword(encoded, password string) error
- type Operator
- type PasswordVerifier
- type Service
- func (s *Service) CreateSession(ctx context.Context) (plaintext string, sess Session, err error)
- func (s *Service) DeleteSession(ctx context.Context, plaintext string) error
- func (s *Service) ListTokens(ctx context.Context) ([]Token, error)
- func (s *Service) MintToken(ctx context.Context, name string, ttl time.Duration) (plaintext string, tok Token, err error)
- func (s *Service) PruneSessions(ctx context.Context, now time.Time) (int64, error)
- func (s *Service) RevokeToken(ctx context.Context, id uuid.UUID) error
- func (s *Service) SetPassword(ctx context.Context, password string, displayName *string) error
- func (s *Service) ValidateSession(ctx context.Context, plaintext string) (*authn.Principal, error)
- func (s *Service) ValidateToken(ctx context.Context, plaintext string) (*authn.Principal, error)
- func (s *Service) VerifyPassword(ctx context.Context, password string) error
- type Session
- type SessionMinter
- type SessionVerifier
- type Store
- type Token
- type TokenVerifier
Constants ¶
const DefaultSessionTTL = 7 * 24 * time.Hour
DefaultSessionTTL is the fixed lifetime of a session. It is set at creation and never extended: the longest a leaked cookie stays useful is bounded by the clock, not by activity (ADR-0021).
const MinPasswordLength = 12
MinPasswordLength is the shortest password SetPassword accepts. Length is the one property of a password that reliably matters; composition rules are not enforced.
const TokenPrefix = "iwo_"
TokenPrefix marks an operator token in transit. It differs from the provisioning token's prefix so a secret scanner, and the surface, can tell the two apart without knowledge of the deployment that minted them.
Variables ¶
var ( // ErrNoOperator means no password has ever been set. The surface maps // it to a distinct problem type so a fresh install is recognizable. ErrNoOperator = errors.New("operator: no password has been set") // ErrPasswordMismatch means the password did not verify. ErrPasswordMismatch = errors.New("operator: password does not match") // ErrPasswordTooShort means a new password is below MinPasswordLength. ErrPasswordTooShort = errors.New("operator: password is too short") ErrSessionMalformed = errors.New("operator: session identifier is malformed") ErrSessionUnknown = errors.New("operator: session is not recognized") ErrSessionExpired = errors.New("operator: session has expired") ErrTokenMalformed = errors.New("operator: operator token is malformed") ErrTokenUnknown = errors.New("operator: operator token is not recognized") ErrTokenExpired = errors.New("operator: operator token has expired") ErrTokenRevoked = errors.New("operator: operator token has been revoked") )
Errors the domain reports. They are distinct so an operator sees exactly why a credential was refused; none of them reveals anything a caller without the credential could not already guess.
Functions ¶
func HashPassword ¶
HashPassword computes an argon2id hash of password and returns it in the self-describing form
$argon2id$v=19$m=<KiB>,t=<iterations>,p=<lanes>$<salt>$<hash>
with salt and hash in unpadded standard base64.
func HashSessionID ¶
HashSessionID validates the shape of a session identifier and returns its SHA-256 digest, or ErrSessionMalformed.
func HashToken ¶
HashToken validates the shape of a plaintext token and returns its SHA-256 digest. Shape validation happens before hashing so a malformed value is reported as malformed rather than as unknown.
func NewAuthenticator ¶ added in v0.5.0
NewAuthenticator composes the operator domain's verifiers, one per credential form, over its session minter.
func NewSessionID ¶
NewSessionID draws a fresh session identifier. The plaintext goes to the browser; the hash is what gets stored.
func NewToken ¶
NewToken draws a fresh operator token. The plaintext is returned once, for display to the operator; the hash is stored, and the prefix is what a listing shows.
func VerifyPassword ¶
VerifyPassword reports whether password matches the stored hash, recomputing with the parameters the hash carries. It returns ErrPasswordMismatch on a wrong password and a distinct error on a hash that cannot be parsed, because the two mean different things to an operator.
Types ¶
type Operator ¶
type Operator struct {
PasswordHash string
DisplayName *string
CreatedAt time.Time
UpdatedAt time.Time
}
Operator is the single operator row: the credential and the attributes beside it. DisplayName is optional; a surface renders a fallback when it is nil.
type PasswordVerifier ¶ added in v0.5.0
type PasswordVerifier struct{ Service *Service }
PasswordVerifier verifies the operator password. It reports ErrNoOperator when no password has been set and ErrPasswordMismatch when it does not verify.
func (PasswordVerifier) Form ¶ added in v0.5.0
func (PasswordVerifier) Form() authn.Form
Form implements authn.Verifier.
type Service ¶
type Service struct {
Store Store
// SessionTTL is the lifetime of a session; DefaultSessionTTL if zero.
SessionTTL time.Duration
// Now is the clock; time.Now if nil.
Now func() time.Time
}
Service is the operator authentication domain.
func (*Service) CreateSession ¶
CreateSession draws a session and persists its hash. The plaintext is returned once, for the cookie.
func (*Service) DeleteSession ¶
DeleteSession revokes a session. A malformed or unknown identifier is not an error: the outcome the caller wants, that the identifier no longer authenticates, already holds.
func (*Service) ListTokens ¶
ListTokens returns every token, newest first.
func (*Service) MintToken ¶
func (s *Service) MintToken(ctx context.Context, name string, ttl time.Duration) (plaintext string, tok Token, err error)
MintToken creates an operator token with the given lifetime (none if ttl is zero) and returns the plaintext exactly once.
func (*Service) PruneSessions ¶
PruneSessions deletes expired sessions. It rides the retention schedule the flow store runs (ADR-0021); there is no job of its own.
func (*Service) RevokeToken ¶
RevokeToken revokes a token as of now.
func (*Service) SetPassword ¶
SetPassword creates the operator or replaces its password, and sets the display name (nil clears it). It refuses a password shorter than MinPasswordLength.
func (*Service) ValidateSession ¶
ValidateSession resolves a session identifier to the principal. Expiry is judged here, at the instant of use, so a session past its lifetime is refused whether or not retention has pruned it yet.
func (*Service) ValidateToken ¶
ValidateToken resolves a bearer token to the principal and records the use. The token is checked before anything else is read, so a caller without a valid token learns nothing.
type Session ¶
Session is the stored form of a browser session. IDHash is the SHA-256 digest of the identifier the browser holds; the identifier itself is never stored.
type SessionMinter ¶ added in v0.5.0
type SessionMinter struct{ Service *Service }
SessionMinter mints and ends sessions with the domain's fixed lifetime.
func (SessionMinter) End ¶ added in v0.5.0
func (m SessionMinter) End(ctx context.Context, id string) error
End implements authn.Minter.
func (SessionMinter) Mint ¶ added in v0.5.0
func (m SessionMinter) Mint(ctx context.Context) (authn.MintedSession, error)
Mint implements authn.Minter.
type SessionVerifier ¶ added in v0.5.0
type SessionVerifier struct{ Service *Service }
SessionVerifier verifies a session identifier a login minted.
func (SessionVerifier) Form ¶ added in v0.5.0
func (SessionVerifier) Form() authn.Form
Form implements authn.Verifier.
type Store ¶
type Store interface {
// GetOperator returns ErrNoOperator when no password has been set.
GetOperator(ctx context.Context) (*Operator, error)
// SetOperator creates or replaces the single operator row.
SetOperator(ctx context.Context, op Operator) error
// CreateSession persists a session (hash only).
CreateSession(ctx context.Context, s Session) error
// GetSession returns ErrSessionUnknown when no session has that hash.
// Expiry is the domain's judgement, not the store's.
GetSession(ctx context.Context, idHash []byte) (*Session, error)
// DeleteSession removes a session; an unknown hash is not an error.
DeleteSession(ctx context.Context, idHash []byte) error
// DeleteExpiredSessions removes every session whose expiry is at or
// before now and reports how many.
DeleteExpiredSessions(ctx context.Context, now time.Time) (int64, error)
// CreateOperatorToken persists a minted token (hash only).
CreateOperatorToken(ctx context.Context, t Token) error
// FindOperatorTokenByHash returns ErrTokenUnknown when no token has that hash.
FindOperatorTokenByHash(ctx context.Context, hash []byte) (*Token, error)
// ListOperatorTokens returns every token, newest first.
ListOperatorTokens(ctx context.Context) ([]Token, error)
// RevokeOperatorToken marks a token revoked at instant now. It returns
// ErrTokenUnknown for an unknown id and ErrTokenRevoked if it already was.
RevokeOperatorToken(ctx context.Context, id uuid.UUID, now time.Time) error
// RecordOperatorTokenUse stores the instant a token last authenticated a call.
RecordOperatorTokenUse(ctx context.Context, id uuid.UUID, now time.Time) error
}
Store is the persistence the domain needs.
type Token ¶
type Token struct {
ID uuid.UUID
Hash []byte
Prefix string
Name string
CreatedAt time.Time
ExpiresAt *time.Time
RevokedAt *time.Time
LastUsedAt *time.Time
}
Token is the stored form of an operator token. It never carries the plaintext: Hash is what is looked up, Prefix is what is listed.
type TokenVerifier ¶ added in v0.5.0
type TokenVerifier struct{ Service *Service }
TokenVerifier verifies a bearer operator token and records its use.
func (TokenVerifier) Form ¶ added in v0.5.0
func (TokenVerifier) Form() authn.Form
Form implements authn.Verifier.
Directories
¶
| Path | Synopsis |
|---|---|
|
Package operatortest holds test doubles for the operator domain.
|
Package operatortest holds test doubles for the operator domain. |