19a28fef17
permit.io fix * permit.io fix
106 lines
2.8 KiB
Go
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
|
|
}
|