Documentation
¶
Index ¶
- Constants
- Variables
- func EnforceMustChangePassword(next http.Handler) http.Handler
- func MustChangePasswordFromContext(ctx context.Context) bool
- func UserToPrincipal(u *User) *identity.Principal
- func WithMustChangePassword(ctx context.Context, v bool) context.Context
- type Config
- type Service
- func (s *Service) AuthMiddleware() func(http.Handler) http.Handler
- func (s *Service) Bootstrap(ctx context.Context) error
- func (s *Service) ChangePassword(ctx context.Context, userID, currentPassword, newPassword string) error
- func (s *Service) ClearSessionCookie(w http.ResponseWriter)
- func (s *Service) CreateExternalSession(ctx context.Context, p *identity.Principal) (*Session, error)
- func (s *Service) Login(ctx context.Context, username, password string) (*Session, *User, error)
- func (s *Service) Logout(ctx context.Context, sessionID string) error
- func (s *Service) ResolveSession(ctx context.Context, sessionID string) (*Session, *identity.Principal, bool, error)
- func (s *Service) SeedDemoUser(ctx context.Context) error
- func (s *Service) SetSessionCookie(w http.ResponseWriter, sessionID string, expiresAt time.Time)
- type Session
- type SessionAuthenticator
- type SessionRepository
- type User
- type UserRepository
Constants ¶
const ProviderLocalIAM = "localiam"
ProviderLocalIAM is the identity.Principal.Provider value set when a principal is resolved from a local IAM session.
const SessionCookieName = "midas_session"
SessionCookieName is the HTTP cookie name used to carry the session ID.
Variables ¶
var ( ErrInvalidCredentials = errors.New("localiam: invalid username or password") ErrUserDisabled = errors.New("localiam: user account is disabled") ErrUserNotFound = errors.New("localiam: user not found") ErrSessionNotFound = errors.New("localiam: session not found or expired") ErrWeakPassword = errors.New("localiam: password does not meet requirements") )
Sentinel errors returned by Service methods.
Functions ¶
func EnforceMustChangePassword ¶
EnforceMustChangePassword is middleware that blocks requests from principals whose must_change_password flag is true, returning HTTP 403, unless the request path is one of the explicitly allowed paths:
- GET /auth/me
- POST /auth/change-password
- POST /auth/logout
func MustChangePasswordFromContext ¶
MustChangePasswordFromContext retrieves the must_change_password flag. Returns false when not set (i.e. no session, or session resolved without flag).
func UserToPrincipal ¶
UserToPrincipal converts a local IAM User to an *identity.Principal. The Principal.ID is prefixed with "localiam:" to namespace it from other provider namespaces (e.g. "static:", "entra:").
Types ¶
type Config ¶
type Config struct {
// Enabled controls whether local IAM is active. When false, the service
// should not be constructed.
Enabled bool
// SessionTTL is how long a session remains valid. Defaults to 8 hours.
SessionTTL time.Duration
// SecureCookies sets the Secure flag on session cookies. Enable in
// production (HTTPS). Disable only for local HTTP development.
SecureCookies bool
}
Config holds localiam runtime configuration.
type Service ¶
type Service struct {
// contains filtered or unexported fields
}
Service provides local platform IAM operations: bootstrap, login, logout, session resolution, and password management. It is the only component that touches the user and session repositories.
func NewService ¶
func NewService(users UserRepository, sessions SessionRepository, cfg Config) *Service
NewService constructs a Service. sessionTTL defaults to 8 hours when zero.
func (*Service) AuthMiddleware ¶
AuthMiddleware returns middleware that reads the session cookie, resolves the session, and stores both the principal (via platformauth.WithPrincipal) and the must_change_password flag in the request context.
It is extraction-only: it never writes an error response when the session is absent or invalid. Enforcement is the responsibility of platformauth.RequireAuthenticated, platformauth.RequireRole, and EnforceMustChangePassword.
func (*Service) Bootstrap ¶
Bootstrap creates the default admin user if no users exist. It is safe to call on every startup — it is a no-op when at least one user already exists.
func (*Service) ChangePassword ¶
func (s *Service) ChangePassword(ctx context.Context, userID, currentPassword, newPassword string) error
ChangePassword verifies currentPassword, then replaces the hash with a bcrypt hash of newPassword and clears MustChangePassword.
Password policy:
- newPassword must not be empty
- newPassword must not equal the literal string "admin"
func (*Service) ClearSessionCookie ¶
func (s *Service) ClearSessionCookie(w http.ResponseWriter)
ClearSessionCookie is the exported variant used by the logout handler.
func (*Service) CreateExternalSession ¶
func (s *Service) CreateExternalSession(ctx context.Context, p *identity.Principal) (*Session, error)
CreateExternalSession creates a session for an externally-authenticated principal (e.g. OIDC). No local user record is required. The principal is stored as JSON in the session and is decoded on each ResolveSession call. Callers must validate and normalize the principal before calling this.
func (*Service) Login ¶
Login validates credentials, creates a session, and returns the session and user. Returns ErrInvalidCredentials on bad username or password.
func (*Service) ResolveSession ¶
func (s *Service) ResolveSession(ctx context.Context, sessionID string) (*Session, *identity.Principal, bool, error)
ResolveSession looks up a session by ID and returns the associated session, the resolved principal, and whether the user must change their password. Returns ErrSessionNotFound when the session is absent or expired.
For external-auth sessions (OIDC) where PrincipalJSON is populated, the principal is decoded from JSON and no local user lookup is performed. mustChangePassword is always false for external sessions.
func (*Service) SeedDemoUser ¶ added in v1.0.2
SeedDemoUser creates a demo Local IAM user (username: demo, password: demo) with the platform.operator role if one does not already exist. It is safe to call on every startup — it is a no-op when the demo user already exists.
WARNING: this creates a well-known credential. Never call in production.
func (*Service) SetSessionCookie ¶
SetSessionCookie writes the session cookie to the response.
type Session ¶
type Session struct {
ID string
UserID string
CreatedAt time.Time
ExpiresAt time.Time
// PrincipalJSON holds a JSON-encoded *identity.Principal for sessions
// created by external auth providers (e.g. OIDC). When set, UserID is
// empty and no local user record is required. Ignored for local IAM sessions.
PrincipalJSON string
}
Session is a server-side platform IAM session. Sessions are stored server-side and identified by a cryptographically secure random ID transmitted via an HTTP-only cookie. No JWT or refresh tokens.
type SessionAuthenticator ¶
type SessionAuthenticator struct {
// contains filtered or unexported fields
}
SessionAuthenticator implements auth.Authenticator by resolving the session cookie to an *identity.Principal. This is the bridge that allows the platformauth middleware to use localiam sessions with the existing auth.Authenticator abstraction.
func NewSessionAuthenticator ¶
func NewSessionAuthenticator(service *Service) *SessionAuthenticator
NewSessionAuthenticator wraps a Service as an auth.Authenticator.
func (*SessionAuthenticator) Authenticate ¶
Authenticate reads the session cookie from the request and resolves it to a Principal. Returns auth.ErrNoCredentials when no cookie is present.
type SessionRepository ¶
type SessionRepository interface {
// Create stores a new session.
Create(ctx context.Context, s *Session) error
// FindByID returns nil, nil when not found.
FindByID(ctx context.Context, id string) (*Session, error)
// Delete removes a single session (logout).
Delete(ctx context.Context, id string) error
// DeleteExpired removes all sessions whose ExpiresAt is before now.
// Called opportunistically; failures are non-fatal.
DeleteExpired(ctx context.Context) error
}
SessionRepository defines persistence for platform IAM sessions.
type User ¶
type User struct {
ID string
Username string
PasswordHash string // bcrypt hash; never store or log plaintext
Roles []string
Enabled bool
MustChangePassword bool
CreatedAt time.Time
UpdatedAt time.Time
LastLoginAt *time.Time // nil until first successful login
}
User is a local platform IAM user. Users represent human operators and administrators of the MIDAS control plane only — they are entirely separate from runtime authority (agents, surfaces, grants).
type UserRepository ¶
type UserRepository interface {
// FindByID returns nil, nil when not found.
FindByID(ctx context.Context, id string) (*User, error)
// FindByUsername returns nil, nil when not found.
FindByUsername(ctx context.Context, username string) (*User, error)
// Create inserts a new user. Returns an error if the username is already taken.
Create(ctx context.Context, u *User) error
// Update overwrites all mutable fields for an existing user.
Update(ctx context.Context, u *User) error
// Count returns the total number of users in the store.
Count(ctx context.Context) (int, error)
}
UserRepository defines persistence for local IAM users.