Documentation
¶
Index ¶
- type AuthCache
- func (c *AuthCache) Clear()
- func (c *AuthCache) Enabled() bool
- func (c *AuthCache) Stats() (int64, int64, int)
- func (c *AuthCache) VerifyKey(ctx context.Context, keyID, plainKey, storedHash string) (bool, error)
- func (c *AuthCache) VerifyPassword(ctx context.Context, userID, password, storedHash string) (bool, error)
- type AuthCacheConfig
- type RevocationHandle
- type RevocationRegistry
- type SessionHandle
- type SessionRegistry
- type TerminationRequest
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type AuthCache ¶
type AuthCache struct {
// contains filtered or unexported fields
}
AuthCache provides caching for password verification results to avoid expensive argon2id re-computation on every request.
func NewAuthCache ¶
func NewAuthCache(cfg AuthCacheConfig) *AuthCache
NewAuthCache creates a new authentication cache.
type AuthCacheConfig ¶
AuthCacheConfig holds configuration for the auth cache.
type RevocationHandle ¶ added in v0.16.0
type RevocationHandle struct {
// contains filtered or unexported fields
}
RevocationHandle is held by a live proxy session for as long as it relies on a particular grant. Its flag is flipped to true the instant that grant is revoked, so the session's per-command check and its limit watchdog observe the revocation without a database round-trip on every query.
All methods are nil-safe: a session that could not obtain a handle (e.g. a nil registry in a test) treats itself as never-revoked.
func (*RevocationHandle) Flag ¶ added in v0.16.0
func (h *RevocationHandle) Flag() *atomic.Bool
Flag exposes the underlying atomic flag so a limit watchdog can poll it cheaply (a single atomic load) alongside the byte/time checks. Returns nil for a nil handle, which downstream guards treat as "no revocation to watch".
func (*RevocationHandle) Revoked ¶ added in v0.16.0
func (h *RevocationHandle) Revoked() bool
Revoked reports whether the grant backing this handle has been revoked.
type RevocationRegistry ¶ added in v0.16.0
type RevocationRegistry struct {
// contains filtered or unexported fields
}
RevocationRegistry is an in-process fan-out from the API's grant-revoke path to the live proxy sessions that authenticated under those grants. It lets a revocation take effect on already-established connections — blocking their next query and tearing the session down — instead of only being consulted at connect time.
It carries no database state: it maps a grant UID to the set of live session handles depending on it. Revoke flips their flags; the sessions' existing LimitGuard watchdog and checkQuotas paths do the rest.
func NewRevocationRegistry ¶ added in v0.16.0
func NewRevocationRegistry() *RevocationRegistry
NewRevocationRegistry creates an empty registry.
func (*RevocationRegistry) Deregister ¶ added in v0.16.0
func (r *RevocationRegistry) Deregister(grantUID uuid.UUID, h *RevocationHandle)
Deregister drops a handle previously returned by Register. Safe to call with a nil registry/handle or a handle that was never registered.
func (*RevocationRegistry) Register ¶ added in v0.16.0
func (r *RevocationRegistry) Register(grantUID uuid.UUID) *RevocationHandle
Register records a live session that relies on grantUID and returns its handle. Deregister must be called when the session ends. Calling on a nil registry, or with uuid.Nil, still returns a usable (never-revoked) handle so callers never have to nil-check the result.
func (*RevocationRegistry) Revoke ¶ added in v0.16.0
func (r *RevocationRegistry) Revoke(grantUID uuid.UUID) int
Revoke flips the revoked flag on every live session bound to grantUID and returns the number of sessions signaled. Safe to call for a grant with no live sessions (returns 0). It does not deregister the handles — the sessions tear themselves down and Deregister on the way out.
type SessionHandle ¶ added in v0.29.0
type SessionHandle struct {
// contains filtered or unexported fields
}
SessionHandle is held by one live proxy session for its whole life. Its flag is flipped the instant somebody asks for that session to end — an admin through the terminate endpoint, or this process's poller noticing a termination requested on another replica — so the session's limit watchdog observes it on its next tick with no database round trip of its own.
All methods are nil-safe: a session that could not obtain a handle (a nil registry in a test) treats itself as never terminated.
func (*SessionHandle) Flag ¶ added in v0.29.0
func (h *SessionHandle) Flag() *atomic.Bool
Flag exposes the underlying atomic so a limit watchdog can poll it with a single atomic load alongside the byte/time checks. nil for a nil handle, which downstream guards read as "nothing to watch".
func (*SessionHandle) Request ¶ added in v0.29.0
func (h *SessionHandle) Request() TerminationRequest
Request returns why the session was asked to end, or the zero value when it was not (or when the reason was lost to a race with the flag, which cannot happen: the request is stored before the flag is raised).
func (*SessionHandle) Terminated ¶ added in v0.29.0
func (h *SessionHandle) Terminated() bool
Terminated reports whether this session has been asked to end.
type SessionRegistry ¶ added in v0.29.0
type SessionRegistry struct {
// contains filtered or unexported fields
}
SessionRegistry is the in-process fan-out from "end connection X" to the live proxy session serving it, keyed by **connection uid**.
Every protocol already keeps a registry of its own — PostgreSQL by cancel key, MySQL by connection id — but each is keyed by a protocol handle, and the connection uid is the only identifier an admin has. This one is therefore protocol-agnostic and carries no database state: it maps a uid to the handle of the session serving it, and Terminate raises that handle's flag. The session's existing LimitGuard watchdog and onLimitViolation teardown (cancel upstream, then close both sockets) do the rest.
It is a sibling of RevocationRegistry, not a replacement: revocation fans out from one *grant* to the several sessions under it, this one addresses a single session. They are both signals into the same guard.
func NewSessionRegistry ¶ added in v0.29.0
func NewSessionRegistry() *SessionRegistry
NewSessionRegistry creates an empty registry.
func (*SessionRegistry) Deregister ¶ added in v0.29.0
func (r *SessionRegistry) Deregister(connUID uuid.UUID, h *SessionHandle)
Deregister drops a handle previously returned by Register. Safe to call with a nil registry/handle or a handle that was never registered.
func (*SessionRegistry) Live ¶ added in v0.29.0
func (r *SessionRegistry) Live(connUID uuid.UUID) bool
Live reports whether this process is serving the session named by connUID. Used by the terminate endpoint to say whether the local fast path applied, and by tests.
func (*SessionRegistry) Register ¶ added in v0.29.0
func (r *SessionRegistry) Register(connUID uuid.UUID) *SessionHandle
Register records the live session serving connUID and returns its handle. Deregister must be called when the session ends. Calling on a nil registry, or with uuid.Nil, still returns a usable (never-terminated) handle so callers never have to nil-check the result.
The value is a *set* of handles even though a connection uid names exactly one session: a uid is minted per session, so a second handle under the same uid is a bug, and a map that silently replaced the first would leave the real session unreachable. A set makes that case terminate both instead of losing one.
func (*SessionRegistry) Terminate ¶ added in v0.29.0
func (r *SessionRegistry) Terminate(connUID uuid.UUID, req TerminationRequest) bool
Terminate asks the live session serving connUID to end, and reports whether it signaled one *now*.
false therefore covers two cases that want the same handling: the session lives on another replica (or has already gone), and the session is here but was already asked to end. Both mean "there is nothing new for this caller to do", which is what the cross-instance poller needs — it re-reads the same request row every tick until the session is actually gone, and must not log a termination every two seconds while one tears down.
The request is published before the flag is raised, so a watchdog that observes the flag always finds the reason behind it. Handles are not deregistered here: the session tears itself down and Deregisters on the way out, exactly as the revocation path works. Terminating twice keeps the first reason — whoever got there first is who actually ended the session.
type TerminationRequest ¶ added in v0.29.0
type TerminationRequest struct {
// Reason is the store vocabulary value (`admin_terminated`,
// `grant_revoked`, …). Empty falls back to the session's own default.
Reason string
// By is the username of the human who asked, empty when nobody did.
By string
// Detail is that human's free text, shown to nobody but the audit log.
Detail string
}
TerminationRequest is why a live session is being ended from outside it.
It carries a string reason rather than a store constant because this package sits *below* the store (the store owns a registry, not the other way round), so the vocabulary — store.TerminationAdminTerminated, TerminationGrantRevoked — is passed through as data. The proxy stamps whatever arrives onto the connection row and the audit entry, which is what lets one mechanism serve both arms of the cross-instance poller: an admin asking for this session to end, and a grant revoked on another replica catching up with it.