2022-05-02 02:29:30 -05:00
package accesscontrol
import (
"context"
"fmt"
"time"
"github.com/grafana/grafana/pkg/infra/localcache"
"github.com/grafana/grafana/pkg/infra/log"
)
2022-08-24 06:29:17 -05:00
// ScopeAttributeResolver is used to resolve attributes in scopes to one or more scopes that are
// evaluated by logical or. E.g. "dashboards:id:1" -> "dashboards:uid:test-dashboard" or "folder:uid:test-folder"
type ScopeAttributeResolver interface {
Resolve ( ctx context . Context , orgID int64 , scope string ) ( [ ] string , error )
}
2024-05-09 04:18:03 -05:00
type ActionResolver interface {
2024-06-12 03:20:19 -05:00
// ExpandActionSets takes a set of permissions that might include some action set permissions, and returns a set of permissions with action sets expanded into underlying permissions
2024-05-21 09:09:26 -05:00
ExpandActionSets ( permissions [ ] Permission ) [ ] Permission
2024-06-12 03:20:19 -05:00
// ExpandActionSetsWithFilter works like ExpandActionSets, but it also takes a function for action filtering. When action sets are expanded into the underlying permissions,
// only those permissions whose action is matched by actionMatcher are included.
ExpandActionSetsWithFilter ( permissions [ ] Permission , actionMatcher func ( action string ) bool ) [ ] Permission
// ResolveAction returns all action sets that include the given action
ResolveAction ( action string ) [ ] string
// ResolveActionPrefix returns all action sets that include at least one action with the specified prefix
ResolveActionPrefix ( prefix string ) [ ] string
2024-05-09 04:18:03 -05:00
}
2022-08-24 06:29:17 -05:00
// ScopeAttributeResolverFunc is an adapter to allow functions to implement ScopeAttributeResolver interface
type ScopeAttributeResolverFunc func ( ctx context . Context , orgID int64 , scope string ) ( [ ] string , error )
func ( f ScopeAttributeResolverFunc ) Resolve ( ctx context . Context , orgID int64 , scope string ) ( [ ] string , error ) {
return f ( ctx , orgID , scope )
}
type ScopeAttributeMutator func ( context . Context , string ) ( [ ] string , error )
2022-05-02 02:29:30 -05:00
const (
ttl = 30 * time . Second
cleanInterval = 2 * time . Minute
)
2022-08-24 06:29:17 -05:00
func NewResolvers ( log log . Logger ) Resolvers {
return Resolvers {
log : log ,
2022-05-02 02:29:30 -05:00
cache : localcache . New ( ttl , cleanInterval ) ,
2022-08-24 06:29:17 -05:00
attributeResolvers : map [ string ] ScopeAttributeResolver { } ,
2022-05-02 02:29:30 -05:00
}
}
2022-08-24 06:29:17 -05:00
type Resolvers struct {
2022-05-02 02:29:30 -05:00
log log . Logger
cache * localcache . CacheService
attributeResolvers map [ string ] ScopeAttributeResolver
}
2022-08-24 06:29:17 -05:00
func ( s * Resolvers ) AddScopeAttributeResolver ( prefix string , resolver ScopeAttributeResolver ) {
2023-09-04 11:49:47 -05:00
s . log . Debug ( "Adding scope attribute resolver" , "prefix" , prefix )
2022-08-24 06:29:17 -05:00
s . attributeResolvers [ prefix ] = resolver
}
func ( s * Resolvers ) GetScopeAttributeMutator ( orgID int64 ) ScopeAttributeMutator {
2022-05-02 02:29:30 -05:00
return func ( ctx context . Context , scope string ) ( [ ] string , error ) {
2024-08-16 17:08:19 -05:00
ctx , span := tracer . Start ( ctx , "accesscontrol.GetScopeAttributeMutator" )
defer span . End ( )
2022-05-02 02:29:30 -05:00
key := getScopeCacheKey ( orgID , scope )
// Check cache before computing the scope
if cachedScope , ok := s . cache . Get ( key ) ; ok {
scopes := cachedScope . ( [ ] string )
2023-09-04 11:49:47 -05:00
s . log . Debug ( "Used cache to resolve scope" , "scope" , scope , "resolved_scopes" , scopes )
2022-05-02 02:29:30 -05:00
return scopes , nil
}
prefix := ScopePrefix ( scope )
if resolver , ok := s . attributeResolvers [ prefix ] ; ok {
scopes , err := resolver . Resolve ( ctx , orgID , scope )
if err != nil {
return nil , fmt . Errorf ( "could not resolve %v: %w" , scope , err )
}
// Cache result
s . cache . Set ( key , scopes , ttl )
2023-09-04 11:49:47 -05:00
s . log . Debug ( "Resolved scope" , "scope" , scope , "resolved_scopes" , scopes )
2022-05-02 02:29:30 -05:00
return scopes , nil
}
2022-08-25 05:50:27 -05:00
return nil , ErrResolverNotFound
2022-05-02 02:29:30 -05:00
}
}
// getScopeCacheKey creates an identifier to fetch and store resolution of scopes in the cache
func getScopeCacheKey ( orgID int64 , scope string ) string {
return fmt . Sprintf ( "%s-%v" , scope , orgID )
}