security

package
v1.0.2 Latest Latest
Warning

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

Go to latest
Published: Dec 30, 2025 License: MIT Imports: 16 Imported by: 0

README

ResolveSpec Security Provider

Type-safe, composable security system for ResolveSpec with support for authentication, column-level security (masking), and row-level security (filtering).

Features

  • Interface-Based - Type-safe providers instead of callbacks
  • Login/Logout Support - Built-in authentication lifecycle
  • Composable - Mix and match different providers
  • No Global State - Each handler has its own security configuration
  • Testable - Easy to mock and test
  • Extensible - Implement custom providers for your needs
  • Stored Procedures - All database operations use PostgreSQL stored procedures for security and maintainability

Stored Procedure Architecture

All database-backed security providers use PostgreSQL stored procedures exclusively. No raw SQL queries are executed from Go code.

Benefits
  • Security: Database logic is centralized and protected
  • Maintainability: Update database logic without recompiling Go code
  • Performance: Stored procedures are pre-compiled and optimized
  • Testability: Test database logic independently
  • Consistency: Standardized resolvespec_* naming convention
Available Stored Procedures
Procedure Purpose Used By
resolvespec_login Session-based login DatabaseAuthenticator
resolvespec_logout Session invalidation DatabaseAuthenticator
resolvespec_session Session validation DatabaseAuthenticator
resolvespec_session_update Update session activity DatabaseAuthenticator
resolvespec_refresh_token Token refresh DatabaseAuthenticator
resolvespec_jwt_login JWT user validation JWTAuthenticator
resolvespec_jwt_logout JWT token blacklist JWTAuthenticator
resolvespec_column_security Load column rules DatabaseColumnSecurityProvider
resolvespec_row_security Load row templates DatabaseRowSecurityProvider

See database_schema.sql for complete stored procedure definitions and examples.

Quick Start

import (
    "github.com/bitechdev/ResolveSpec/pkg/security"
    "github.com/bitechdev/ResolveSpec/pkg/restheadspec"
)

// 1. Create security providers
auth := security.NewJWTAuthenticator("your-secret-key", db)
colSec := security.NewDatabaseColumnSecurityProvider(db)
rowSec := security.NewDatabaseRowSecurityProvider(db)

// 2. Combine providers
provider := security.NewCompositeSecurityProvider(auth, colSec, rowSec)

// 3. Create handler and register security hooks
handler := restheadspec.NewHandlerWithGORM(db)
securityList := security.NewSecurityList(provider)
restheadspec.RegisterSecurityHooks(handler, securityList)

// 4. Apply middleware
router := mux.NewRouter()
restheadspec.SetupMuxRoutes(router, handler)
router.Use(security.NewAuthMiddleware(securityList))
router.Use(security.SetSecurityMiddleware(securityList))

Architecture

Spec-Agnostic Design

The security system is completely spec-agnostic - it doesn't depend on any specific spec implementation. Instead, each spec (restheadspec, funcspec, resolvespec) implements its own security integration by adapting to the SecurityContext interface.

┌─────────────────────────────────────┐
│     Security Package (Generic)      │
│  - SecurityContext interface        │
│  - Security providers                │
│  - Core security logic               │
└─────────────────────────────────────┘
           ▲          ▲          ▲
           │          │          │
    ┌──────┘          │          └──────┐
    │                 │                 │
┌───▼────┐      ┌────▼─────┐     ┌────▼──────┐
│RestHead│      │ FuncSpec │     │ResolveSpec│
│  Spec  │      │          │     │           │
│        │      │          │     │           │
│Adapts  │      │ Adapts   │     │  Adapts   │
│to      │      │ to       │     │  to       │
│Security│      │ Security │     │  Security │
│Context │      │ Context  │     │  Context  │
└────────┘      └──────────┘     └───────────┘

Benefits:

  • ✅ No circular dependencies
  • ✅ Each spec can customize security integration
  • ✅ Easy to add new specs
  • ✅ Security logic is reusable across all specs
Core Interfaces

The security system is built on three main interfaces:

1. Authenticator

Handles user authentication lifecycle:

type Authenticator interface {
    Login(ctx context.Context, req LoginRequest) (*LoginResponse, error)
    Logout(ctx context.Context, req LogoutRequest) error
    Authenticate(r *http.Request) (*UserContext, error)
}
2. ColumnSecurityProvider

Manages column-level security (masking/hiding):

type ColumnSecurityProvider interface {
    GetColumnSecurity(ctx context.Context, userID int, schema, table string) ([]ColumnSecurity, error)
}
3. RowSecurityProvider

Manages row-level security (WHERE clause filtering):

type RowSecurityProvider interface {
    GetRowSecurity(ctx context.Context, userID int, schema, table string) (RowSecurity, error)
}
SecurityProvider

The main interface that combines all three:

type SecurityProvider interface {
    Authenticator
    ColumnSecurityProvider
    RowSecurityProvider
}
4. SecurityContext (Spec Integration Interface)

Each spec implements this interface to integrate with the security system:

type SecurityContext interface {
    GetContext() context.Context
    GetUserID() (int, bool)
    GetSchema() string
    GetEntity() string
    GetModel() interface{}
    GetQuery() interface{}
    SetQuery(interface{})
    GetResult() interface{}
    SetResult(interface{})
}

Implementation Examples:

  • restheadspec: Adapts restheadspec.HookContextSecurityContext
  • funcspec: Adapts funcspec.HookContextSecurityContext
  • resolvespec: Adapts resolvespec.HookContextSecurityContext
UserContext

Enhanced user context with complete user information:

type UserContext struct {
    UserID    int            // User's unique ID
    UserName  string         // Username
    UserLevel int            // User privilege level
    SessionID string         // Current session ID
    RemoteID  string         // Remote system ID
    Roles     []string       // User roles
    Email     string         // User email
    Claims    map[string]any // Additional authentication claims
    Meta      map[string]any // Additional metadata (can hold any JSON-serializable values)
}

Available Implementations

Authenticators

HeaderAuthenticator - Simple header-based authentication:

auth := security.NewHeaderAuthenticator()
// Expects: X-User-ID, X-User-Name, X-User-Level, etc.

DatabaseAuthenticator - Database session-based authentication (Recommended):

auth := security.NewDatabaseAuthenticator(db)
// Supports: Login, Logout, Session management, Token refresh
// All operations use stored procedures: resolvespec_login, resolvespec_logout,
// resolvespec_session, resolvespec_session_update, resolvespec_refresh_token
// Requires: users and user_sessions tables + stored procedures (see database_schema.sql)

