auth

package
v0.1.0 Latest Latest
Warning

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

Go to latest
Published: Apr 7, 2026 License: Apache-2.0 Imports: 17 Imported by: 0

Documentation

Overview

Package auth provides authentication and authorization for Wormhole.

The auth package implements team-based authentication using HMAC-SHA256 tokens and role-based access control for multi-user scenarios.

Features

  • Team token generation with HMAC-SHA256 signing
  • Token validation (signature + expiration)
  • Role-based permissions (admin, member, viewer)
  • Simple pre-shared token mode for quick setup
  • In-memory team management

Token Modes

Two modes are supported:

  • HMAC Mode: Tokens are signed with a secret key and include team, role, issued-at, expiration, and a random nonce.
  • Simple Mode: Tokens are plain strings compared against a whitelist. All matched tokens get "default" team + "member" role.

Usage

// HMAC mode
a, err := auth.New(auth.Config{
    Secret:      []byte("your-secret-key-at-least-16-bytes"),
    TokenExpiry: 24 * time.Hour,
})

// Generate team token
token, err := a.GenerateTeamToken("team-name", auth.RoleMember)

// Validate token
claims, err := a.ValidateToken(token)
if err != nil {
    return err
}

// Check permission
if !auth.HasPermission(claims, auth.PermissionWrite) {
    return auth.ErrForbidden
}

// Simple mode
a := auth.NewSimple([]string{"token-abc", "token-xyz"})
claims, err := a.ValidateToken("token-abc") // returns default/member claims.

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrInvalidToken    = errors.New("invalid token")
	ErrTokenExpired    = errors.New("token expired")
	ErrTokenRevoked    = errors.New("token revoked")
	ErrForbidden       = errors.New("forbidden")
	ErrTeamNotFound    = errors.New("team not found")
	ErrInvalidSecret   = errors.New("secret must be at least 16 bytes")
	ErrDuplicateTeam   = errors.New("team already exists")
	ErrInvalidTeamName = errors.New("invalid team name")
)

Sentinel errors for authentication.

Functions

func DefaultSQLiteStorePath

func DefaultSQLiteStorePath() string

DefaultSQLiteStorePath returns the default path for the SQLite database.

func HasPermission

func HasPermission(claims *Claims, perm Permission) bool

HasPermission checks if the claims grant the specified permission.

Types

type AuditEvent

type AuditEvent struct {
	Timestamp time.Time              `json:"timestamp"`
	Type      AuditEventType         `json:"type"`
	IP        string                 `json:"ip,omitempty"`
	TeamName  string                 `json:"team,omitempty"`
	Role      string                 `json:"role,omitempty"`
	SessionID string                 `json:"session_id,omitempty"`
	Subdomain string                 `json:"subdomain,omitempty"`
	Error     string                 `json:"error,omitempty"`
	Details   map[string]interface{} `json:"details,omitempty"`
}

AuditEvent represents a single audit log entry.

type AuditEventType

type AuditEventType string

AuditEventType represents the type of audit event.

const (
	// EventAuthSuccess indicates successful authentication.
	EventAuthSuccess AuditEventType = "auth_success"
	// EventAuthFailure indicates failed authentication.
	EventAuthFailure AuditEventType = "auth_failure"
	// EventIPBlocked indicates an IP was blocked due to failures.
	EventIPBlocked AuditEventType = "ip_blocked"
	// EventIPUnblocked indicates an IP was manually unblocked.
	EventIPUnblocked AuditEventType = "ip_unblocked"
	// EventTokenGenerated indicates a new token was generated.
	EventTokenGenerated AuditEventType = "token_generated"
	// EventClientConnected indicates a client connected.
	EventClientConnected AuditEventType = "client_connected"
	// EventClientDisconnected indicates a client disconnected.
	EventClientDisconnected AuditEventType = "client_disconnected"
)

type AuditLogger

