auth

package
v0.9.1 Latest Latest
Warning

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

Go to latest
Published: Apr 10, 2026 License: MIT Imports: 16 Imported by: 0

Documentation

Index

Constants

View Source
const (
	OpEq       = "eq"
	OpNeq      = "neq"
	OpIn       = "in"
	OpNotIn    = "not_in"
	OpContains = "contains"
)

Condition operators.

View Source
const (
	// SessionCookieName is the HTTP cookie name for session tokens.
	SessionCookieName = "anna_session"

	// SessionDuration is the default session lifetime.
	SessionDuration = 7 * 24 * time.Hour
)
View Source
const (
	EffectAllow = "allow"
	EffectDeny  = "deny"
)

Policy effect constants.

View Source
const (
	RoleAdmin = "admin"
	RoleUser  = "user"
)

RoleAdmin and RoleUser are the built-in role IDs.

Variables

View Source
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.

View Source
var ErrAccessDenied = errors.New("access denied")

ErrAccessDenied is returned by Must when the request is denied.

View Source
var ErrNoSession = errors.New("no session cookie")

ErrNoSession is returned when no session cookie is present.

Functions

func CheckPassword

func CheckPassword(hash, plain string) error

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

func GetSessionCookie(r *http.Request) (string, error)

GetSessionCookie extracts the session ID from the request cookie. Returns ErrNoSession if the cookie is missing or empty.

func HashPassword

func HashPassword(plain string) (string, error)

HashPassword hashes a plaintext password using bcrypt with cost 12.

func IsLinkCode

func IsLinkCode(s string) bool

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

func SeedPolicies(ctx context.Context, store AuthStore) error

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 Action

type Action string

Action is a string alias for authorization actions.

const (
	ActionRead    Action = "read"
	ActionWrite   Action = "write"
	ActionCreate  Action = "create"
	ActionDelete  Action = "delete"
	ActionExecute Action = "execute"
	ActionManage  Action = "manage"
)

Action constants.

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.

func (AuthUser) IsAdmin

func (u AuthUser) IsAdmin() bool

IsAdmin returns true if the user has the admin role.

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

func NewSharedLinkCodeStore(ctx context.Context, db *sql.DB) (*LinkCodeStore, error)

NewSharedLinkCodeStore creates a link code store backed by the shared Anna DB so admin and channel subprocesses can exchange codes across processes.

func (*LinkCodeStore) Consume

func (s *LinkCodeStore) Consume(code string) (int64, string, bool)

Consume looks up a link code and returns the associated user ID and platform if valid. The code is consumed (deleted) on success. Returns (0, "", false) if the code is invalid or expired.

func (*LinkCodeStore) Generate

func (s *LinkCodeStore) Generate(userID int64, platform string) string

Generate creates a new 6-character alphanumeric link code for the given user and platform. Returns the code string.

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

Can returns true if the access request is allowed by the loaded policies. It uses the deny-overrides algorithm:

  1. Find all policies matching subject roles, action, and resource type
  2. Evaluate conditions (ABAC) for matching policies
  3. If ANY matching policy has effect=deny -> deny
  4. If at least one matching policy has effect=allow -> allow
  5. 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 NewRateLimiter

func NewRateLimiter() *RateLimiter

NewRateLimiter creates a new RateLimiter.

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.

type Session

type Session struct {
	ID        string    `json:"id"`
	UserID    int64     `json:"user_id"`
	ExpiresAt time.Time `json:"expires_at"`
	CreatedAt time.Time `json:"created_at"`
}

Session represents an HTTP session.

type Subject

type Subject struct {
	UserID   int64          `json:"user_id"`
	Roles    []string       `json:"roles"`
	AgentIDs []string       `json:"agent_ids"`
	Attrs    map[string]any `json:"attrs,omitempty"`
}

Subject represents the entity requesting access.

Jump to

Keyboard shortcuts

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