JWTAuthenticator - JWT token authentication with login/logout:

auth := security.NewJWTAuthenticator("secret-key", db)
// Supports: Login, Logout, JWT token validation
// All operations use stored procedures: resolvespec_jwt_login, resolvespec_jwt_logout
// Note: Requires JWT library installation for token signing/verification
Column Security Providers

DatabaseColumnSecurityProvider - Loads rules from database:

colSec := security.NewDatabaseColumnSecurityProvider(db)
// Uses stored procedure: resolvespec_column_security
// Queries core.secaccess and core.hub_link tables

ConfigColumnSecurityProvider - Static configuration:

rules := map[string][]security.ColumnSecurity{
    "public.employees": {
        {Path: []string{"ssn"}, Accesstype: "mask", MaskStart: 5},
    },
}
colSec := security.NewConfigColumnSecurityProvider(rules)
Row Security Providers

DatabaseRowSecurityProvider - Loads filters from database:

rowSec := security.NewDatabaseRowSecurityProvider(db)
// Uses stored procedure: resolvespec_row_security

ConfigRowSecurityProvider - Static templates:

templates := map[string]string{
    "public.orders": "user_id = {UserID}",
}
blocked := map[string]bool{
    "public.admin_logs": true,
}
rowSec := security.NewConfigRowSecurityProvider(templates, blocked)

Usage Examples

Example 1: Complete Database-Backed Security with Sessions (restheadspec)
func main() {
    db := setupDatabase()

    // Run migrations (see database_schema.sql)
    // db.Exec("CREATE TABLE users ...")
    // db.Exec("CREATE TABLE user_sessions ...")

    // Create handler
    handler := restheadspec.NewHandlerWithGORM(db)

    // Create security providers
    auth := security.NewDatabaseAuthenticator(db) // Session-based auth
    colSec := security.NewDatabaseColumnSecurityProvider(db)
    rowSec := security.NewDatabaseRowSecurityProvider(db)

    // Combine providers
    provider := security.NewCompositeSecurityProvider(auth, colSec, rowSec)
    securityList := security.NewSecurityList(provider)

    // Register security hooks for this spec
    restheadspec.RegisterSecurityHooks(handler, securityList)

    // Setup routes
    router := mux.NewRouter()

    // Add auth endpoints
    router.HandleFunc("/auth/login", handleLogin(securityList)).Methods("POST")
    router.HandleFunc("/auth/logout", handleLogout(securityList)).Methods("POST")
    router.HandleFunc("/auth/refresh", handleRefresh(securityList)).Methods("POST")

    // Setup API with security
    apiRouter := router.PathPrefix("/api").Subrouter()
    restheadspec.SetupMuxRoutes(apiRouter, handler)
    apiRouter.Use(security.NewAuthMiddleware(securityList))
    apiRouter.Use(security.SetSecurityMiddleware(securityList))

    http.ListenAndServe(":8080", router)
}

func handleLogin(securityList *security.SecurityList) http.HandlerFunc {
    return func(w http.ResponseWriter, r *http.Request) {
        var req security.LoginRequest
        json.NewDecoder(r.Body).Decode(&req)

        // Add client info to claims
        req.Claims = map[string]any{
            "ip_address": r.RemoteAddr,
            "user_agent": r.UserAgent(),
        }

        resp, err := securityList.Provider().Login(r.Context(), req)
        if err != nil {
            http.Error(w, err.Error(), http.StatusUnauthorized)
            return
        }

        // Set session cookie (optional)
        http.SetCookie(w, &http.Cookie{
            Name:     "session_token",
            Value:    resp.Token,
            Expires:  time.Now().Add(24 * time.Hour),
            HttpOnly: true,
            Secure:   true, // Use in production with HTTPS
            SameSite: http.SameSiteStrictMode,
        })

        json.NewEncoder(w).Encode(resp)
    }
}

func handleRefresh(securityList *security.SecurityList) http.HandlerFunc {
    return func(w http.ResponseWriter, r *http.Request) {
        token := r.Header.Get("X-Refresh-Token")

        if refreshable, ok := securityList.Provider().(security.Refreshable); ok {
            resp, err := refreshable.RefreshToken(r.Context(), token)
            if err != nil {
                http.Error(w, err.Error(), http.StatusUnauthorized)
                return
            }
            json.NewEncoder(w).Encode(resp)
        } else {
            http.Error(w, "Refresh not supported", http.StatusNotImplemented)
        }
    }
}
Example 2: Config-Based Security (No Database)
func main() {
    db := setupDatabase()
    handler := restheadspec.NewHandlerWithGORM(db)

    // Static column security rules
    columnRules := map[string][]security.ColumnSecurity{
        "public.employees": {
            {Path: []string{"ssn"}, Accesstype: "mask", MaskStart: 5},
            {Path: []string{"salary"}, Accesstype: "hide"},
        },
    }

    // Static row security templates
    rowTemplates := map[string]string{
        "public.orders": "user_id = {UserID}",
    }

    // Create providers
    auth := security.NewHeaderAuthenticator()
    colSec := security.NewConfigColumnSecurityProvider(columnRules)
    rowSec := security.NewConfigRowSecurityProvider(rowTemplates, nil)

    // Combine providers and register hooks
    provider := security.NewCompositeSecurityProvider(auth, colSec, rowSec)
    securityList := security.NewSecurityList(provider)
    restheadspec.RegisterSecurityHooks(handler, securityList)

    // Setup routes...
}
Example 3: FuncSpec Security (SQL Query API)
import (
    "github.com/bitechdev/ResolveSpec/pkg/funcspec"
    "github.com/bitechdev/ResolveSpec/pkg/security"
)

func main() {
    db := setupDatabase()

    // Create funcspec handler
    handler := funcspec.NewHandler(db)

    // Create security providers
    auth := security.NewJWTAuthenticator("secret-key", db)
    colSec := security.NewDatabaseColumnSecurityProvider(db)
    rowSec := security.NewDatabaseRowSecurityProvider(db)

    // Combine providers
    provider := security.NewCompositeSecurityProvider(auth, colSec, rowSec)
    securityList := security.NewSecurityList(provider)

    // Register security hooks (audit logging)
    funcspec.RegisterSecurityHooks(handler, securityList)

    // Note: funcspec operates on raw SQL queries, so row/column
    // security is limited. Security should be enforced at the
    // SQL function level or via database policies.

    // Setup routes...
}
Example 4: ResolveSpec Security (REST API)
import (
    "github.com/bitechdev/ResolveSpec/pkg/resolvespec"
    "github.com/bitechdev/ResolveSpec/pkg/security"
)