type AuditLogger struct {
	// contains filtered or unexported fields
}

AuditLogger logs authentication and authorization events.

func NewAuditLogger

func NewAuditLogger(config AuditLoggerConfig) *AuditLogger

NewAuditLogger creates a new audit logger.

func (*AuditLogger) IsEnabled

func (l *AuditLogger) IsEnabled() bool

IsEnabled returns whether audit logging is enabled.

func (*AuditLogger) Log

func (l *AuditLogger) Log(event AuditEvent)

Log writes an audit event to the log.

func (*AuditLogger) LogAuthFailure

func (l *AuditLogger) LogAuthFailure(ip, reason string)

LogAuthFailure logs a failed authentication event.

func (*AuditLogger) LogAuthSuccess

func (l *AuditLogger) LogAuthSuccess(ip, teamName string, role Role, sessionID, subdomain string)

LogAuthSuccess logs a successful authentication event.

func (*AuditLogger) LogClientConnected

func (l *AuditLogger) LogClientConnected(ip, sessionID, subdomain, teamName string, role Role)

LogClientConnected logs a client connection event.

func (*AuditLogger) LogClientDisconnected

func (l *AuditLogger) LogClientDisconnected(sessionID, subdomain string, duration time.Duration)

LogClientDisconnected logs a client disconnection event.

func (*AuditLogger) LogIPBlocked

func (l *AuditLogger) LogIPBlocked(ip string, failureCount int)

LogIPBlocked logs an IP blocking event.

func (*AuditLogger) LogIPUnblocked

func (l *AuditLogger) LogIPUnblocked(ip string, manual bool)

LogIPUnblocked logs an IP unblocking event.

func (*AuditLogger) LogTokenGenerated

func (l *AuditLogger) LogTokenGenerated(teamName string, role Role)

LogTokenGenerated logs a token generation event.

func (*AuditLogger) SetEnabled

func (l *AuditLogger) SetEnabled(enabled bool)

SetEnabled enables or disables audit logging.

type AuditLoggerConfig

type AuditLoggerConfig struct {
	// Enabled turns audit logging on or off.
	Enabled bool

	// Writer is the destination for audit logs (defaults to os.Stdout).
	Writer io.Writer
}

AuditLoggerConfig configures the audit logger.

type Auth

type Auth struct {
	// contains filtered or unexported fields
}

Auth provides token-based authentication and authorization.

func New

func New(config Config) (*Auth, error)

New creates a new Auth instance.

func NewSimple

func NewSimple(allowedTokens []string) *Auth

NewSimple creates an Auth instance for simple pre-shared token mode. In this mode, tokens are compared directly against the allowed list.

func (*Auth) CleanupRevokedTokens

func (a *Auth) CleanupRevokedTokens() int

CleanupRevokedTokens removes expired entries from the revocation blacklist. This should be called periodically to prevent the blacklist from growing unbounded.

func (*Auth) Close

func (a *Auth) Close() error

Close releases any resources held by the Auth instance. This should be called when the Auth instance is no longer needed.

func (*Auth) ExtendTokenExpiry

func (a *Auth) ExtendTokenExpiry(token string, extension time.Duration) (string, error)

ExtendTokenExpiry creates a new token with an extended expiry time. The original token is NOT revoked.

func (*Auth) GenerateTeamToken

func (a *Auth) GenerateTeamToken(teamName string, role Role) (string, error)

GenerateTeamToken generates a new signed token for the given team and role.

func (*Auth) GetTeam

func (a *Auth) GetTeam(name string) (*TeamInfo, error)

GetTeam returns team information.

func (*Auth) IsRevoked

func (a *Auth) IsRevoked(tokenID string) bool

IsRevoked checks if a token ID is in the revocation blacklist.

func (*Auth) ListTeams

func (a *Auth) ListTeams() []TeamInfo

ListTeams returns all registered teams.

func (*Auth) RefreshAndRevokeToken

