auth

package
v0.3.1 Latest Latest
Warning

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

Go to latest
Published: Apr 10, 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(teamName string) error

RevokeAllTeamTokens invalidates all existing tokens for a team by incrementing the team's revoked version. Any token whose version is less than or equal to the new revoked version will be rejected during validation. Returns ErrTeamNotFound if the team does not exist.

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.
	RevokedVersion int64     `json:"revoked_version"` // Minimum valid token version.
}

TeamInfo stores metadata about a team.

Jump to

Keyboard shortcuts

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