func main() {
    db := setupDatabase()
    registry := common.NewModelRegistry()

    // Register models
    registry.RegisterModel("public.users", &User{})
    registry.RegisterModel("public.orders", &Order{})

    // Create resolvespec handler
    handler := resolvespec.NewHandler(db, registry)

    // Create security providers
    auth := security.NewDatabaseAuthenticator(db)
    colSec := security.NewDatabaseColumnSecurityProvider(db)
    rowSec := security.NewDatabaseRowSecurityProvider(db)

    // Combine providers
    provider := security.NewCompositeSecurityProvider(auth, colSec, rowSec)
    securityList := security.NewSecurityList(provider)

    // Register security hooks for resolvespec
    resolvespec.RegisterSecurityHooks(handler, securityList)

    // Setup routes...
}
Example 5: Custom Provider

Implement your own provider for complete control:

type MySecurityProvider struct {
    db *gorm.DB
}

func (p *MySecurityProvider) Login(ctx context.Context, req security.LoginRequest) (*security.LoginResponse, error) {
    // Your custom login logic
}

func (p *MySecurityProvider) Logout(ctx context.Context, req security.LogoutRequest) error {
    // Your custom logout logic
}

func (p *MySecurityProvider) Authenticate(r *http.Request) (*security.UserContext, error) {
    // Your custom authentication logic
}

func (p *MySecurityProvider) GetColumnSecurity(ctx context.Context, userID int, schema, table string) ([]security.ColumnSecurity, error) {
    // Your custom column security logic
}

func (p *MySecurityProvider) GetRowSecurity(ctx context.Context, userID int, schema, table string) (security.RowSecurity, error) {
    // Your custom row security logic
}

// Use it with any spec
provider := &MySecurityProvider{db: db}
securityList := security.NewSecurityList(provider)

// Register with restheadspec
restheadspec.RegisterSecurityHooks(restHandler, securityList)

// Or with funcspec
funcspec.RegisterSecurityHooks(funcHandler, securityList)

// Or with resolvespec
resolvespec.RegisterSecurityHooks(resolveHandler, securityList)

Security Features

Column Security (Masking/Hiding)

Mask SSN (show last 4 digits):

{
    Path:       []string{"ssn"},
    Accesstype: "mask",
    MaskStart:  5,
    MaskChar:   "*",
}
// "123-45-6789" → "*****6789"

Hide entire field:

{
    Path:       []string{"salary"},
    Accesstype: "hide",
}
// Field returns 0 or empty

Nested JSON field masking:

{
    Path:       []string{"address", "street"},
    Accesstype: "mask",
    MaskStart:  10,
}
Row Security (Filtering)

User isolation:

{
    Template: "user_id = {UserID}",
}
// Users only see their own records

Tenant isolation:

{
    Template: "tenant_id = {TenantID} AND user_id = {UserID}",
}

Block all access:

{
    HasBlock: true,
}
// Completely blocks access to the table

Template variables:

  • {UserID} - Current user's ID
  • {PrimaryKeyName} - Primary key column
  • {TableName} - Table name
  • {SchemaName} - Schema name

Request Flow

HTTP Request
    ↓
NewAuthMiddleware (security package)
    ├─ Calls provider.Authenticate(request)
    └─ Adds UserContext to context
    ↓
SetSecurityMiddleware (security package)
    └─ Adds SecurityList to context
    ↓
Spec Handler (restheadspec/funcspec/resolvespec)
    ↓
BeforeRead Hook (registered by spec)
    ├─ Adapts spec's HookContext → SecurityContext
    ├─ Calls security.LoadSecurityRules(secCtx, securityList)
    │   ├─ Calls provider.GetColumnSecurity()
    │   └─ Calls provider.GetRowSecurity()
    └─ Caches security rules
    ↓
BeforeScan Hook (registered by spec)
    ├─ Adapts spec's HookContext → SecurityContext
    ├─ Calls security.ApplyRowSecurity(secCtx, securityList)
    └─ Applies row security (adds WHERE clause to query)
    ↓
Database Query (with security filters)
    ↓
AfterRead Hook (registered by spec)
    ├─ Adapts spec's HookContext → SecurityContext
    ├─ Calls security.ApplyColumnSecurity(secCtx, securityList)
    ├─ Applies column security (masks/hides fields)
    └─ Calls security.LogDataAccess(secCtx)
    ↓
HTTP Response (secured data)

Key Points:

  • Security package is spec-agnostic and provides core logic
  • Each spec registers its own hooks that adapt to SecurityContext
  • Security rules are loaded once and cached for the request
  • Row security is applied to the query (database level)
  • Column security is applied to results (application level)

Testing

The interface-based design makes testing straightforward:

// Mock authenticator for tests
type MockAuthenticator struct {
    UserToReturn *security.UserContext
    ErrorToReturn error
}

func (m *MockAuthenticator) Authenticate(r *http.Request) (*security.UserContext, error) {
    return m.UserToReturn, m.ErrorToReturn
}

// Use in tests
func TestMyHandler(t *testing.T) {
    mockAuth := &MockAuthenticator{
        UserToReturn: &security.UserContext{UserID: 123},
    }

    provider := security.NewCompositeSecurityProvider(
        mockAuth,
        &MockColumnSecurity{},
        &MockRowSecurity{},
    )

    securityList := security.SetupSecurityProvider(handler, provider)
    // ... test your handler
}

Migration Guide

From Old Callback System

If you're upgrading from the old callback-based system:

Old:

security.GlobalSecurity.AuthenticateCallback = myAuthFunc
security.GlobalSecurity.LoadColumnSecurityCallback = myColSecFunc
security.GlobalSecurity.LoadRowSecurityCallback = myRowSecFunc
security.SetupSecurityProvider(handler, &security.GlobalSecurity)

New:

// 1. Wrap your functions in a provider
type MyProvider struct{}

func (p *MyProvider) Authenticate(r *http.Request) (*security.UserContext, error) {
    userID, roles, err := myAuthFunc(r)
    return &security.UserContext{UserID: userID, Roles: strings.Split(roles, ",")}, err
}

func (p *MyProvider) GetColumnSecurity(ctx context.Context, userID int, schema, table string) ([]security.ColumnSecurity, error) {
    return myColSecFunc(userID, schema, table)
}

func (p *MyProvider) GetRowSecurity(ctx context.Context, userID int, schema, table string) (security.RowSecurity, error) {
    return myRowSecFunc(userID, schema, table)
}