func (a *Auth) RefreshAndRevokeToken(oldToken string) (string, error)

RefreshAndRevokeToken generates a new token and revokes the old one atomically. This is the recommended way to refresh tokens when rotation is desired.

func (*Auth) RefreshToken

func (a *Auth) RefreshToken(token string) (string, error)

RefreshToken generates a new token with the same claims as the original, but with a fresh issuance time and expiry. The original token is NOT revoked. Use RevokeToken to invalidate the old token if desired.

func (*Auth) RegisterTeam

func (a *Auth) RegisterTeam(name string) error

RegisterTeam registers a team in the store.

func (*Auth) RevokeAllTeamTokens

func (a *Auth) RevokeAllTeamTokens(_ string) error

RevokeAllTeamTokens marks a team as fully revoked by incrementing a version. This is a placeholder for a more sophisticated team-level revocation. For now, it's not implemented as it would require version tracking in tokens. Use RevokeToken for individual token revocation.

func (*Auth) RevokeToken

func (a *Auth) RevokeToken(tokenID string, expiresAt time.Time) error

RevokeToken adds a token ID to the revocation blacklist. The expiresAt parameter indicates when the token would have expired; after that time, the revocation entry can be cleaned up. If expiresAt is zero, the revocation is permanent until manually cleared.

func (*Auth) RevokeTokenByString

func (a *Auth) RevokeTokenByString(token string) error

RevokeTokenByString parses a token string and revokes it by ID. Returns ErrInvalidToken if the token cannot be parsed or has no ID.

func (*Auth) RevokedTokenCount

func (a *Auth) RevokedTokenCount() int

RevokedTokenCount returns the number of tokens in the revocation blacklist.

func (*Auth) Store

func (a *Auth) Store() Store

Store returns the underlying storage backend. This is useful for advanced operations or testing.

func (*Auth) UnrevokeToken

func (a *Auth) UnrevokeToken(tokenID string)

UnrevokeToken removes a token ID from the revocation blacklist.

func (*Auth) ValidateToken

func (a *Auth) ValidateToken(token string) (*Claims, error)

ValidateToken validates a token and returns its claims. It supports both HMAC-signed tokens and simple pre-shared tokens.

type Claims

type Claims struct {
	// TokenID is the unique identifier for this token.
	TokenID string `json:"jti,omitempty"`
	// TeamName is the team this token belongs to.
	TeamName string `json:"team"`
	// Role is the role assigned to this token.
	Role Role `json:"role"`
	// IssuedAt is when the token was issued.
	IssuedAt time.Time `json:"iat"`
	// ExpiresAt is when the token expires (zero means no expiry).
	ExpiresAt time.Time `json:"exp,omitempty"`
}

Claims contains the validated token information.

type Config

type Config struct {
	// Secret is the HMAC signing key (must be at least 16 bytes).
	Secret []byte

	// TokenExpiry is the default expiry duration for new tokens.
	TokenExpiry time.Duration

	// AllowedTokens is a list of pre-shared plain tokens (simple mode).
	// When set, these tokens bypass HMAC validation entirely.
	AllowedTokens []string

	// Store is the storage backend for teams and revoked tokens.
	// If nil, a MemoryStore is used (no persistence).
	Store Store
}

Config holds the authentication configuration.

type MemoryStore

type MemoryStore struct {
	// contains filtered or unexported fields
}

MemoryStore implements Store using in-memory maps. This is the default, zero-persistence backend.

func NewMemoryStore

func NewMemoryStore() *MemoryStore

NewMemoryStore creates a new in-memory store.

func (*MemoryStore) CleanupExpiredRevocations

func (s *MemoryStore) CleanupExpiredRevocations() (int, error)

CleanupExpiredRevocations removes expired revocation entries.

func (*MemoryStore) Close

func (s *MemoryStore) Close() error

Close is a no-op for memory store.

