Documentation
¶
Index ¶
- Constants
- Variables
- func CheckPassword(hash, plain string) error
- func ClearSessionCookie(w http.ResponseWriter)
- func GetSessionCookie(r *http.Request) (string, error)
- func HashPassword(plain string) (string, error)
- func IsLinkCode(s string) bool
- func NewSessionID() string
- func SeedPolicies(ctx context.Context, store AuthStore) error
- func SetSessionCookie(w http.ResponseWriter, sessionID string, secure bool)
- type AccessRequest
- type Action
- type AuthStore
- type AuthUser
- type Identity
- type LinkCodeStore
- type Policy
- type PolicyEngine
- type RateLimiter
- type Resource
- type ResourceType
- type Session
- type Subject
Constants ¶
const ( OpEq = "eq" OpNeq = "neq" OpIn = "in" OpNotIn = "not_in" OpContains = "contains" )
Condition operators.
const ( // SessionCookieName is the HTTP cookie name for session tokens. SessionCookieName = "anna_session" // SessionDuration is the default session lifetime. SessionDuration = 7 * 24 * time.Hour )
const ( EffectAllow = "allow" EffectDeny = "deny" )
Policy effect constants.
const ( RoleAdmin = "admin" RoleUser = "user" )
RoleAdmin and RoleUser are the built-in role IDs.
Variables ¶
var ( ErrRateLimitIP = errors.New("too many requests from this IP, try again later") ErrRateLimitUsername = errors.New("too many failed attempts for this account, try again in 30 seconds") )
Rate limiting errors.
var ErrAccessDenied = errors.New("access denied")
ErrAccessDenied is returned by Must when the request is denied.
var ErrNoSession = errors.New("no session cookie")
ErrNoSession is returned when no session cookie is present.
Functions ¶
func CheckPassword ¶
CheckPassword verifies a plaintext password against a bcrypt hash.
func ClearSessionCookie ¶
func ClearSessionCookie(w http.ResponseWriter)
ClearSessionCookie removes the session cookie from the response. Setting Secure=true is harmless on HTTP and ensures the cookie is properly cleared on HTTPS deployments.
func GetSessionCookie ¶
GetSessionCookie extracts the session ID from the request cookie. Returns ErrNoSession if the cookie is missing or empty.
func HashPassword ¶
HashPassword hashes a plaintext password using bcrypt with cost 12.
func IsLinkCode ¶
IsLinkCode returns true if the string looks like a valid link code format (6 alphanumeric characters). This is a quick check before attempting Consume.
func NewSessionID ¶
func NewSessionID() string
NewSessionID generates a cryptographically random hex-encoded session ID (32 bytes = 64 hex characters).
func SeedPolicies ¶
SeedPolicies ensures the built-in policies exist in the store. It uses an idempotent pattern: existing entries are skipped.
func SetSessionCookie ¶
func SetSessionCookie(w http.ResponseWriter, sessionID string, secure bool)
SetSessionCookie writes the session cookie to the response. The Secure flag is set when secure is true (i.e., not localhost/dev).
Types ¶
type AccessRequest ¶
type AccessRequest struct {
Subject Subject `json:"subject"`
Action Action `json:"action"`
Resource Resource `json:"resource"`
Context map[string]any `json:"context,omitempty"`
}
AccessRequest represents a request to check authorization.
type AuthStore ¶
type AuthStore interface {
// Users
CreateUser(ctx context.Context, username, passwordHash string) (AuthUser, error)
GetUser(ctx context.Context, id int64) (AuthUser, error)
GetUserByUsername(ctx context.Context, username string) (AuthUser, error)
ListUsers(ctx context.Context) ([]AuthUser, error)
UpdateUser(ctx context.Context, u AuthUser) error
UpdateUserRole(ctx context.Context, userID int64, role string) error
UpdateUserDefaultAgent(ctx context.Context, userID int64, agentID string) error
UpdateUserNotifyIdentity(ctx context.Context, userID int64, identityID *int64) error
DeleteUser(ctx context.Context, id int64) error
CountUsers(ctx context.Context) (int64, error)
// Identities (linked channel accounts)
CreateIdentity(ctx context.Context, i Identity) (Identity, error)
GetIdentity(ctx context.Context, id int64) (Identity, error)
GetIdentityByPlatform(ctx context.Context, platform, externalID string) (Identity, error)
ListIdentitiesByUser(ctx context.Context, userID int64) ([]Identity, error)
DeleteIdentity(ctx context.Context, id int64) error
// Policies
CreatePolicy(ctx context.Context, p Policy) (Policy, error)
GetPolicy(ctx context.Context, id string) (Policy, error)
ListPolicies(ctx context.Context) ([]Policy, error)
ListEnabledPolicies(ctx context.Context) ([]Policy, error)
UpdatePolicy(ctx context.Context, p Policy) error
DeletePolicy(ctx context.Context, id string) error
// User-Agent assignments
AssignAgent(ctx context.Context, userID int64, agentID string) error
RemoveAgent(ctx context.Context, userID int64, agentID string) error
ListUserAgentIDs(ctx context.Context, userID int64) ([]string, error)
ListAgentUserIDs(ctx context.Context, agentID string) ([]int64, error)
// Sessions
CreateSession(ctx context.Context, s Session) (Session, error)
GetSession(ctx context.Context, id string) (Session, error)
DeleteSession(ctx context.Context, id string) error
DeleteExpiredSessions(ctx context.Context) error
DeleteUserSessions(ctx context.Context, userID int64) error
UpdateSessionExpiry(ctx context.Context, id string, expiresAt time.Time) error
}
AuthStore provides typed access to auth-related data in the database. This is separate from config.Store — auth methods are NOT mixed in.
type AuthUser ¶
type AuthUser struct {
ID int64 `json:"id"`
Username string `json:"username"`
PasswordHash string `json:"-"`
Role string `json:"role"`
IsActive bool `json:"is_active"`
DefaultAgentID string `json:"default_agent_id,omitempty"`
NotifyIdentityID *int64 `json:"notify_identity_id,omitempty"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
AuthUser represents a system user with login credentials and preferences.
type Identity ¶
type Identity struct {
ID int64 `json:"id"`
UserID int64 `json:"user_id"`
Platform string `json:"platform"`
ExternalID string `json:"external_id"`
Name string `json:"name"`
LinkedAt time.Time `json:"linked_at"`
}
Identity represents a linked channel identity.
type LinkCodeStore ¶
type LinkCodeStore struct {
// contains filtered or unexported fields
}
LinkCodeStore manages single-use link codes for channel account linking. Codes expire after 5 minutes. The default constructor keeps them in-memory; the shared constructor persists them to the Anna DB for cross-process use.
func NewLinkCodeStore ¶
func NewLinkCodeStore() *LinkCodeStore
NewLinkCodeStore creates a new link code store.
func NewSharedLinkCodeStore ¶
NewSharedLinkCodeStore creates a link code store backed by the shared Anna DB so admin and channel subprocesses can exchange codes across processes.
type Policy ¶
type Policy struct {
ID string `json:"id"`
Name string `json:"name"`
Effect string `json:"effect"`
Subjects string `json:"subjects"`
Actions string `json:"actions"`
Resources string `json:"resources"`
Conditions string `json:"conditions"`
Priority int `json:"priority"`
IsSystem bool `json:"is_system"`
Enabled bool `json:"enabled"`
CreatedAt time.Time `json:"created_at"`
}
Policy represents an ABAC policy with JSON conditions.
type PolicyEngine ¶
type PolicyEngine struct {
// contains filtered or unexported fields
}
PolicyEngine evaluates access requests against loaded policies using a deny-overrides algorithm. Policies are loaded once at startup.
func NewEngine ¶
func NewEngine(ctx context.Context, store AuthStore) (*PolicyEngine, error)
NewEngine creates a PolicyEngine by loading all enabled policies from the store. Policies are sorted by priority (descending) for deterministic evaluation.
func NewEngineFromPolicies ¶
func NewEngineFromPolicies(policies []Policy) *PolicyEngine
NewEngineFromPolicies creates a PolicyEngine from a pre-loaded set of policies. Useful for testing.
func (*PolicyEngine) Can ¶
func (e *PolicyEngine) Can(_ context.Context, req AccessRequest) bool
Can returns true if the access request is allowed by the loaded policies. It uses the deny-overrides algorithm:
- Find all policies matching subject roles, action, and resource type
- Evaluate conditions (ABAC) for matching policies
- If ANY matching policy has effect=deny -> deny
- If at least one matching policy has effect=allow -> allow
- No match -> deny (default deny)
func (*PolicyEngine) Must ¶
func (e *PolicyEngine) Must(ctx context.Context, req AccessRequest) error
Must is like Can but returns ErrAccessDenied when the request is denied.
type RateLimiter ¶
type RateLimiter struct {
// contains filtered or unexported fields
}
RateLimiter provides per-IP and per-username rate limiting for login attempts.
func (*RateLimiter) CheckIP ¶
func (rl *RateLimiter) CheckIP(ip string) error
CheckIP verifies the IP has not exceeded the request limit. Does not increment the counter — call RecordIPAttempt after a failed attempt.
func (*RateLimiter) CheckUsername ¶
func (rl *RateLimiter) CheckUsername(username string) error
CheckUsername verifies the username is not in a cooldown period.
func (*RateLimiter) RecordIPAttempt ¶
func (rl *RateLimiter) RecordIPAttempt(ip string)
RecordIPAttempt records a failed attempt for rate limiting by IP.
func (*RateLimiter) RecordLoginFailure ¶
func (rl *RateLimiter) RecordLoginFailure(username string)
RecordLoginFailure records a failed login attempt for a username.
func (*RateLimiter) RecordLoginSuccess ¶
func (rl *RateLimiter) RecordLoginSuccess(username string)
RecordLoginSuccess resets the failure counter for a username.
type Resource ¶
type Resource struct {
Type ResourceType `json:"type"`
ID string `json:"id"`
OwnerID int64 `json:"owner_id"`
Attrs map[string]any `json:"attrs,omitempty"`
}
Resource represents the target of an authorization request.
type ResourceType ¶
type ResourceType string
ResourceType is a string alias for resource types.
const ( ResourceAgent ResourceType = "agent" ResourceAgentList ResourceType = "agent_list" ResourceProvider ResourceType = "provider" ResourceChannel ResourceType = "channel" ResourceSession ResourceType = "session" ResourceUser ResourceType = "user" ResourceUserData ResourceType = "user_data" ResourceSkill ResourceType = "skill" ResourceScheduler ResourceType = "scheduler" ResourceSetting ResourceType = "setting" )
ResourceType constants.