func (p *MyProvider) Login(ctx context.Context, req security.LoginRequest) (*security.LoginResponse, error) {
    return nil, fmt.Errorf("not implemented")
}

func (p *MyProvider) Logout(ctx context.Context, req security.LogoutRequest) error {
    return nil
}

// 2. Create security list and register hooks
provider := &MyProvider{}
securityList := security.NewSecurityList(provider)

// 3. Register with your spec
restheadspec.RegisterSecurityHooks(handler, securityList)
From Old SetupSecurityProvider API

If you're upgrading from the previous interface-based system:

Old:

securityList := security.SetupSecurityProvider(handler, provider)

New:

securityList := security.NewSecurityList(provider)
restheadspec.RegisterSecurityHooks(handler, securityList) // or funcspec/resolvespec

The main changes:

  1. Security package no longer knows about specific spec types
  2. Each spec registers its own security hooks
  3. More flexible - same security provider works with all specs

Documentation

File Description
QUICK_REFERENCE.md Quick reference guide with examples
INTERFACE_GUIDE.md Complete implementation guide
examples.go Working provider implementations
setup_example.go 6 complete integration examples

API Reference

Context Helpers

Get user information from request context:

userCtx, ok := security.GetUserContext(ctx)
userID, ok := security.GetUserID(ctx)
userName, ok := security.GetUserName(ctx)
userLevel, ok := security.GetUserLevel(ctx)
sessionID, ok := security.GetSessionID(ctx)
remoteID, ok := security.GetRemoteID(ctx)
roles, ok := security.GetUserRoles(ctx)
email, ok := security.GetUserEmail(ctx)
Optional Interfaces

Implement these for additional features:

Refreshable - Token refresh support:

type Refreshable interface {
    RefreshToken(ctx context.Context, refreshToken string) (*LoginResponse, error)
}

Validatable - Token validation:

type Validatable interface {
    ValidateToken(ctx context.Context, token string) (bool, error)
}

Cacheable - Cache management:

type Cacheable interface {
    ClearCache(ctx context.Context, userID int, schema, table string) error
}

Benefits Over Callbacks

Feature Old (Callbacks) New (Interfaces)
Type Safety ❌ Callbacks can be nil ✅ Compile-time verification
Global State ❌ GlobalSecurity variable ✅ Dependency injection
Testability ⚠️ Need to set globals ✅ Easy to mock
Composability ❌ Single provider only ✅ Mix and match
Login/Logout ❌ Not supported ✅ Built-in
Extensibility ⚠️ Limited ✅ Optional interfaces

Common Patterns

Caching Security Rules
type CachedProvider struct {
    inner security.ColumnSecurityProvider
    cache *cache.Cache
}

func (p *CachedProvider) GetColumnSecurity(ctx context.Context, userID int, schema, table string) ([]security.ColumnSecurity, error) {
    key := fmt.Sprintf("%d:%s.%s", userID, schema, table)
    if cached, found := p.cache.Get(key); found {
        return cached.([]security.ColumnSecurity), nil
    }

    rules, err := p.inner.GetColumnSecurity(ctx, userID, schema, table)
    if err == nil {
        p.cache.Set(key, rules, cache.DefaultExpiration)
    }
    return rules, err
}
Role-Based Security
func (p *MyProvider) GetColumnSecurity(ctx context.Context, userID int, schema, table string) ([]security.ColumnSecurity, error) {
    userCtx, _ := security.GetUserContext(ctx)

    if contains(userCtx.Roles, "admin") {
        return []security.ColumnSecurity{}, nil // No restrictions
    }

    return loadRestrictionsForUser(userID, schema, table), nil
}
Multi-Tenant Isolation
func (p *MyProvider) GetRowSecurity(ctx context.Context, userID int, schema, table string) (security.RowSecurity, error) {
    tenantID := getUserTenant(userID)

    return security.RowSecurity{
        Template: fmt.Sprintf("tenant_id = %d AND user_id = {UserID}", tenantID),
    }, nil
}

Middleware and Handler API

NewAuthMiddleware

Standard middleware that authenticates all requests:

router.Use(security.NewAuthMiddleware(securityList))

Routes can skip authentication using the SkipAuth helper:

func PublicHandler(w http.ResponseWriter, r *http.Request) {
    ctx := security.SkipAuth(r.Context())
    // This route will bypass authentication
    // A guest user context will be set instead
}

router.Handle("/public", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    ctx := security.SkipAuth(r.Context())
    PublicHandler(w, r.WithContext(ctx))
}))

When authentication is skipped, a guest user context is automatically set:

  • UserID: 0
  • UserName: "guest"
  • Roles: ["guest"]
  • RemoteID: Request's remote address

Routes can use optional authentication with the OptionalAuth helper:

func OptionalAuthHandler(w http.ResponseWriter, r *http.Request) {
    ctx := security.OptionalAuth(r.Context())
    r = r.WithContext(ctx)

    // This route will try to authenticate
    // If authentication succeeds, authenticated user context is set
    // If authentication fails, guest user context is set instead

    userCtx, _ := security.GetUserContext(r.Context())
    if userCtx.UserID == 0 {
        // Guest user
        fmt.Fprintf(w, "Welcome, guest!")
    } else {
        // Authenticated user
        fmt.Fprintf(w, "Welcome back, %s!", userCtx.UserName)
    }
}

router.Handle("/home", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    ctx := security.OptionalAuth(r.Context())
    OptionalAuthHandler(w, r.WithContext(ctx))
}))

Authentication Modes Summary:

  • Required (default): Authentication must succeed or returns 401
  • SkipAuth: Bypasses authentication entirely, always sets guest context
  • OptionalAuth: Tries authentication, falls back to guest context if it fails
NewAuthHandler

Standalone authentication handler (without middleware wrapping):

// Use when you need authentication logic without middleware
authHandler := security.NewAuthHandler(securityList, myHandler)
http.Handle("/api/protected", authHandler)
NewOptionalAuthHandler

Standalone optional authentication handler that tries to authenticate but falls back to guest:

// Use for routes that should work for both authenticated and guest users
optionalHandler := security.NewOptionalAuthHandler(securityList, myHandler)
http.Handle("/home", optionalHandler)

// Example handler that checks user context
func myHandler(w http.ResponseWriter, r *http.Request) {
    userCtx, _ := security.GetUserContext(r.Context())
    if userCtx.UserID == 0 {
        fmt.Fprintf(w, "Welcome, guest!")
    } else {
        fmt.Fprintf(w, "Welcome back, %s!", userCtx.UserName)
    }
}
Helper Functions

Extract user information from context:

// Get full user context
userCtx, ok := security.GetUserContext(ctx)