func (*MemoryStore) CountRevokedTokens

func (s *MemoryStore) CountRevokedTokens() (int, error)

CountRevokedTokens returns the number of revoked tokens.

func (*MemoryStore) DeleteTeam

func (s *MemoryStore) DeleteTeam(name string) error

DeleteTeam removes a team from memory.

func (*MemoryStore) GetTeam

func (s *MemoryStore) GetTeam(name string) (*TeamInfo, error)

GetTeam retrieves a team from memory.

func (*MemoryStore) IsTokenRevoked

func (s *MemoryStore) IsTokenRevoked(tokenID string) (bool, error)

IsTokenRevoked checks if a token is revoked.

func (*MemoryStore) ListTeams

func (s *MemoryStore) ListTeams() ([]TeamInfo, error)

ListTeams returns all teams from memory.

func (*MemoryStore) RemoveRevokedToken

func (s *MemoryStore) RemoveRevokedToken(tokenID string) error

RemoveRevokedToken removes a token from the revocation list.

func (*MemoryStore) SaveRevokedToken

func (s *MemoryStore) SaveRevokedToken(tokenID string, expiresAt time.Time) error

SaveRevokedToken saves a revoked token to memory.

func (*MemoryStore) SaveTeam

func (s *MemoryStore) SaveTeam(team *TeamInfo) error

SaveTeam saves a team to memory.

type Permission

type Permission string

Permission represents an action that can be authorized.

const (
	// PermissionConnect allows establishing a tunnel connection.
	PermissionConnect Permission = "connect"
	// PermissionWrite allows creating and managing tunnels.
	PermissionWrite Permission = "write"
	// PermissionRead allows viewing tunnels and statistics.
	PermissionRead Permission = "read"
	// PermissionAdmin allows administrative operations.
	PermissionAdmin Permission = "admin"
)

type RateLimitConfig

type RateLimitConfig struct {
	// MaxFailures is the maximum number of auth failures before blocking.
	MaxFailures int

	// Window is the time window for counting failures.
	Window time.Duration

	// BlockDuration is how long to block after exceeding MaxFailures.
	BlockDuration time.Duration

	// CleanupInterval is how often to clean up expired entries.
	CleanupInterval time.Duration
}

RateLimitConfig configures the rate limiter behavior.

func DefaultRateLimitConfig

func DefaultRateLimitConfig() RateLimitConfig

DefaultRateLimitConfig returns sensible defaults for rate limiting.

type RateLimiter

type RateLimiter struct {
	// contains filtered or unexported fields
}

RateLimiter tracks authentication failures and blocks IPs.

func NewRateLimiter

func NewRateLimiter(config RateLimitConfig) *RateLimiter

NewRateLimiter creates a new rate limiter with the given config.

func (*RateLimiter) Close

func (rl *RateLimiter) Close()

Close stops the rate limiter and its cleanup goroutine.

func (*RateLimiter) GetBlockedIPs

func (rl *RateLimiter) GetBlockedIPs() []string

GetBlockedIPs returns a list of currently blocked IP addresses.

func (*RateLimiter) IsBlocked

func (rl *RateLimiter) IsBlocked(ip string) bool

IsBlocked checks if the given IP is currently blocked.

func (*RateLimiter) RecordFailure

func (rl *RateLimiter) RecordFailure(ip string) bool

RecordFailure records an authentication failure for the given IP. Returns true if the IP is now blocked.

func (*RateLimiter) RecordSuccess

func (rl *RateLimiter) RecordSuccess(ip string)

RecordSuccess records a successful authentication, clearing failure count.

func (*RateLimiter) Stats

func (rl *RateLimiter) Stats() RateLimiterStats

Stats returns current rate limiter statistics.

func (*RateLimiter) Unblock

func (rl *RateLimiter) Unblock(ip string)

Unblock manually unblocks an IP address.

type RateLimiterStats

