Files
query-orchestration/internal/cognitoauth/permitio.go
T
Jay Brown 19a28fef17 Merged in bugfix/auth-permit (pull request #217)
permit.io fix

* permit.io fix
2026-03-19 15:22:07 +00:00

106 lines
2.8 KiB
Go

package cognitoauth
import (
"log/slog"
"sync"
"github.com/permitio/permit-golang/pkg/config"
"github.com/permitio/permit-golang/pkg/enforcement"
"github.com/permitio/permit-golang/pkg/permit"
)
// clientKey represents the unique identifier for a PermitIO client configuration
type clientKey struct {
apiKey string
pdpURL string
}
// PermitChecker abstracts the permit.io authorization check for testability.
type PermitChecker interface {
CheckPermission(userID, action, resourceType string) (bool, error)
}
// PermitIOClient wraps the Permit.io client with logging
type PermitIOClient struct {
client *permit.Client
logger *slog.Logger
}
var (
// clientCache stores cached PermitIO clients by their configuration
clientCache = make(map[clientKey]*PermitIOClient)
// clientMutex protects concurrent access to the cache
clientMutex sync.RWMutex
)
// NewPermitIOClient creates or returns a cached Permit.io client instance
// Uses caching based on the combination of apiKey and pdpURL to avoid creating
// duplicate clients for the same configuration.
func NewPermitIOClient(apiKey, pdpURL string, logger *slog.Logger) *PermitIOClient {
key := clientKey{
apiKey: apiKey,
pdpURL: pdpURL,
}
// First, try to get existing client with read lock
clientMutex.RLock()
if existingClient, exists := clientCache[key]; exists {
clientMutex.RUnlock()
return existingClient
}
clientMutex.RUnlock()
// If not found, acquire write lock and check again (double-checked locking)
clientMutex.Lock()
defer clientMutex.Unlock()
// Check again in case another goroutine created it while we were waiting
if existingClient, exists := clientCache[key]; exists {
return existingClient
}
// Create new client
newClient := &PermitIOClient{
client: permit.NewPermit(
config.NewConfigBuilder(apiKey).
WithPdpUrl(pdpURL).
Build(),
),
logger: logger,
}
// Cache the new client
clientCache[key] = newClient
return newClient
}
// CheckPermission verifies if a user has permission to perform an action on a resource
func (p *PermitIOClient) CheckPermission(userID, action, resourceType string) (bool, error) {
user := enforcement.UserBuilder(userID).Build()
resource := enforcement.ResourceBuilder(resourceType).Build()
p.logger.Debug("Sending permission check to PDP",
"user_id", userID,
"action", action,
"resource_type", resourceType)
permitted, err := p.client.Check(user, enforcement.Action(action), resource)
if err != nil {
p.logger.Error("Permit.io authorization check failed",
"user", userID,
"action", action,
"resource", resourceType,
"error", err)
return false, err
}
p.logger.Debug("Permit.io authorization check",
"user", userID,
"action", action,
"resource", resourceType,
"permitted", permitted)
return permitted, nil
}