// Get specific fields
userID, ok := security.GetUserID(ctx)
userName, ok := security.GetUserName(ctx)
userLevel, ok := security.GetUserLevel(ctx)
sessionID, ok := security.GetSessionID(ctx)
remoteID, ok := security.GetRemoteID(ctx)
roles, ok := security.GetUserRoles(ctx)
email, ok := security.GetUserEmail(ctx)
meta, ok := security.GetUserMeta(ctx)
Metadata Support

The Meta field in UserContext can hold any JSON-serializable values:

// Set metadata during login
loginReq := security.LoginRequest{
    Username: "user@example.com",
    Password: "password",
    Meta: map[string]any{
        "department": "engineering",
        "location": "US",
        "preferences": map[string]any{
            "theme": "dark",
        },
    },
}

// Access metadata in handlers
meta, ok := security.GetUserMeta(ctx)
if ok {
    department := meta["department"].(string)
}

License

Part of the ResolveSpec project.

Documentation

Index

Constants

View Source
const (
	// Context keys for user information
	UserIDKey       contextKey = "user_id"
	UserNameKey     contextKey = "user_name"
	UserLevelKey    contextKey = "user_level"
	SessionIDKey    contextKey = "session_id"
	SessionRIDKey   contextKey = "session_rid"
	RemoteIDKey     contextKey = "remote_id"
	UserRolesKey    contextKey = "user_roles"
	UserEmailKey    contextKey = "user_email"
	UserContextKey  contextKey = "user_context"
	UserMetaKey     contextKey = "user_meta"
	SkipAuthKey     contextKey = "skip_auth"
	OptionalAuthKey contextKey = "optional_auth"
)

Variables

This section is empty.

Functions

func ApplyColumnSecurity added in v0.0.63

func ApplyColumnSecurity(secCtx SecurityContext, securityList *SecurityList) error

ApplyColumnSecurity is a public wrapper for applyColumnSecurity that accepts a SecurityContext This allows other packages to apply column-level security using the generic interface

func ApplyRowSecurity added in v0.0.63

func ApplyRowSecurity(secCtx SecurityContext, securityList *SecurityList) error

ApplyRowSecurity is a public wrapper for applyRowSecurity that accepts a SecurityContext This allows other packages to apply row-level security using the generic interface

func GetRemoteID added in v0.0.63

func GetRemoteID(ctx context.Context) (string, bool)

GetRemoteID extracts the remote ID from context

func GetSessionID added in v0.0.63

func GetSessionID(ctx context.Context) (string, bool)

GetSessionID extracts the session ID from context

func GetSessionRID added in v0.0.81

func GetSessionRID(ctx context.Context) (int64, bool)

GetSessionID extracts the session ID from context

func GetUserEmail added in v0.0.63

func GetUserEmail(ctx context.Context) (string, bool)

GetUserEmail extracts user email from context

func GetUserID

func GetUserID(ctx context.Context) (int, bool)

GetUserID extracts the user ID from context

func GetUserLevel added in v0.0.63

func GetUserLevel(ctx context.Context) (int, bool)

GetUserLevel extracts the user level from context

func GetUserMeta added in v0.0.64

func GetUserMeta(ctx context.Context) (map[string]any, bool)

GetUserMeta extracts user metadata from context

func GetUserName added in v0.0.63

func GetUserName(ctx context.Context) (string, bool)

GetUserName extracts the user name from context

func GetUserRoles

func GetUserRoles(ctx context.Context) ([]string, bool)

GetUserRoles extracts user roles from context

func LoadSecurityRules added in v0.0.63

func LoadSecurityRules(secCtx SecurityContext, securityList *SecurityList) error

LoadSecurityRules is a public wrapper for loadSecurityRules that accepts a SecurityContext This allows other packages to load security rules using the generic interface

func LogDataAccess added in v0.0.63

func LogDataAccess(secCtx SecurityContext) error

LogDataAccess is a public wrapper for logDataAccess that accepts a SecurityContext This allows other packages to use the audit logging functionality

func NewAuthHandler added in v0.0.64

func NewAuthHandler(securityList *SecurityList, next http.Handler) http.Handler

NewAuthHandler creates an authentication handler that can be used standalone This handler performs authentication and returns 401 if authentication fails Use this when you need authentication logic without middleware wrapping

func NewAuthMiddleware added in v0.0.63

func NewAuthMiddleware(securityList *SecurityList) func(http.Handler) http.Handler

NewAuthMiddleware creates an authentication middleware with the given security list This middleware extracts user authentication from the request and adds it to context Routes can skip authentication by setting SkipAuthKey context value (use SkipAuth helper) Routes can use optional authentication by setting OptionalAuthKey context value (use OptionalAuth helper) When authentication is skipped or fails with optional auth, a guest user context is set instead

func NewOptionalAuthHandler added in v0.0.64

func NewOptionalAuthHandler(securityList *SecurityList, next http.Handler) http.Handler

NewOptionalAuthHandler creates an optional authentication handler that can be used standalone This handler tries to authenticate but falls back to guest context if authentication fails Use this for routes that should show personalized content for authenticated users but still work for guests

func OptionalAuth added in v0.0.64

func OptionalAuth(ctx context.Context) context.Context

OptionalAuth returns a context with optional auth flag set to true Use this to mark routes that should try to authenticate, but fall back to guest if authentication fails

func SetSecurityMiddleware

func SetSecurityMiddleware(securityList *SecurityList) func(http.Handler) http.Handler

SetSecurityMiddleware adds security context to requests This middleware should be applied after AuthMiddleware

func SkipAuth added in v0.0.64

func SkipAuth(ctx context.Context) context.Context

SkipAuth returns a context with skip auth flag set to true Use this to mark routes that should bypass authentication middleware

func WithAuth added in v0.0.83

func WithAuth(handler func(http.ResponseWriter, *http.Request), securityList *SecurityList) func(http.ResponseWriter, *http.Request)

WithAuth wraps an HTTPFuncType handler with required authentication This function performs authentication and returns 401 if authentication fails Use this for handlers that require authenticated users

Usage:

handler := funcspec.NewHandler(db)
wrappedHandler := security.WithAuth(handler.SqlQueryList("SELECT * FROM orders WHERE user_id = [rid_user]", false, false, false), securityList)
router.HandleFunc("/api/orders", wrappedHandler)

func WithAuthAndSecurity added in v0.0.83

func WithAuthAndSecurity(handler func(http.ResponseWriter, *http.Request), securityList *SecurityList) func(http.ResponseWriter, *http.Request)

