Refactor RBAC rule cloning route for role
It moves role permission cloning under /system/roles from /system/permissions, since cloning action copies all rules, and it can not be limited per-component and also shifted all respective service methods to role service and removed Rbac rule cloning methods from access-control template.
This commit is contained in:
84
.env.example
84
.env.example
@@ -33,7 +33,7 @@
|
||||
|
||||
###############################################################################
|
||||
# Allow insecure (invalid, expired TLS/SSL certificates) connections.
|
||||
#
|
||||
#
|
||||
# [IMPORTANT]
|
||||
# ====
|
||||
# We strongly recommend keeping this value set to false except for local development or demos.
|
||||
@@ -191,7 +191,7 @@
|
||||
|
||||
###############################################################################
|
||||
# Password for the web console endpoint. When running in dev environment, password is not required.
|
||||
#
|
||||
#
|
||||
# Corteza intentionally sets default password to random chars to prevent security incidents.
|
||||
# Type: string
|
||||
# Default: <no value>
|
||||
@@ -278,7 +278,7 @@
|
||||
# Email sending
|
||||
#
|
||||
# Configure your local SMTP server or use one of the available providers.
|
||||
#
|
||||
#
|
||||
# These values are copied to settings when the server starts and can be managed from the administration console.
|
||||
# We recommend you remove these values after they are copied to settings.
|
||||
# If server detects difference between these options and settings, it shows a warning in the log on server start.
|
||||
@@ -348,13 +348,13 @@
|
||||
|
||||
###############################################################################
|
||||
# Enables actionlog for compose record create, update, and delete. which is disabled by default.
|
||||
#
|
||||
#
|
||||
# [IMPORTANT]
|
||||
# ====
|
||||
# This is temp fix for now, it will be removed completely in future release.
|
||||
# Once new env var will be introduced for actionlog policy, which will enable more control over action log policies.
|
||||
# ====
|
||||
#
|
||||
#
|
||||
# Type: bool
|
||||
# Default: <no value>
|
||||
# ACTIONLOG_COMPOSE_RECORD_ENABLED=<no value>
|
||||
@@ -431,7 +431,7 @@
|
||||
|
||||
###############################################################################
|
||||
# Password security allows you to disable constraints to which passwords must conform to.
|
||||
#
|
||||
#
|
||||
# [CAUTION]
|
||||
# ====
|
||||
# Disabling password security can be useful for development environments as it removes the need for complex passwords.
|
||||
@@ -443,7 +443,7 @@
|
||||
|
||||
###############################################################################
|
||||
# Secret used for signing JWT tokens.
|
||||
#
|
||||
#
|
||||
# [IMPORTANT]
|
||||
# ====
|
||||
# If secret is not set, system auto-generates one from DB_DSN and HOSTNAME environment variables.
|
||||
@@ -461,7 +461,7 @@
|
||||
|
||||
###############################################################################
|
||||
# Lifetime of the refresh token. Should be much longer than lifetime of the access token.
|
||||
#
|
||||
#
|
||||
# Refresh tokens are used to exchange expired access tokens with new ones.
|
||||
# Type: time.Duration
|
||||
# Default: 72h
|
||||
@@ -469,7 +469,7 @@
|
||||
|
||||
###############################################################################
|
||||
# Redirect URL to be sent with OAuth2 authentication request to provider
|
||||
#
|
||||
#
|
||||
# `provider` placeholder is replaced with the actual value when used.
|
||||
# Type: string
|
||||
# Default: <no value>
|
||||
@@ -477,7 +477,7 @@
|
||||
|
||||
###############################################################################
|
||||
# Secret used for securing cookies
|
||||
#
|
||||
#
|
||||
# [IMPORTANT]
|
||||
# ====
|
||||
# If secret is not set, system auto-generates one from DB_DSN and HOSTNAME environment variables.
|
||||
@@ -520,21 +520,21 @@
|
||||
|
||||
###############################################################################
|
||||
# Maximum time user is allowed to stay idle when logged in without "remember-me" option and before session is expired.
|
||||
#
|
||||
#
|
||||
# Recomended value is between an hour and a day.
|
||||
#
|
||||
#
|
||||
# [IMPORTANT]
|
||||
# ====
|
||||
# This affects only profile (/auth) pages. Using applications (admin, compose, ...) does not prolong the session.
|
||||
# ====
|
||||
#
|
||||
#
|
||||
# Type: time.Duration
|
||||
# Default: 24h
|
||||
# AUTH_SESSION_LIFETIME=24h
|
||||
|
||||
###############################################################################
|
||||
# Duration of the session in /auth lasts when user logs-in with "remember-me" option.
|
||||
#
|
||||
#
|
||||
# If set to 0, "remember-me" option is removed.
|
||||
# Type: time.Duration
|
||||
# Default: 8640h
|
||||
@@ -561,7 +561,7 @@
|
||||
|
||||
###############################################################################
|
||||
# Secret used for securing CSRF protection
|
||||
#
|
||||
#
|
||||
# [IMPORTANT]
|
||||
# ====
|
||||
# If secret is not set, system auto-generates one from DB_DSN and HOSTNAME environment variables.
|
||||
@@ -591,19 +591,19 @@
|
||||
|
||||
###############################################################################
|
||||
# Handle for OAuth2 client used for automatic redirect from /auth/oauth2/go endpoint.
|
||||
#
|
||||
#
|
||||
# This simplifies configuration for OAuth2 flow for Corteza Web applications as it removes
|
||||
# the need to suply redirection URL and client ID (oauth2/go endpoint does that internally)
|
||||
#
|
||||
#
|
||||
# Type: string
|
||||
# Default: corteza-webapp
|
||||
# AUTH_DEFAULT_CLIENT=corteza-webapp
|
||||
|
||||
###############################################################################
|
||||
# Path to js, css, images and template source files
|
||||
#
|
||||
#
|
||||
# When corteza starts, if path exists it tries to load template files from it.
|
||||
#
|
||||
#
|
||||
# When empty path is set (default value), embedded files are used.
|
||||
# Type: string
|
||||
# Default: <no value>
|
||||
@@ -612,7 +612,7 @@
|
||||
###############################################################################
|
||||
# When enabled, corteza reloads template before every execution.
|
||||
# Enable this for debugging or when developing auth templates.
|
||||
#
|
||||
#
|
||||
# Should be disabled in production where templates do not change between server restarts.
|
||||
# Type: bool
|
||||
# Default: <no value>
|
||||
@@ -790,9 +790,9 @@
|
||||
###############################################################################
|
||||
# List of compa delimited languages (language tags) to enable.
|
||||
# In case when an enabled language can not be loaded, error is logged.
|
||||
#
|
||||
#
|
||||
# When loading language configurations (config.xml) from the configured path(s).
|
||||
#
|
||||
#
|
||||
# Type: string
|
||||
# Default: en
|
||||
# LOCALE_LANGUAGES=en
|
||||
@@ -807,7 +807,7 @@
|
||||
# Name of the query string parameter used to pass the language tag (it overrides Accept-Language header).
|
||||
# Set it to empty string to disable detection from the query string.
|
||||
# This parameter is ignored if only one language is enabled
|
||||
#
|
||||
#
|
||||
# Type: string
|
||||
# Default: lng
|
||||
# LOCALE_QUERY_STRING_PARAM=lng
|
||||
@@ -838,9 +838,9 @@
|
||||
|
||||
###############################################################################
|
||||
# Disables JSON format for logging and enables more human-readable output with colors.
|
||||
#
|
||||
#
|
||||
# Disable for production.
|
||||
#
|
||||
#
|
||||
# Type: bool
|
||||
# Default: <no value>
|
||||
# LOG_DEBUG=<no value>
|
||||
@@ -848,11 +848,11 @@
|
||||
###############################################################################
|
||||
# Minimum logging level. If set to "warn",
|
||||
# Levels warn, error, dpanic panic and fatal will be logged.
|
||||
#
|
||||
#
|
||||
# Recommended value for production: warn
|
||||
#
|
||||
#
|
||||
# Possible values: debug, info, warn, error, dpanic, panic, fatal
|
||||
#
|
||||
#
|
||||
# Type: string
|
||||
# Default: warn
|
||||
# LOG_LEVEL=warn
|
||||
@@ -860,25 +860,25 @@
|
||||
###############################################################################
|
||||
# Log filtering rules by level and name (log-level:log-namespace).
|
||||
# Please note that level (LOG_LEVEL) is applied before filter and it affects the final output!
|
||||
#
|
||||
#
|
||||
# Leave unset for production.
|
||||
#
|
||||
#
|
||||
# Example:
|
||||
# `warn+:* *:auth,workflow.*`
|
||||
# Log warnings, errors, panic, fatals. Everything from auth and workflow is logged.
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
# See more examples and documentation here: https://github.com/moul/zapfilter
|
||||
#
|
||||
#
|
||||
# Type: string
|
||||
# Default: <no value>
|
||||
# LOG_FILTER=<no value>
|
||||
|
||||
###############################################################################
|
||||
# Set to true to see where the logging was called from.
|
||||
#
|
||||
#
|
||||
# Disable for production.
|
||||
#
|
||||
#
|
||||
# Type: bool
|
||||
# Default: <no value>
|
||||
# LOG_INCLUDE_CALLER=<no value>
|
||||
@@ -886,9 +886,9 @@
|
||||
###############################################################################
|
||||
# Include stack-trace when logging at a specified level or below.
|
||||
# Disable for production.
|
||||
#
|
||||
#
|
||||
# Possible values: debug, info, warn, error, dpanic, panic, fatal
|
||||
#
|
||||
#
|
||||
# Type: string
|
||||
# Default: dpanic
|
||||
# LOG_STACKTRACE_LEVEL=dpanic
|
||||
@@ -1000,11 +1000,11 @@
|
||||
#
|
||||
# Provisioning allows you to configure a {PRODUCT_NAME} instance when deployed.
|
||||
# It occurs automatically after the {PRODUCT_NAME} server starts.
|
||||
#
|
||||
#
|
||||
# [IMPORTANT]
|
||||
# ====
|
||||
# We recommend you to keep provisioning enabled as it simplifies version updates by updating the database and updating settings.
|
||||
#
|
||||
#
|
||||
# If you're doing local development or some debugging, you can disable this.
|
||||
# ====
|
||||
#
|
||||
@@ -1041,7 +1041,7 @@
|
||||
# ====
|
||||
# These parameters help in the development and testing process.
|
||||
# When you are deploying to production, these should be disabled to improve performance and reduce storage usage.
|
||||
#
|
||||
#
|
||||
# You should configure external services such as Sentry or ELK to keep track of logs and error reports.
|
||||
# ====
|
||||
#
|
||||
@@ -1141,7 +1141,7 @@
|
||||
# Delay system startup
|
||||
#
|
||||
# You can configure these options to defer API execution until another external (HTTP) service is up and running.
|
||||
#
|
||||
#
|
||||
# [ TIP ]
|
||||
# ====
|
||||
# Delaying API execution can come in handy in complex setups where execution order is important.
|
||||
@@ -1165,7 +1165,7 @@
|
||||
###############################################################################
|
||||
# Space delimited list of hosts and/or URLs to probe.
|
||||
# Host format: `host` or `host:443` (port will default to 80).
|
||||
#
|
||||
#
|
||||
# [NOTE]
|
||||
# ====
|
||||
# Services are probed in parallel.
|
||||
|
||||
12
automation/service/access_control.gen.go
generated
12
automation/service/access_control.gen.go
generated
@@ -26,7 +26,6 @@ type (
|
||||
Evaluate(rbac.Session, string, rbac.Resource) rbac.Evaluated
|
||||
Grant(context.Context, ...*rbac.Rule) error
|
||||
FindRulesByRoleID(roleID uint64) (rr rbac.RuleSet)
|
||||
CloneRulesByRoleID(ctx context.Context, fromRoleID uint64, toRoleID ...uint64) error
|
||||
}
|
||||
|
||||
accessControl struct {
|
||||
@@ -261,17 +260,6 @@ func (svc accessControl) FindRulesByRoleID(ctx context.Context, roleID uint64) (
|
||||
return svc.rbac.FindRulesByRoleID(roleID), nil
|
||||
}
|
||||
|
||||
// CloneRulesByRoleID clone all rules of a Role S to a specific Role T
|
||||
//
|
||||
// This function is auto-generated
|
||||
func (svc accessControl) CloneRulesByRoleID(ctx context.Context, fromRoleID uint64, toRoleID ...uint64) error {
|
||||
if !svc.CanGrant(ctx) {
|
||||
return AccessControlErrNotAllowedToSetPermissions()
|
||||
}
|
||||
|
||||
return svc.rbac.CloneRulesByRoleID(ctx, fromRoleID, toRoleID...)
|
||||
}
|
||||
|
||||
// CanReadWorkflow checks if current user can read workflow
|
||||
//
|
||||
// This function is auto-generated
|
||||
|
||||
@@ -25,7 +25,6 @@ type (
|
||||
Evaluate(rbac.Session, string, rbac.Resource) rbac.Evaluated
|
||||
Grant(context.Context, ...*rbac.Rule) error
|
||||
FindRulesByRoleID(roleID uint64) (rr rbac.RuleSet)
|
||||
CloneRulesByRoleID(ctx context.Context, fromRoleID uint64, toRoleID ...uint64) error
|
||||
}
|
||||
|
||||
accessControl struct {
|
||||
@@ -206,17 +205,6 @@ func (svc accessControl) FindRulesByRoleID(ctx context.Context, roleID uint64) (
|
||||
return svc.rbac.FindRulesByRoleID(roleID), nil
|
||||
}
|
||||
|
||||
// CloneRulesByRoleID clone all rules of a Role S to a specific Role T
|
||||
//
|
||||
// This function is auto-generated
|
||||
func (svc accessControl) CloneRulesByRoleID(ctx context.Context, fromRoleID uint64, toRoleID ...uint64) error {
|
||||
if !svc.CanGrant(ctx) {
|
||||
return AccessControlErrNotAllowedToSetPermissions()
|
||||
}
|
||||
|
||||
return svc.rbac.CloneRulesByRoleID(ctx, fromRoleID, toRoleID...)
|
||||
}
|
||||
|
||||
{{- range .operations }}
|
||||
// {{ .checkFuncName }} checks if current user can {{ lower .description }}
|
||||
//
|
||||
|
||||
25
compose/service/access_control.gen.go
generated
25
compose/service/access_control.gen.go
generated
@@ -23,11 +23,9 @@ type (
|
||||
}
|
||||
|
||||
rbacService interface {
|
||||
Can(rbac.Session, string, rbac.Resource) bool
|
||||
Evaluate(rbac.Session, string, rbac.Resource) rbac.Evaluated
|
||||
Grant(context.Context, ...*rbac.Rule) error
|
||||
FindRulesByRoleID(roleID uint64) (rr rbac.RuleSet)
|
||||
CloneRulesByRoleID(ctx context.Context, fromRoleID uint64, toRoleID ...uint64) error
|
||||
}
|
||||
|
||||
accessControl struct {
|
||||
@@ -46,14 +44,14 @@ func AccessControl(rms roleMemberSearcher) *accessControl {
|
||||
}
|
||||
}
|
||||
|
||||
func (svc *accessControl) can(ctx context.Context, op string, res rbac.Resource) bool {
|
||||
return svc.rbac.Can(rbac.ContextToSession(ctx), op, res)
|
||||
func (svc accessControl) can(ctx context.Context, op string, res rbac.Resource) bool {
|
||||
return svc.rbac.Evaluate(rbac.ContextToSession(ctx), op, res).Can
|
||||
}
|
||||
|
||||
// Effective returns a list of effective permissions for all given resource
|
||||
//
|
||||
// This function is auto-generated
|
||||
func (svc *accessControl) Effective(ctx context.Context, rr ...rbac.Resource) (ee rbac.EffectiveSet) {
|
||||
func (svc accessControl) Effective(ctx context.Context, rr ...rbac.Resource) (ee rbac.EffectiveSet) {
|
||||
for _, res := range rr {
|
||||
r := res.RbacResource()
|
||||
for op := range rbacResourceOperations(r) {
|
||||
@@ -67,7 +65,7 @@ func (svc *accessControl) Effective(ctx context.Context, rr ...rbac.Resource) (e
|
||||
// Evaluate returns a list of permissions evaluated for the given user/roles combo
|
||||
//
|
||||
// This function is auto-generated
|
||||
func (svc *accessControl) Evaluate(ctx context.Context, userID uint64, roles []uint64, rr ...string) (ee rbac.EvaluatedSet, err error) {
|
||||
func (svc accessControl) Evaluate(ctx context.Context, userID uint64, roles []uint64, rr ...string) (ee rbac.EvaluatedSet, err error) {
|
||||
// Reusing the grant permission since this is who the feature is for
|
||||
if !svc.CanGrant(ctx) {
|
||||
// @todo should be altered to check grant permissions PER resource
|
||||
@@ -123,7 +121,7 @@ func (svc *accessControl) Evaluate(ctx context.Context, userID uint64, roles []u
|
||||
// Resources returns list of resources
|
||||
//
|
||||
// This function is auto-generated
|
||||
func (svc *accessControl) Resources() []rbac.Resource {
|
||||
func (svc accessControl) Resources() []rbac.Resource {
|
||||
return []rbac.Resource{
|
||||
rbac.NewResource(types.ChartRbacResource(0, 0)),
|
||||
rbac.NewResource(types.ModuleRbacResource(0, 0)),
|
||||
@@ -138,7 +136,7 @@ func (svc *accessControl) Resources() []rbac.Resource {
|
||||
// List returns list of operations on all resources
|
||||
//
|
||||
// This function is auto-generated
|
||||
func (svc *accessControl) List() (out []map[string]string) {
|
||||
func (svc accessControl) List() (out []map[string]string) {
|
||||
def := []map[string]string{
|
||||
{
|
||||
"type": types.ChartResourceType,
|
||||
@@ -372,17 +370,6 @@ func (svc accessControl) FindRulesByRoleID(ctx context.Context, roleID uint64) (
|
||||
return svc.rbac.FindRulesByRoleID(roleID), nil
|
||||
}
|
||||
|
||||
// CloneRulesByRoleID clone all rules of a Role S to a specific Role T
|
||||
//
|
||||
// This function is auto-generated
|
||||
func (svc accessControl) CloneRulesByRoleID(ctx context.Context, fromRoleID uint64, toRoleID ...uint64) error {
|
||||
if !svc.CanGrant(ctx) {
|
||||
return AccessControlErrNotAllowedToSetPermissions()
|
||||
}
|
||||
|
||||
return svc.rbac.CloneRulesByRoleID(ctx, fromRoleID, toRoleID...)
|
||||
}
|
||||
|
||||
// CanReadChart checks if current user can read
|
||||
//
|
||||
// This function is auto-generated
|
||||
|
||||
12
federation/service/access_control.gen.go
generated
12
federation/service/access_control.gen.go
generated
@@ -26,7 +26,6 @@ type (
|
||||
Evaluate(rbac.Session, string, rbac.Resource) rbac.Evaluated
|
||||
Grant(context.Context, ...*rbac.Rule) error
|
||||
FindRulesByRoleID(roleID uint64) (rr rbac.RuleSet)
|
||||
CloneRulesByRoleID(ctx context.Context, fromRoleID uint64, toRoleID ...uint64) error
|
||||
}
|
||||
|
||||
accessControl struct {
|
||||
@@ -248,17 +247,6 @@ func (svc accessControl) FindRulesByRoleID(ctx context.Context, roleID uint64) (
|
||||
return svc.rbac.FindRulesByRoleID(roleID), nil
|
||||
}
|
||||
|
||||
// CloneRulesByRoleID clone all rules of a Role S to a specific Role T
|
||||
//
|
||||
// This function is auto-generated
|
||||
func (svc accessControl) CloneRulesByRoleID(ctx context.Context, fromRoleID uint64, toRoleID ...uint64) error {
|
||||
if !svc.CanGrant(ctx) {
|
||||
return AccessControlErrNotAllowedToSetPermissions()
|
||||
}
|
||||
|
||||
return svc.rbac.CloneRulesByRoleID(ctx, fromRoleID, toRoleID...)
|
||||
}
|
||||
|
||||
// CanManageNode checks if current user can manage federation node
|
||||
//
|
||||
// This function is auto-generated
|
||||
|
||||
@@ -396,6 +396,21 @@ endpoints:
|
||||
type: map[string]interface{}
|
||||
parser: parseMapStringInterface
|
||||
title: Arguments to pass to the script
|
||||
- name: cloneRules
|
||||
path: "/{roleID}/rules/clone"
|
||||
method: POST
|
||||
title: Clone permission settings to a role
|
||||
parameters:
|
||||
path:
|
||||
- name: roleID
|
||||
type: uint64
|
||||
required: true
|
||||
title: Role ID
|
||||
get:
|
||||
- name: cloneToRoleID
|
||||
type: "[]string"
|
||||
required: true
|
||||
title: Clone set of rules to roleID
|
||||
- title: Users
|
||||
path: "/users"
|
||||
entrypoint: user
|
||||
@@ -1272,21 +1287,6 @@ endpoints:
|
||||
type: rbac.RuleSet
|
||||
required: true
|
||||
title: List of permission rules to set
|
||||
- name: clone
|
||||
path: "/{roleID}/rules/clone"
|
||||
method: POST
|
||||
title: Clone permission settings to a role
|
||||
parameters:
|
||||
path:
|
||||
- name: roleID
|
||||
type: uint64
|
||||
required: true
|
||||
title: Role ID
|
||||
get:
|
||||
- name: cloneToRoleID
|
||||
type: "[]string"
|
||||
required: true
|
||||
title: Clone set of rules to roleID
|
||||
- title: Reminders
|
||||
entrypoint: reminder
|
||||
path: "/reminder"
|
||||
|
||||
@@ -25,7 +25,6 @@ type (
|
||||
Read(context.Context, *request.PermissionsRead) (interface{}, error)
|
||||
Delete(context.Context, *request.PermissionsDelete) (interface{}, error)
|
||||
Update(context.Context, *request.PermissionsUpdate) (interface{}, error)
|
||||
Clone(context.Context, *request.PermissionsClone) (interface{}, error)
|
||||
}
|
||||
|
||||
// HTTP API interface
|
||||
@@ -36,7 +35,6 @@ type (
|
||||
Read func(http.ResponseWriter, *http.Request)
|
||||
Delete func(http.ResponseWriter, *http.Request)
|
||||
Update func(http.ResponseWriter, *http.Request)
|
||||
Clone func(http.ResponseWriter, *http.Request)
|
||||
}
|
||||
)
|
||||
|
||||
@@ -136,22 +134,6 @@ func NewPermissions(h PermissionsAPI) *Permissions {
|
||||
return
|
||||
}
|
||||
|
||||
api.Send(w, r, value)
|
||||
},
|
||||
Clone: func(w http.ResponseWriter, r *http.Request) {
|
||||
defer r.Body.Close()
|
||||
params := request.NewPermissionsClone()
|
||||
if err := params.Fill(r); err != nil {
|
||||
api.Send(w, r, err)
|
||||
return
|
||||
}
|
||||
|
||||
value, err := h.Clone(r.Context(), params)
|
||||
if err != nil {
|
||||
api.Send(w, r, err)
|
||||
return
|
||||
}
|
||||
|
||||
api.Send(w, r, value)
|
||||
},
|
||||
}
|
||||
@@ -166,6 +148,5 @@ func (h Permissions) MountRoutes(r chi.Router, middlewares ...func(http.Handler)
|
||||
r.Get("/permissions/{roleID}/rules", h.Read)
|
||||
r.Delete("/permissions/{roleID}/rules", h.Delete)
|
||||
r.Patch("/permissions/{roleID}/rules", h.Update)
|
||||
r.Post("/permissions/{roleID}/rules/clone", h.Clone)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -33,6 +33,7 @@ type (
|
||||
MemberAdd(context.Context, *request.RoleMemberAdd) (interface{}, error)
|
||||
MemberRemove(context.Context, *request.RoleMemberRemove) (interface{}, error)
|
||||
TriggerScript(context.Context, *request.RoleTriggerScript) (interface{}, error)
|
||||
CloneRules(context.Context, *request.RoleCloneRules) (interface{}, error)
|
||||
}
|
||||
|
||||
// HTTP API interface
|
||||
@@ -51,6 +52,7 @@ type (
|
||||
MemberAdd func(http.ResponseWriter, *http.Request)
|
||||
MemberRemove func(http.ResponseWriter, *http.Request)
|
||||
TriggerScript func(http.ResponseWriter, *http.Request)
|
||||
CloneRules func(http.ResponseWriter, *http.Request)
|
||||
}
|
||||
)
|
||||
|
||||
@@ -278,6 +280,22 @@ func NewRole(h RoleAPI) *Role {
|
||||
return
|
||||
}
|
||||
|
||||
api.Send(w, r, value)
|
||||
},
|
||||
CloneRules: func(w http.ResponseWriter, r *http.Request) {
|
||||
defer r.Body.Close()
|
||||
params := request.NewRoleCloneRules()
|
||||
if err := params.Fill(r); err != nil {
|
||||
api.Send(w, r, err)
|
||||
return
|
||||
}
|
||||
|
||||
value, err := h.CloneRules(r.Context(), params)
|
||||
if err != nil {
|
||||
api.Send(w, r, err)
|
||||
return
|
||||
}
|
||||
|
||||
api.Send(w, r, value)
|
||||
},
|
||||
}
|
||||
@@ -300,5 +318,6 @@ func (h Role) MountRoutes(r chi.Router, middlewares ...func(http.Handler) http.H
|
||||
r.Post("/roles/{roleID}/member/{userID}", h.MemberAdd)
|
||||
r.Delete("/roles/{roleID}/member/{userID}", h.MemberRemove)
|
||||
r.Post("/roles/{roleID}/trigger", h.TriggerScript)
|
||||
r.Post("/roles/{roleID}/rules/clone", h.CloneRules)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@ import (
|
||||
"context"
|
||||
|
||||
"github.com/cortezaproject/corteza-server/pkg/api"
|
||||
"github.com/cortezaproject/corteza-server/pkg/payload"
|
||||
"github.com/cortezaproject/corteza-server/pkg/rbac"
|
||||
"github.com/cortezaproject/corteza-server/system/rest/request"
|
||||
"github.com/cortezaproject/corteza-server/system/service"
|
||||
@@ -21,7 +20,6 @@ type (
|
||||
Evaluate(ctx context.Context, user uint64, roles []uint64, rr ...string) (ee rbac.EvaluatedSet, err error)
|
||||
List() []map[string]string
|
||||
FindRulesByRoleID(context.Context, uint64) (rbac.RuleSet, error)
|
||||
CloneRulesByRoleID(ctx context.Context, roleID uint64, toRoleID ...uint64) error
|
||||
Grant(ctx context.Context, rr ...*rbac.Rule) error
|
||||
}
|
||||
)
|
||||
@@ -69,11 +67,3 @@ func (ctrl Permissions) Update(ctx context.Context, r *request.PermissionsUpdate
|
||||
|
||||
return api.OK(), ctrl.ac.Grant(ctx, r.Rules...)
|
||||
}
|
||||
|
||||
// Clone all RBAC rules on ALL components (not just system)
|
||||
//
|
||||
// @todo needs to be moved under roles
|
||||
func (ctrl Permissions) Clone(ctx context.Context, r *request.PermissionsClone) (interface{}, error) {
|
||||
// Clone rules from role S to role T
|
||||
return api.OK(), ctrl.ac.CloneRulesByRoleID(ctx, r.RoleID, payload.ParseUint64s(r.CloneToRoleID)...)
|
||||
}
|
||||
|
||||
@@ -86,18 +86,6 @@ type (
|
||||
// List of permission rules to set
|
||||
Rules rbac.RuleSet
|
||||
}
|
||||
|
||||
PermissionsClone struct {
|
||||
// RoleID PATH parameter
|
||||
//
|
||||
// Role ID
|
||||
RoleID uint64 `json:",string"`
|
||||
|
||||
// CloneToRoleID GET parameter
|
||||
//
|
||||
// Clone set of rules to roleID
|
||||
CloneToRoleID []string
|
||||
}
|
||||
)
|
||||
|
||||
// NewPermissionsList request
|
||||
@@ -366,61 +354,3 @@ func (r *PermissionsUpdate) Fill(req *http.Request) (err error) {
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// NewPermissionsClone request
|
||||
func NewPermissionsClone() *PermissionsClone {
|
||||
return &PermissionsClone{}
|
||||
}
|
||||
|
||||
// Auditable returns all auditable/loggable parameters
|
||||
func (r PermissionsClone) Auditable() map[string]interface{} {
|
||||
return map[string]interface{}{
|
||||
"roleID": r.RoleID,
|
||||
"cloneToRoleID": r.CloneToRoleID,
|
||||
}
|
||||
}
|
||||
|
||||
// Auditable returns all auditable/loggable parameters
|
||||
func (r PermissionsClone) GetRoleID() uint64 {
|
||||
return r.RoleID
|
||||
}
|
||||
|
||||
// Auditable returns all auditable/loggable parameters
|
||||
func (r PermissionsClone) GetCloneToRoleID() []string {
|
||||
return r.CloneToRoleID
|
||||
}
|
||||
|
||||
// Fill processes request and fills internal variables
|
||||
func (r *PermissionsClone) Fill(req *http.Request) (err error) {
|
||||
|
||||
{
|
||||
// GET params
|
||||
tmp := req.URL.Query()
|
||||
|
||||
if val, ok := tmp["cloneToRoleID[]"]; ok {
|
||||
r.CloneToRoleID, err = val, nil
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else if val, ok := tmp["cloneToRoleID"]; ok {
|
||||
r.CloneToRoleID, err = val, nil
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
var val string
|
||||
// path params
|
||||
|
||||
val = chi.URLParam(req, "roleID")
|
||||
r.RoleID, err = payload.ParseUint64(val), nil
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -242,6 +242,18 @@ type (
|
||||
// Arguments to pass to the script
|
||||
Args map[string]interface{}
|
||||
}
|
||||
|
||||
RoleCloneRules struct {
|
||||
// RoleID PATH parameter
|
||||
//
|
||||
// Role ID
|
||||
RoleID uint64 `json:",string"`
|
||||
|
||||
// CloneToRoleID GET parameter
|
||||
//
|
||||
// Clone set of rules to roleID
|
||||
CloneToRoleID []string
|
||||
}
|
||||
)
|
||||
|
||||
// NewRoleList request
|
||||
@@ -1284,3 +1296,61 @@ func (r *RoleTriggerScript) Fill(req *http.Request) (err error) {
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// NewRoleCloneRules request
|
||||
func NewRoleCloneRules() *RoleCloneRules {
|
||||
return &RoleCloneRules{}
|
||||
}
|
||||
|
||||
// Auditable returns all auditable/loggable parameters
|
||||
func (r RoleCloneRules) Auditable() map[string]interface{} {
|
||||
return map[string]interface{}{
|
||||
"roleID": r.RoleID,
|
||||
"cloneToRoleID": r.CloneToRoleID,
|
||||
}
|
||||
}
|
||||
|
||||
// Auditable returns all auditable/loggable parameters
|
||||
func (r RoleCloneRules) GetRoleID() uint64 {
|
||||
return r.RoleID
|
||||
}
|
||||
|
||||
// Auditable returns all auditable/loggable parameters
|
||||
func (r RoleCloneRules) GetCloneToRoleID() []string {
|
||||
return r.CloneToRoleID
|
||||
}
|
||||
|
||||
// Fill processes request and fills internal variables
|
||||
func (r *RoleCloneRules) Fill(req *http.Request) (err error) {
|
||||
|
||||
{
|
||||
// GET params
|
||||
tmp := req.URL.Query()
|
||||
|
||||
if val, ok := tmp["cloneToRoleID[]"]; ok {
|
||||
r.CloneToRoleID, err = val, nil
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else if val, ok := tmp["cloneToRoleID"]; ok {
|
||||
r.CloneToRoleID, err = val, nil
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
var val string
|
||||
// path params
|
||||
|
||||
val = chi.URLParam(req, "roleID")
|
||||
r.RoleID, err = payload.ParseUint64(val), nil
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -169,6 +169,11 @@ func (ctrl Role) Unarchive(ctx context.Context, r *request.RoleUnarchive) (inter
|
||||
return api.OK(), ctrl.role.Unarchive(ctx, r.RoleID)
|
||||
}
|
||||
|
||||
func (ctrl Role) CloneRules(ctx context.Context, r *request.RoleCloneRules) (interface{}, error) {
|
||||
// Clone rules from role S to role T
|
||||
return api.OK(), ctrl.role.CloneRules(ctx, r.RoleID, payload.ParseUint64s(r.CloneToRoleID)...)
|
||||
}
|
||||
|
||||
// deprecated
|
||||
func (ctrl Role) Merge(ctx context.Context, r *request.RoleMerge) (interface{}, error) {
|
||||
return api.OK(), nil
|
||||
|
||||
12
system/service/access_control.gen.go
generated
12
system/service/access_control.gen.go
generated
@@ -26,7 +26,6 @@ type (
|
||||
Evaluate(rbac.Session, string, rbac.Resource) rbac.Evaluated
|
||||
Grant(context.Context, ...*rbac.Rule) error
|
||||
FindRulesByRoleID(roleID uint64) (rr rbac.RuleSet)
|
||||
CloneRulesByRoleID(ctx context.Context, fromRoleID uint64, toRoleID ...uint64) error
|
||||
}
|
||||
|
||||
accessControl struct {
|
||||
@@ -578,17 +577,6 @@ func (svc accessControl) FindRulesByRoleID(ctx context.Context, roleID uint64) (
|
||||
return svc.rbac.FindRulesByRoleID(roleID), nil
|
||||
}
|
||||
|
||||
// CloneRulesByRoleID clone all rules of a Role S to a specific Role T
|
||||
//
|
||||
// This function is auto-generated
|
||||
func (svc accessControl) CloneRulesByRoleID(ctx context.Context, fromRoleID uint64, toRoleID ...uint64) error {
|
||||
if !svc.CanGrant(ctx) {
|
||||
return AccessControlErrNotAllowedToSetPermissions()
|
||||
}
|
||||
|
||||
return svc.rbac.CloneRulesByRoleID(ctx, fromRoleID, toRoleID...)
|
||||
}
|
||||
|
||||
// CanReadApplication checks if current user can read application
|
||||
//
|
||||
// This function is auto-generated
|
||||
|
||||
@@ -28,6 +28,7 @@ type (
|
||||
|
||||
ac roleAccessController
|
||||
eventbus eventDispatcher
|
||||
rbac rbacRuleService
|
||||
|
||||
user UserService
|
||||
auth roleAuth
|
||||
@@ -42,6 +43,8 @@ type (
|
||||
}
|
||||
|
||||
roleAccessController interface {
|
||||
CanGrant(context.Context) bool
|
||||
|
||||
CanSearchRoles(context.Context) bool
|
||||
CanCreateRole(context.Context) bool
|
||||
CanReadRole(context.Context, *types.Role) bool
|
||||
@@ -67,6 +70,7 @@ type (
|
||||
Unarchive(ctx context.Context, ID uint64) error
|
||||
Delete(ctx context.Context, ID uint64) error
|
||||
Undelete(ctx context.Context, ID uint64) error
|
||||
CloneRules(ctx context.Context, ID uint64, cloneToRoleID ...uint64) error
|
||||
|
||||
Membership(ctx context.Context, userID uint64) (types.RoleMemberSet, error)
|
||||
MemberList(ctx context.Context, roleID uint64) (types.RoleMemberSet, error)
|
||||
@@ -82,15 +86,20 @@ type (
|
||||
UpdateRoles(rr ...*rbac.Role)
|
||||
}
|
||||
|
||||
rbacRuleService interface {
|
||||
CloneRulesByRoleID(ctx context.Context, roleID uint64, toRoleID ...uint64) error
|
||||
}
|
||||
|
||||
roleAuth interface {
|
||||
RemoveAccessTokens(context.Context, *types.User) error
|
||||
}
|
||||
)
|
||||
|
||||
func Role() *role {
|
||||
func Role(rbac rbacRuleService) *role {
|
||||
return &role{
|
||||
ac: DefaultAccessControl,
|
||||
eventbus: eventbus.Service(),
|
||||
rbac: rbac,
|
||||
|
||||
actionlog: DefaultActionlog,
|
||||
|
||||
@@ -604,6 +613,14 @@ func (svc role) Unarchive(ctx context.Context, roleID uint64) (err error) {
|
||||
return svc.recordAction(ctx, raProps, RoleActionUnarchive, err)
|
||||
}
|
||||
|
||||
func (svc role) CloneRules(ctx context.Context, roleID uint64, cloneToRoleID ...uint64) (err error) {
|
||||
if !svc.ac.CanGrant(ctx) {
|
||||
return RoleErrNotAllowedToCloneRules()
|
||||
}
|
||||
|
||||
return svc.rbac.CloneRulesByRoleID(ctx, roleID, cloneToRoleID...)
|
||||
}
|
||||
|
||||
func (svc role) Membership(ctx context.Context, userID uint64) (types.RoleMemberSet, error) {
|
||||
mm, _, err := store.SearchRoleMembers(ctx, svc.store, types.RoleMemberFilter{UserID: userID})
|
||||
return mm, err
|
||||
|
||||
36
system/service/role_actions.gen.go
generated
36
system/service/role_actions.gen.go
generated
@@ -1039,6 +1039,42 @@ func RoleErrNotAllowedToUnarchive(mm ...*roleActionProps) *errors.Error {
|
||||
return e
|
||||
}
|
||||
|
||||
// RoleErrNotAllowedToCloneRules returns "system:role.notAllowedToCloneRules" as *errors.Error
|
||||
//
|
||||
//
|
||||
// This function is auto-generated.
|
||||
//
|
||||
func RoleErrNotAllowedToCloneRules(mm ...*roleActionProps) *errors.Error {
|
||||
var p = &roleActionProps{}
|
||||
if len(mm) > 0 {
|
||||
p = mm[0]
|
||||
}
|
||||
|
||||
var e = errors.New(
|
||||
errors.KindInternal,
|
||||
|
||||
p.Format("not allowed to clone rules of this role", nil),
|
||||
|
||||
errors.Meta("type", "notAllowedToCloneRules"),
|
||||
errors.Meta("resource", "system:role"),
|
||||
|
||||
// action log entry; no formatting, it will be applied inside recordAction fn.
|
||||
errors.Meta(roleLogMetaKey{}, "failed to clone rules of {{role.handle}}; insufficient permissions"),
|
||||
errors.Meta(rolePropsMetaKey{}, p),
|
||||
|
||||
// translation namespace & key
|
||||
errors.Meta(locale.ErrorMetaNamespace{}, "system"),
|
||||
errors.Meta(locale.ErrorMetaKey{}, "role.errors.notAllowedToCloneRules"),
|
||||
|
||||
errors.StackSkip(1),
|
||||
)
|
||||
|
||||
if len(mm) > 0 {
|
||||
}
|
||||
|
||||
return e
|
||||
}
|
||||
|
||||
// RoleErrNotAllowedToManageMembers returns "system:role.notAllowedToManageMembers" as *errors.Error
|
||||
//
|
||||
//
|
||||
|
||||
@@ -120,6 +120,10 @@ errors:
|
||||
message: "not allowed to unarchive this role"
|
||||
log: "failed to unarchive {{role.handle}}; insufficient permissions"
|
||||
|
||||
- error: notAllowedToCloneRules
|
||||
message: "not allowed to clone rules of this role"
|
||||
log: "failed to clone rules of {{role.handle}}; insufficient permissions"
|
||||
|
||||
- error: notAllowedToManageMembers
|
||||
message: "not allowed to manage role members"
|
||||
log: "failed to manage {{role.handle}} members; insufficient permissions"
|
||||
|
||||
@@ -202,7 +202,7 @@ func Initialize(ctx context.Context, log *zap.Logger, s store.Storer, ws websock
|
||||
DefaultAuthClient = AuthClient(DefaultStore, DefaultAccessControl, DefaultActionlog, eventbus.Service(), c.Auth)
|
||||
DefaultUser = User(UserOptions{LimitUsers: c.Limit.SystemUsers})
|
||||
DefaultReport = Report(DefaultStore, DefaultAccessControl, DefaultActionlog, eventbus.Service())
|
||||
DefaultRole = Role()
|
||||
DefaultRole = Role(rbac.Global())
|
||||
DefaultApplication = Application(DefaultStore, DefaultAccessControl, DefaultActionlog, eventbus.Service())
|
||||
DefaultReminder = Reminder(ctx, DefaultLogger.Named("reminder"), ws)
|
||||
DefaultSink = Sink()
|
||||
|
||||
Reference in New Issue
Block a user