|
|
|
|
@ -13,24 +13,31 @@ import ( |
|
|
|
|
"github.com/prometheus/client_golang/prometheus" |
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
func ProvideService(features featuremgmt.FeatureToggles, usageStats usagestats.Service) *OSSAccessControlService { |
|
|
|
|
s := &OSSAccessControlService{ |
|
|
|
|
features: features, |
|
|
|
|
UsageStats: usageStats, |
|
|
|
|
Log: log.New("accesscontrol"), |
|
|
|
|
ScopeResolver: accesscontrol.NewScopeResolver(), |
|
|
|
|
} |
|
|
|
|
func ProvideService(features featuremgmt.FeatureToggles, usageStats usagestats.Service, provider accesscontrol.PermissionsProvider) *OSSAccessControlService { |
|
|
|
|
s := ProvideOSSAccessControl(features, usageStats, provider) |
|
|
|
|
s.registerUsageMetrics() |
|
|
|
|
return s |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// ProvideOSSAccessControl creates an oss implementation of access control without usage stats registration
|
|
|
|
|
func ProvideOSSAccessControl(features featuremgmt.FeatureToggles, usageStats usagestats.Service, provider accesscontrol.PermissionsProvider) *OSSAccessControlService { |
|
|
|
|
return &OSSAccessControlService{ |
|
|
|
|
features: features, |
|
|
|
|
provider: provider, |
|
|
|
|
usageStats: usageStats, |
|
|
|
|
log: log.New("accesscontrol"), |
|
|
|
|
scopeResolver: accesscontrol.NewScopeResolver(), |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// OSSAccessControlService is the service implementing role based access control.
|
|
|
|
|
type OSSAccessControlService struct { |
|
|
|
|
log log.Logger |
|
|
|
|
usageStats usagestats.Service |
|
|
|
|
features featuremgmt.FeatureToggles |
|
|
|
|
UsageStats usagestats.Service |
|
|
|
|
Log log.Logger |
|
|
|
|
scopeResolver accesscontrol.ScopeResolver |
|
|
|
|
provider accesscontrol.PermissionsProvider |
|
|
|
|
registrations accesscontrol.RegistrationList |
|
|
|
|
ScopeResolver accesscontrol.ScopeResolver |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (ac *OSSAccessControlService) IsDisabled() bool { |
|
|
|
|
@ -41,7 +48,7 @@ func (ac *OSSAccessControlService) IsDisabled() bool { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (ac *OSSAccessControlService) registerUsageMetrics() { |
|
|
|
|
ac.UsageStats.RegisterMetricsFunc(func(context.Context) (map[string]interface{}, error) { |
|
|
|
|
ac.usageStats.RegisterMetricsFunc(func(context.Context) (map[string]interface{}, error) { |
|
|
|
|
return map[string]interface{}{ |
|
|
|
|
"stats.oss.accesscontrol.enabled.count": ac.getUsageMetrics(), |
|
|
|
|
}, nil |
|
|
|
|
@ -74,7 +81,7 @@ func (ac *OSSAccessControlService) Evaluate(ctx context.Context, user *models.Si |
|
|
|
|
user.Permissions[user.OrgId] = accesscontrol.GroupScopesByAction(permissions) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
attributeMutator := ac.ScopeResolver.GetResolveAttributeScopeMutator(user.OrgId) |
|
|
|
|
attributeMutator := ac.scopeResolver.GetResolveAttributeScopeMutator(user.OrgId) |
|
|
|
|
resolvedEvaluator, err := evaluator.MutateScopes(ctx, attributeMutator) |
|
|
|
|
if err != nil { |
|
|
|
|
return false, err |
|
|
|
|
@ -92,12 +99,37 @@ func (ac *OSSAccessControlService) GetUserPermissions(ctx context.Context, user |
|
|
|
|
timer := prometheus.NewTimer(metrics.MAccessPermissionsSummary) |
|
|
|
|
defer timer.ObserveDuration() |
|
|
|
|
|
|
|
|
|
var err error |
|
|
|
|
keywordMutator := ac.ScopeResolver.GetResolveKeywordScopeMutator(user) |
|
|
|
|
permissions := ac.getFixedPermissions(ctx, user) |
|
|
|
|
|
|
|
|
|
dbPermissions, err := ac.provider.GetUserPermissions(ctx, accesscontrol.GetUserPermissionsQuery{ |
|
|
|
|
OrgID: user.OrgId, |
|
|
|
|
UserID: user.UserId, |
|
|
|
|
Roles: ac.GetUserBuiltInRoles(user), |
|
|
|
|
Actions: []string{}, |
|
|
|
|
}) |
|
|
|
|
if err != nil { |
|
|
|
|
return nil, err |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
builtinRoles := ac.GetUserBuiltInRoles(user) |
|
|
|
|
permissions = append(permissions, dbPermissions...) |
|
|
|
|
resolved := make([]*accesscontrol.Permission, 0, len(permissions)) |
|
|
|
|
keywordMutator := ac.scopeResolver.GetResolveKeywordScopeMutator(user) |
|
|
|
|
for _, p := range permissions { |
|
|
|
|
// if the permission has a keyword in its scope it will be resolved
|
|
|
|
|
p.Scope, err = keywordMutator(ctx, p.Scope) |
|
|
|
|
if err != nil { |
|
|
|
|
return nil, err |
|
|
|
|
} |
|
|
|
|
resolved = append(resolved, p) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return resolved, nil |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (ac *OSSAccessControlService) getFixedPermissions(ctx context.Context, user *models.SignedInUser) []*accesscontrol.Permission { |
|
|
|
|
permissions := make([]*accesscontrol.Permission, 0) |
|
|
|
|
for _, builtin := range builtinRoles { |
|
|
|
|
|
|
|
|
|
for _, builtin := range ac.GetUserBuiltInRoles(user) { |
|
|
|
|
if roleNames, ok := accesscontrol.FixedRoleGrants[builtin]; ok { |
|
|
|
|
for _, name := range roleNames { |
|
|
|
|
role, exists := accesscontrol.FixedRoles[name] |
|
|
|
|
@ -105,19 +137,13 @@ func (ac *OSSAccessControlService) GetUserPermissions(ctx context.Context, user |
|
|
|
|
continue |
|
|
|
|
} |
|
|
|
|
for i := range role.Permissions { |
|
|
|
|
// if the permission has a keyword in its scope it will be resolved
|
|
|
|
|
p := (role.Permissions[i]) |
|
|
|
|
p.Scope, err = keywordMutator(ctx, p.Scope) |
|
|
|
|
if err != nil { |
|
|
|
|
return nil, err |
|
|
|
|
} |
|
|
|
|
permissions = append(permissions, &p) |
|
|
|
|
permissions = append(permissions, &role.Permissions[i]) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return permissions, nil |
|
|
|
|
return permissions |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (ac *OSSAccessControlService) GetUserBuiltInRoles(user *models.SignedInUser) []string { |
|
|
|
|
@ -138,7 +164,7 @@ func (ac *OSSAccessControlService) saveFixedRole(role accesscontrol.RoleDTO) { |
|
|
|
|
// needs to be increased. Hence, we don't overwrite a role with a
|
|
|
|
|
// greater version.
|
|
|
|
|
if storedRole.Version >= role.Version { |
|
|
|
|
ac.Log.Debug("the has already been stored in a greater version, skipping registration", "role", role.Name) |
|
|
|
|
ac.log.Debug("the role has already been stored in a greater version, skipping registration", "role", role.Name) |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
@ -154,7 +180,7 @@ func (ac *OSSAccessControlService) assignFixedRole(role accesscontrol.RoleDTO, b |
|
|
|
|
if ok { |
|
|
|
|
for _, assignedRole := range assignments { |
|
|
|
|
if assignedRole == role.Name { |
|
|
|
|
ac.Log.Debug("the role has already been assigned", "rolename", role.Name, "build_in_role", builtInRole) |
|
|
|
|
ac.log.Debug("the role has already been assigned", "rolename", role.Name, "build_in_role", builtInRole) |
|
|
|
|
alreadyAssigned = true |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
@ -214,5 +240,5 @@ func (ac *OSSAccessControlService) DeclareFixedRoles(registrations ...accesscont |
|
|
|
|
// RegisterAttributeScopeResolver allows the caller to register scope resolvers for a
|
|
|
|
|
// specific scope prefix (ex: datasources:name:)
|
|
|
|
|
func (ac *OSSAccessControlService) RegisterAttributeScopeResolver(scopePrefix string, resolver accesscontrol.AttributeScopeResolveFunc) { |
|
|
|
|
ac.ScopeResolver.AddAttributeResolver(scopePrefix, resolver) |
|
|
|
|
ac.scopeResolver.AddAttributeResolver(scopePrefix, resolver) |
|
|
|
|
} |
|
|
|
|
|