WithAuthAndSecurity wraps an HTTPFuncType handler with both authentication and security context This is a convenience function that combines WithAuth and WithSecurityContext Use this when you need both authentication and security context for a handler

Usage:

handler := funcspec.NewHandler(db)
wrappedHandler := security.WithAuthAndSecurity(handler.SqlQueryList("SELECT * FROM users", false, false, false), securityList)
router.HandleFunc("/api/users", wrappedHandler)

func WithOptionalAuth added in v0.0.83

func WithOptionalAuth(handler func(http.ResponseWriter, *http.Request), securityList *SecurityList) func(http.ResponseWriter, *http.Request)

WithOptionalAuth wraps an HTTPFuncType handler with optional authentication This function tries to authenticate but falls back to guest context if authentication fails Use this for handlers that should show personalized content for authenticated users but still work for guests

Usage:

handler := funcspec.NewHandler(db)
wrappedHandler := security.WithOptionalAuth(handler.SqlQueryList("SELECT * FROM products", false, false, false), securityList)
router.HandleFunc("/api/products", wrappedHandler)

func WithOptionalAuthAndSecurity added in v0.0.83

func WithOptionalAuthAndSecurity(handler func(http.ResponseWriter, *http.Request), securityList *SecurityList) func(http.ResponseWriter, *http.Request)

WithOptionalAuthAndSecurity wraps an HTTPFuncType handler with optional authentication and security context This is a convenience function that combines WithOptionalAuth and WithSecurityContext Use this when you want optional authentication and security context for a handler

Usage:

handler := funcspec.NewHandler(db)
wrappedHandler := security.WithOptionalAuthAndSecurity(handler.SqlQueryList("SELECT * FROM products", false, false, false), securityList)
router.HandleFunc("/api/products", wrappedHandler)

func WithSecurityContext added in v0.0.83

func WithSecurityContext(handler func(http.ResponseWriter, *http.Request), securityList *SecurityList) func(http.ResponseWriter, *http.Request)

WithSecurityContext wraps an HTTPFuncType handler with security context This function allows you to add security context to specific handler functions without needing to apply middleware globally

Usage:

handler := funcspec.NewHandler(db)
wrappedHandler := security.WithSecurityContext(handler.SqlQueryList("SELECT * FROM users", false, false, false), securityList)
router.HandleFunc("/api/users", wrappedHandler)

Types

type Authenticator added in v0.0.63

type Authenticator interface {
	// Login authenticates credentials and returns a token
	Login(ctx context.Context, req LoginRequest) (*LoginResponse, error)

	// Logout invalidates a user's session/token
	Logout(ctx context.Context, req LogoutRequest) error

	// Authenticate extracts and validates user from HTTP request
	// Returns UserContext or error if authentication fails
	Authenticate(r *http.Request) (*UserContext, error)
}

Authenticator handles user authentication operations

type CONTEXT_KEY added in v0.0.20

type CONTEXT_KEY string
const SECURITY_CONTEXT_KEY CONTEXT_KEY = "SecurityList"

type Cacheable added in v0.0.63

type Cacheable interface {
	// ClearCache clears cached security rules for a user/entity
	ClearCache(ctx context.Context, userID int, schema, table string) error
}

Cacheable allows providers to support caching of security rules

type ColumnSecurity

type ColumnSecurity struct {
	Schema       string            `json:"schema"`
	Tablename    string            `json:"tablename"`
	Path         []string          `json:"path"`
	ExtraFilters map[string]string `json:"extra_filters"`
	UserID       int               `json:"user_id"`
	Accesstype   string            `json:"accesstype"`
	MaskStart    int               `json:"mask_start"`
	MaskEnd      int               `json:"mask_end"`
	MaskInvert   bool              `json:"mask_invert"`
	MaskChar     string            `json:"mask_char"`
	Control      string            `json:"control"`
	ID           int               `json:"id"`
}

type ColumnSecurityProvider added in v0.0.63

type ColumnSecurityProvider interface {
	// GetColumnSecurity loads column security rules for a user and entity
	GetColumnSecurity(ctx context.Context, userID int, schema, table string) ([]ColumnSecurity, error)
}

ColumnSecurityProvider handles column-level security (masking/hiding)

type CompositeSecurityProvider added in v0.0.63

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

CompositeSecurityProvider combines multiple security providers Allows separating authentication, column security, and row security concerns

func NewCompositeSecurityProvider added in v0.0.63

func NewCompositeSecurityProvider(
	auth Authenticator,
	colSec ColumnSecurityProvider,
	rowSec RowSecurityProvider,
) (*CompositeSecurityProvider, error)

NewCompositeSecurityProvider creates a composite provider All parameters are required

func (*CompositeSecurityProvider) Authenticate added in v0.0.63

func (c *CompositeSecurityProvider) Authenticate(r *http.Request) (*UserContext, error)

Authenticate delegates to the authenticator

func (*CompositeSecurityProvider) ClearCache added in v0.0.63

func (c *CompositeSecurityProvider) ClearCache(ctx context.Context, userID int, schema, table string) error

ClearCache implements Cacheable if any provider supports it

func (*CompositeSecurityProvider) GetColumnSecurity added in v0.0.63

func (c *CompositeSecurityProvider) GetColumnSecurity(ctx context.Context, userID int, schema, table string) ([]ColumnSecurity, error)

GetColumnSecurity delegates to the column security provider

func (*CompositeSecurityProvider) GetRowSecurity added in v0.0.63

func (c *CompositeSecurityProvider) GetRowSecurity(ctx context.Context, userID int, schema, table string) (RowSecurity, error)

GetRowSecurity delegates to the row security provider

func (*CompositeSecurityProvider) Login added in v0.0.63

Login delegates to the authenticator

func (*CompositeSecurityProvider) Logout added in v0.0.63

Logout delegates to the authenticator

func (*CompositeSecurityProvider) RefreshToken added in v0.0.63

func (c *CompositeSecurityProvider) RefreshToken(ctx context.Context, refreshToken string) (*LoginResponse, error)

RefreshToken implements Refreshable if the authenticator supports it

func (*CompositeSecurityProvider) ValidateToken added in v0.0.63

func (c *CompositeSecurityProvider) ValidateToken(ctx context.Context, token string) (bool, error)

ValidateToken implements Validatable if the authenticator supports it

type ConfigColumnSecurityProvider added in v0.0.63

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

ConfigColumnSecurityProvider provides static column security configuration

func NewConfigColumnSecurityProvider added in v0.0.63

func NewConfigColumnSecurityProvider(rules map[string][]ColumnSecurity) *ConfigColumnSecurityProvider