type RateLimiterStats struct {
	TrackedIPs int `json:"tracked_ips"`
	BlockedIPs int `json:"blocked_ips"`
}

Stats returns rate limiter statistics.

type Role

type Role string

Role represents a user role in the system.

const (
	// RoleAdmin has full access including team management.
	RoleAdmin Role = "admin"
	// RoleMember can create tunnels and use the service.
	RoleMember Role = "member"
	// RoleViewer can only view tunnels and statistics.
	RoleViewer Role = "viewer"
)

type SQLiteStore

type SQLiteStore struct {
	// contains filtered or unexported fields
}

SQLiteStore implements Store using SQLite for persistence.

func NewSQLiteStore

func NewSQLiteStore(config SQLiteStoreConfig) (*SQLiteStore, error)

NewSQLiteStore creates a new SQLite-backed store.

func (*SQLiteStore) CleanupExpiredRevocations

func (s *SQLiteStore) CleanupExpiredRevocations() (int, error)

CleanupExpiredRevocations removes expired revocation entries.

func (*SQLiteStore) Close

func (s *SQLiteStore) Close() error

Close closes the database connection.

func (*SQLiteStore) CountRevokedTokens

func (s *SQLiteStore) CountRevokedTokens() (int, error)

CountRevokedTokens returns the number of revoked tokens.

func (*SQLiteStore) DeleteTeam

func (s *SQLiteStore) DeleteTeam(name string) error

DeleteTeam removes a team from SQLite.

func (*SQLiteStore) GetTeam

func (s *SQLiteStore) GetTeam(name string) (*TeamInfo, error)

GetTeam retrieves a team from SQLite.

func (*SQLiteStore) IsTokenRevoked

func (s *SQLiteStore) IsTokenRevoked(tokenID string) (bool, error)

IsTokenRevoked checks if a token is revoked.

func (*SQLiteStore) ListTeams

func (s *SQLiteStore) ListTeams() ([]TeamInfo, error)

ListTeams returns all teams from SQLite.

func (*SQLiteStore) RemoveRevokedToken

func (s *SQLiteStore) RemoveRevokedToken(tokenID string) error

RemoveRevokedToken removes a token from the revocation list.

func (*SQLiteStore) SaveRevokedToken

func (s *SQLiteStore) SaveRevokedToken(tokenID string, expiresAt time.Time) error

SaveRevokedToken saves a revoked token to SQLite.

func (*SQLiteStore) SaveTeam

func (s *SQLiteStore) SaveTeam(team *TeamInfo) error

SaveTeam saves a team to SQLite.

type SQLiteStoreConfig

type SQLiteStoreConfig struct {
	// Path is the path to the SQLite database file.
	// If empty, defaults to ~/.wormhole/wormhole.db
	Path string

	// CreateDir creates the parent directory if it doesn't exist.
	CreateDir bool
}

SQLiteStoreConfig configures the SQLite store.

type Store

type Store interface {
	// Team operations.
	SaveTeam(team *TeamInfo) error
	GetTeam(name string) (*TeamInfo, error)
	ListTeams() ([]TeamInfo, error)
	DeleteTeam(name string) error

	// Token revocation operations.
	SaveRevokedToken(tokenID string, expiresAt time.Time) error
	IsTokenRevoked(tokenID string) (bool, error)
	RemoveRevokedToken(tokenID string) error
	CleanupExpiredRevocations() (int, error)
	CountRevokedTokens() (int, error)

	// Close releases any resources held by the store.
	Close() error
}

Store defines the interface for persisting authentication data. Implementations can be in-memory (default) or persistent (SQLite).

type TeamInfo

type TeamInfo struct {
	Name      string    `json:"name"`
	CreatedAt time.Time `json:"created_at"`
	Tokens    int       `json:"tokens"` // Number of active tokens.
}

TeamInfo stores metadata about a team.

Jump to

Keyboard shortcuts

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