Documentation
¶
Overview ¶
Package adminapitoken issues and verifies administrators' personal access tokens: long-lived credentials for automation on the administrator APIs (docs/reference/admin-api-tokens.md).
A token is "anixadm_" and 43 characters of URL-safe base64 for 32 random bytes. The kernel stores only its SHA-256 (v4_kernel_admin_api_token); the token is shown once, when it is created. A request names it in "Authorization: Bearer <token>" and nowhere else, and the lookup is by hash: an attacker cannot learn anything from the comparison without the token's preimage.
A token carries no rights of its own beyond a scope (read or admin). The owner's rights are read from v2_user on every use, so banning, demoting or deleting an administrator ends their tokens at once, and a token used while its owner is not an administrator is revoked for good (it does not come back when the owner is restored).
Index ¶
- Constants
- Variables
- func Generate() (token, hash, hint string, err error)
- func Hash(token string) string
- func LooksLikeToken(s string) bool
- func ValidScope(scope string) bool
- func WellFormed(s string) bool
- type Actor
- type CreateInput
- type Denial
- type Event
- type ListFilter
- type Principal
- type Service
- func (s *Service) Authenticate(ctx context.Context, presented, ip string) (*Principal, error)
- func (s *Service) Create(ctx context.Context, input CreateInput) (string, model.AdminAPIToken, error)
- func (s *Service) List(ctx context.Context, filter ListFilter) ([]model.AdminAPIToken, error)
- func (s *Service) RecordCreateDenied(ctx context.Context, event Event)
- func (s *Service) RecordDenied(ctx context.Context, event Event)
- func (s *Service) RecordUse(ctx context.Context, event Event)
- func (s *Service) Revoke(ctx context.Context, id string, actor Actor) (model.AdminAPIToken, bool, error)
- func (s *Service) WithClock(now func() time.Time) *Service
Constants ¶
const ( // Prefix marks an admin API token. It lets secret scanners and humans // recognise one, and the middleware tell it from a JWT. Prefix = "anixadm_" // TokenLength is the length of every token. TokenLength = len(Prefix) + encodedLength // MaxNameLength bounds a token's name, counted in characters (runes), as the // web form counts them and as the column (varchar 100) does. MaxNameLength = 100 // MaxActivePerUser bounds the unrevoked, unexpired tokens of one owner. MaxActivePerUser = 25 // MaxLifetime bounds an expiry that is set; no expiry stays allowed. MaxLifetime = 2 * 365 * 24 * time.Hour // ManagementPath is the prefix of the routes that manage tokens. They // need a signed-in session: no API token reaches them. ManagementPath = "/api/v4/kernel/api-tokens" )
const ( ContextKeyAuthMethod = "auth_method" ContextKeyTokenID = "api_token_id" ContextKeyTokenScope = "api_token_scope" // AuthMethodAPIToken is the value of ContextKeyAuthMethod for a request // an admin API token authenticated. AuthMethodAPIToken = "api_token" )
Request context keys the authentication middleware sets. They are set on the server side only; a client cannot send them.
const ( AuditModule = "admin_api_token" AuditActionCreate = "admin_api_token_create" // AuditActionCreateDenied is a creation refused for its re-authentication. AuditActionCreateDenied = "admin_api_token_create_denied" AuditActionRevoke = "admin_api_token_revoke" AuditActionUse = "admin_api_token_use" AuditActionUseDenied = "admin_api_token_use_denied" )
Audit entries (v2_operation_log). Entries carry a token's id, name, scope, hint and expiry, never the token or its hash.
Variables ¶
var ( // ErrInvalid covers a malformed, unknown or unusable token. ErrInvalid = errors.New("invalid admin API token") // ErrRevoked is a revoked token. ErrRevoked = errors.New("admin API token revoked") // ErrExpired is a token past its expiry. ErrExpired = errors.New("admin API token expired") // ErrOwnerDenied is a token whose owner is banned, demoted or deleted. ErrOwnerDenied = errors.New("admin API token owner is not an active administrator") // ErrScopeDenied is a request the token's scope does not allow. ErrScopeDenied = errors.New("admin API token scope does not allow this request") // ErrInteractiveOnly is a request that needs a signed-in session. ErrInteractiveOnly = errors.New("this request needs a signed-in session, not an API token") // ErrNotFound is a token that does not exist or is not the caller's. ErrNotFound = errors.New("admin API token not found") // ErrInvalidRequest wraps every refused creation. ErrInvalidRequest = errors.New("invalid admin API token request") // ErrTooMany is an owner at MaxActivePerUser. ErrTooMany = errors.New("too many active admin API tokens") // ErrOwnerNotAdmin is a creation for an account that is not an active // administrator. ErrOwnerNotAdmin = errors.New("only an active administrator may hold admin API tokens") )
Why an authentication or a use was refused.
Functions ¶
func LooksLikeToken ¶
LooksLikeToken reports whether s starts like a token, however it is shaped; the middleware refuses these in a URL.
func ValidScope ¶
ValidScope reports whether scope is one the kernel knows.
func WellFormed ¶
WellFormed reports whether s has the shape of a token, so a request that cannot be one is refused without a lookup.
Types ¶
type Actor ¶
type Actor struct {
UserID uint
Name string
IP string
// Super lets the actor revoke other administrators' tokens.
Super bool
}
Actor is the administrator who revokes a token.
type CreateInput ¶
type CreateInput struct {
UserID uint
Name string
Scope string
// ExpiresAt ends the token; nil never (allowed, not advised).
ExpiresAt *time.Time
// Actor and IP describe the caller in the audit entry.
Actor string
IP string
}
CreateInput describes a new token.
type Denial ¶
type Denial struct {
Err error
TokenID string
UserID uint
// Detail is a short safe reason for the audit entry.
Detail string
}
Denial is a refused authentication: Err is one of the Err values above, the other fields say which token and owner it concerned when they are known.
type Event ¶
type Event struct {
TokenID string
UserID uint
Actor string
IP string
Method string
Path string
// Reason is a short safe reason: a Denial's Detail or the error.
Reason string
Status int
}
Event is a request an API token made or was refused.
type ListFilter ¶
type ListFilter struct {
// UserID limits the list to one owner; nil lists every owner's tokens.
UserID *uint
// IncludeInactive also lists revoked and expired tokens.
IncludeInactive bool
}
ListFilter selects tokens.
type Service ¶
type Service struct {
// contains filtered or unexported fields
}
Service issues, lists, revokes and authenticates admin API tokens.
func (*Service) Authenticate ¶
Authenticate resolves a presented token to its owner and scope. A refusal is a *Denial (use errors.Is with the Err values). ip is recorded as the token's last use, at most every few minutes.
func (*Service) Create ¶
func (s *Service) Create(ctx context.Context, input CreateInput) (string, model.AdminAPIToken, error)
Create issues a token for an active administrator and returns it: the only time it exists in clear. The audit entry is written with the row.
func (*Service) List ¶
func (s *Service) List(ctx context.Context, filter ListFilter) ([]model.AdminAPIToken, error)
List returns tokens, newest first. A token's secret is never in a row.
func (*Service) RecordCreateDenied ¶
RecordCreateDenied audits a creation refused because the re-authentication failed or was missing, at most once a minute per administrator. The entry carries no password and no code.
func (*Service) RecordDenied ¶
RecordDenied audits a refused use: an unusable token (Reason says why), a scope the request is outside of, or a request that needs a session. The same subject is audited at most once a minute, so a script that keeps failing cannot fill the log; the log line always says which token and owner, never the token.
func (*Service) RecordUse ¶
RecordUse audits a write an API token made, so the audit log can tell a token's requests from the owner's own. The audit log of the administrator APIs records the request itself; this entry names the token.
func (*Service) Revoke ¶
func (s *Service) Revoke(ctx context.Context, id string, actor Actor) (model.AdminAPIToken, bool, error)
Revoke ends a token. An administrator revokes their own; a super administrator revokes anyone's. A token that is not the actor's, or does not exist, is ErrNotFound. Revoking a revoked token changes nothing and reports changed false.