func (*ConfigColumnSecurityProvider) GetColumnSecurity added in v0.0.63

func (p *ConfigColumnSecurityProvider) GetColumnSecurity(ctx context.Context, userID int, schema, table string) ([]ColumnSecurity, error)

type ConfigRowSecurityProvider added in v0.0.63

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

ConfigRowSecurityProvider provides static row security configuration

func NewConfigRowSecurityProvider added in v0.0.63

func NewConfigRowSecurityProvider(templates map[string]string, blocked map[string]bool) *ConfigRowSecurityProvider

func (*ConfigRowSecurityProvider) GetRowSecurity added in v0.0.63

func (p *ConfigRowSecurityProvider) GetRowSecurity(ctx context.Context, userID int, schema, table string) (RowSecurity, error)

type DatabaseAuthenticator added in v0.0.63

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

DatabaseAuthenticator provides session-based authentication with database storage All database operations go through stored procedures for security and consistency Requires stored procedures: resolvespec_login, resolvespec_logout, resolvespec_session, resolvespec_session_update, resolvespec_refresh_token See database_schema.sql for procedure definitions

func NewDatabaseAuthenticator added in v0.0.63

func NewDatabaseAuthenticator(db *sql.DB) *DatabaseAuthenticator

func NewDatabaseAuthenticatorWithOptions added in v0.0.86

func NewDatabaseAuthenticatorWithOptions(db *sql.DB, opts DatabaseAuthenticatorOptions) *DatabaseAuthenticator

func (*DatabaseAuthenticator) Authenticate added in v0.0.63

func (a *DatabaseAuthenticator) Authenticate(r *http.Request) (*UserContext, error)

func (*DatabaseAuthenticator) ClearCache added in v0.0.86

func (a *DatabaseAuthenticator) ClearCache(token string) error

ClearCache removes a specific token from the cache or clears all cache if token is empty

func (*DatabaseAuthenticator) ClearUserCache added in v0.0.86

func (a *DatabaseAuthenticator) ClearUserCache(userID int) error

ClearUserCache removes all cache entries for a specific user ID

func (*DatabaseAuthenticator) Login added in v0.0.63

func (*DatabaseAuthenticator) Logout added in v0.0.63

func (*DatabaseAuthenticator) RefreshToken added in v0.0.63

func (a *DatabaseAuthenticator) RefreshToken(ctx context.Context, refreshToken string) (*LoginResponse, error)

RefreshToken implements Refreshable interface

type DatabaseAuthenticatorExample added in v0.0.63

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

func NewDatabaseAuthenticatorExample added in v0.0.63

func NewDatabaseAuthenticatorExample(db *gorm.DB) *DatabaseAuthenticatorExample

func (*DatabaseAuthenticatorExample) Authenticate added in v0.0.63

func (a *DatabaseAuthenticatorExample) Authenticate(r *http.Request) (*UserContext, error)

func (*DatabaseAuthenticatorExample) Login added in v0.0.63

func (*DatabaseAuthenticatorExample) Logout added in v0.0.63

func (*DatabaseAuthenticatorExample) RefreshToken added in v0.0.63

func (a *DatabaseAuthenticatorExample) RefreshToken(ctx context.Context, refreshToken string) (*LoginResponse, error)

Optional: Implement Refreshable interface

type DatabaseAuthenticatorOptions added in v0.0.86

type DatabaseAuthenticatorOptions struct {
	// CacheTTL is the duration to cache user contexts
	// Default: 5 minutes
	CacheTTL time.Duration
	// Cache is an optional cache instance. If nil, uses the default cache
	Cache *cache.Cache
}

DatabaseAuthenticatorOptions configures the database authenticator

type DatabaseColumnSecurityProvider added in v0.0.63

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

DatabaseColumnSecurityProvider loads column security from database All database operations go through stored procedures Requires stored procedure: resolvespec_column_security

func NewDatabaseColumnSecurityProvider added in v0.0.63

func NewDatabaseColumnSecurityProvider(db *sql.DB) *DatabaseColumnSecurityProvider

func (*DatabaseColumnSecurityProvider) GetColumnSecurity added in v0.0.63

func (p *DatabaseColumnSecurityProvider) GetColumnSecurity(ctx context.Context, userID int, schema, table string) ([]ColumnSecurity, error)

type DatabaseRowSecurityProvider added in v0.0.63

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

DatabaseRowSecurityProvider loads row security from database All database operations go through stored procedures Requires stored procedure: resolvespec_row_security

func NewDatabaseRowSecurityProvider added in v0.0.63

func NewDatabaseRowSecurityProvider(db *sql.DB) *DatabaseRowSecurityProvider

func (*DatabaseRowSecurityProvider) GetRowSecurity added in v0.0.63

func (p *DatabaseRowSecurityProvider) GetRowSecurity(ctx context.Context, userID int, schema, table string) (RowSecurity, error)

type HeaderAuthenticator added in v0.0.63

type HeaderAuthenticator struct{}

HeaderAuthenticator provides simple header-based authentication Expects: X-User-ID, X-User-Name, X-User-Level, X-Session-ID, X-Remote-ID, X-User-Roles, X-User-Email

func NewHeaderAuthenticator added in v0.0.63

func NewHeaderAuthenticator() *HeaderAuthenticator

func (*HeaderAuthenticator) Authenticate added in v0.0.63

func (a *HeaderAuthenticator) Authenticate(r *http.Request) (*UserContext, error)

func (*HeaderAuthenticator) Login added in v0.0.63

func (*HeaderAuthenticator) Logout added in v0.0.63

type HeaderAuthenticatorExample added in v0.0.63

type HeaderAuthenticatorExample struct {
}

func NewHeaderAuthenticatorExample added in v0.0.63

func NewHeaderAuthenticatorExample() *HeaderAuthenticatorExample

func (*HeaderAuthenticatorExample) Authenticate added in v0.0.63

func (a *HeaderAuthenticatorExample) Authenticate(r *http.Request) (*UserContext, error)

func (*HeaderAuthenticatorExample) Login added in v0.0.63

func (*HeaderAuthenticatorExample) Logout added in v0.0.63

type JWTAuthenticator added in v0.0.63

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

JWTAuthenticator provides JWT token-based authentication All database operations go through stored procedures Requires stored procedures: resolvespec_jwt_login, resolvespec_jwt_logout NOTE: JWT signing/verification requires github.com/golang-jwt/jwt/v5 to be installed and imported

func NewJWTAuthenticator added in v0.0.63

func NewJWTAuthenticator(secretKey string, db *sql.DB) *JWTAuthenticator

func (*JWTAuthenticator) Authenticate added in v0.0.63

func (a *JWTAuthenticator) Authenticate(r *http.Request) (*UserContext, error)

func (*JWTAuthenticator) Login added in v0.0.63

func (*JWTAuthenticator) Logout added in v0.0.63

func (a *JWTAuthenticator) Logout(ctx context.Context, req LogoutRequest) error

type JWTAuthenticatorExample added in v0.0.63

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

func NewJWTAuthenticatorExample added in v0.0.63

func NewJWTAuthenticatorExample(secretKey string, db *gorm.DB) *JWTAuthenticatorExample

func (*JWTAuthenticatorExample) Authenticate added in v0.0.63

func (a *JWTAuthenticatorExample) Authenticate(r *http.Request) (*UserContext, error)

func (*JWTAuthenticatorExample) Login added in v0.0.63

func (*JWTAuthenticatorExample) Logout added in v0.0.63

type LoginRequest added in v0.0.63

type LoginRequest struct {
	Username string         `json:"username"`
	Password string         `json:"password"`
	Claims   map[string]any `json:"claims"` // Additional login data
	Meta     map[string]any `json:"meta"`   // Additional metadata to be set on user context
}

LoginRequest contains credentials for login

type LoginResponse added in v0.0.63

type LoginResponse struct {
	Token        string         `json:"token"`
	RefreshToken string         `json:"refresh_token"`
	User         *UserContext   `json:"user"`
	ExpiresIn    int64          `json:"expires_in"` // Token expiration in seconds
	Meta         map[string]any `json:"meta"`       // Additional metadata to be set on user context
}

LoginResponse contains the result of a login attempt

type LogoutRequest added in v0.0.63

type LogoutRequest struct {
	Token  string `json:"token"`
	UserID int    `json:"user_id"`
}

LogoutRequest contains information for logout

type Refreshable added in v0.0.63

type Refreshable interface {
	// RefreshToken exchanges a refresh token for a new access token
	RefreshToken(ctx context.Context, refreshToken string) (*LoginResponse, error)
}

Refreshable allows providers to support token refresh

type RowSecurity

type RowSecurity struct {
	Schema    string `json:"schema"`
	Tablename string `json:"tablename"`
	Template  string `json:"template"`
	HasBlock  bool   `json:"has_block"`
	UserID    int    `json:"user_id"`
}

func (*RowSecurity) GetTemplate

func (m *RowSecurity) GetTemplate(pPrimaryKeyName string, pModelType reflect.Type) string

type RowSecurityProvider added in v0.0.63

type RowSecurityProvider interface {
	// GetRowSecurity loads row security rules for a user and entity
	GetRowSecurity(ctx context.Context, userID int, schema, table string) (RowSecurity, error)
}

RowSecurityProvider handles row-level security (filtering)

type SecurityContext added in v0.0.67

type SecurityContext interface {
	GetContext() context.Context
	GetUserID() (int, bool)
	GetSchema() string
	GetEntity() string
	GetModel() interface{}
	GetQuery() interface{}
	SetQuery(interface{})
	GetResult() interface{}
	SetResult(interface{})
}

SecurityContext is a generic interface that any spec can implement to integrate with security features This interface abstracts the common security context needs across different specs

type SecurityList

type SecurityList struct {
	ColumnSecurityMutex sync.RWMutex
	ColumnSecurity      map[string][]ColumnSecurity
	RowSecurityMutex    sync.RWMutex
	RowSecurity         map[string]RowSecurity
	// contains filtered or unexported fields
}

SecurityList manages security state and caching It wraps a SecurityProvider and provides caching and utility methods

func GetSecurityList added in v0.0.83

func GetSecurityList(ctx context.Context) (*SecurityList, bool)

GetSecurityList extracts the SecurityList from request context

func NewSecurityList added in v0.0.63

func NewSecurityList(provider SecurityProvider) (*SecurityList, error)

NewSecurityList creates a new security list with the given provider

func (*SecurityList) ApplyColumnSecurity

func (m *SecurityList) ApplyColumnSecurity(records reflect.Value, modelType reflect.Type, pUserID int, pSchema, pTablename string) (reflect.Value, error)

func (*SecurityList) ClearSecurity

func (m *SecurityList) ClearSecurity(pUserID int, pSchema, pTablename string) error

func (*SecurityList) ColumSecurityApplyOnRecord

func (m *SecurityList) ColumSecurityApplyOnRecord(prevRecord reflect.Value, newRecord reflect.Value, modelType reflect.Type, pUserID int, pSchema, pTablename string) ([]string, error)

func (*SecurityList) GetRowSecurityTemplate

func (m *SecurityList) GetRowSecurityTemplate(pUserID int, pSchema, pTablename string) (RowSecurity, error)

func (*SecurityList) LoadColumnSecurity

func (m *SecurityList) LoadColumnSecurity(ctx context.Context, pUserID int, pSchema, pTablename string, pOverwrite bool) error

func (*SecurityList) LoadRowSecurity

func (m *SecurityList) LoadRowSecurity(ctx context.Context, pUserID int, pSchema, pTablename string, pOverwrite bool) (RowSecurity, error)

func (*SecurityList) Provider added in v0.0.63

func (m *SecurityList) Provider() SecurityProvider

Provider returns the underlying security provider

type SecurityProvider added in v0.0.63

type SecurityProvider interface {
	Authenticator
	ColumnSecurityProvider
	RowSecurityProvider
}

SecurityProvider is the main interface combining all security concerns

type UserContext added in v0.0.63

type UserContext struct {
	UserID     int            `json:"user_id"`
	UserName   string         `json:"user_name"`
	UserLevel  int            `json:"user_level"`
	SessionID  string         `json:"session_id"`
	SessionRID int64          `json:"session_rid"`
	RemoteID   string         `json:"remote_id"`
	Roles      []string       `json:"roles"`
	Email      string         `json:"email"`
	Claims     map[string]any `json:"claims"`
	Meta       map[string]any `json:"meta"` // Additional metadata that can hold any JSON-serializable values
}

UserContext holds authenticated user information

func GetUserContext added in v0.0.63

func GetUserContext(ctx context.Context) (*UserContext, bool)

GetUserContext extracts the full user context from request context

type Validatable added in v0.0.63

type Validatable interface {
	// ValidateToken checks if a token is valid without extracting full user context
	ValidateToken(ctx context.Context, token string) (bool, error)
}

Validatable allows providers to validate tokens without full authentication

Jump to

Keyboard shortcuts

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