Add user credentials management endpoints
This commit is contained in:
@@ -308,8 +308,7 @@ func NewRecord(h RecordAPI) *Record {
|
||||
return
|
||||
}
|
||||
|
||||
value, err := h.
|
||||
Revisions(r.Context(), params)
|
||||
value, err := h.Revisions(r.Context(), params)
|
||||
if err != nil {
|
||||
api.Send(w, r, err)
|
||||
return
|
||||
|
||||
@@ -686,6 +686,23 @@ endpoints:
|
||||
required: true
|
||||
title: ID
|
||||
|
||||
- name: listCredentials
|
||||
method: GET
|
||||
title: List user's credentials
|
||||
path: "/{userID}/credentials"
|
||||
parameters:
|
||||
path:
|
||||
- { type: uint64, name: userID, required: true, title: ID }
|
||||
|
||||
- name: deleteCredentials
|
||||
method: DELETE
|
||||
title: List user's credentials
|
||||
path: "/{userID}/credentials/{credentialsID}"
|
||||
parameters:
|
||||
path:
|
||||
- { type: uint64, name: userID, required: true, title: ID }
|
||||
- { type: uint64, name: credentialsID, required: true, title: Credentials ID }
|
||||
|
||||
- name: export
|
||||
method: GET
|
||||
title: Export users
|
||||
|
||||
@@ -34,29 +34,33 @@ type (
|
||||
MembershipRemove(context.Context, *request.UserMembershipRemove) (interface{}, error)
|
||||
TriggerScript(context.Context, *request.UserTriggerScript) (interface{}, error)
|
||||
SessionsRemove(context.Context, *request.UserSessionsRemove) (interface{}, error)
|
||||
ListCredentials(context.Context, *request.UserListCredentials) (interface{}, error)
|
||||
DeleteCredentials(context.Context, *request.UserDeleteCredentials) (interface{}, error)
|
||||
Export(context.Context, *request.UserExport) (interface{}, error)
|
||||
Import(context.Context, *request.UserImport) (interface{}, error)
|
||||
}
|
||||
|
||||
// HTTP API interface
|
||||
User struct {
|
||||
List func(http.ResponseWriter, *http.Request)
|
||||
Create func(http.ResponseWriter, *http.Request)
|
||||
Update func(http.ResponseWriter, *http.Request)
|
||||
PartialUpdate func(http.ResponseWriter, *http.Request)
|
||||
Read func(http.ResponseWriter, *http.Request)
|
||||
Delete func(http.ResponseWriter, *http.Request)
|
||||
Suspend func(http.ResponseWriter, *http.Request)
|
||||
Unsuspend func(http.ResponseWriter, *http.Request)
|
||||
Undelete func(http.ResponseWriter, *http.Request)
|
||||
SetPassword func(http.ResponseWriter, *http.Request)
|
||||
MembershipList func(http.ResponseWriter, *http.Request)
|
||||
MembershipAdd func(http.ResponseWriter, *http.Request)
|
||||
MembershipRemove func(http.ResponseWriter, *http.Request)
|
||||
TriggerScript func(http.ResponseWriter, *http.Request)
|
||||
SessionsRemove func(http.ResponseWriter, *http.Request)
|
||||
Export func(http.ResponseWriter, *http.Request)
|
||||
Import func(http.ResponseWriter, *http.Request)
|
||||
List func(http.ResponseWriter, *http.Request)
|
||||
Create func(http.ResponseWriter, *http.Request)
|
||||
Update func(http.ResponseWriter, *http.Request)
|
||||
PartialUpdate func(http.ResponseWriter, *http.Request)
|
||||
Read func(http.ResponseWriter, *http.Request)
|
||||
Delete func(http.ResponseWriter, *http.Request)
|
||||
Suspend func(http.ResponseWriter, *http.Request)
|
||||
Unsuspend func(http.ResponseWriter, *http.Request)
|
||||
Undelete func(http.ResponseWriter, *http.Request)
|
||||
SetPassword func(http.ResponseWriter, *http.Request)
|
||||
MembershipList func(http.ResponseWriter, *http.Request)
|
||||
MembershipAdd func(http.ResponseWriter, *http.Request)
|
||||
MembershipRemove func(http.ResponseWriter, *http.Request)
|
||||
TriggerScript func(http.ResponseWriter, *http.Request)
|
||||
SessionsRemove func(http.ResponseWriter, *http.Request)
|
||||
ListCredentials func(http.ResponseWriter, *http.Request)
|
||||
DeleteCredentials func(http.ResponseWriter, *http.Request)
|
||||
Export func(http.ResponseWriter, *http.Request)
|
||||
Import func(http.ResponseWriter, *http.Request)
|
||||
}
|
||||
)
|
||||
|
||||
@@ -302,6 +306,38 @@ func NewUser(h UserAPI) *User {
|
||||
|
||||
api.Send(w, r, value)
|
||||
},
|
||||
ListCredentials: func(w http.ResponseWriter, r *http.Request) {
|
||||
defer r.Body.Close()
|
||||
params := request.NewUserListCredentials()
|
||||
if err := params.Fill(r); err != nil {
|
||||
api.Send(w, r, err)
|
||||
return
|
||||
}
|
||||
|
||||
value, err := h.ListCredentials(r.Context(), params)
|
||||
if err != nil {
|
||||
api.Send(w, r, err)
|
||||
return
|
||||
}
|
||||
|
||||
api.Send(w, r, value)
|
||||
},
|
||||
DeleteCredentials: func(w http.ResponseWriter, r *http.Request) {
|
||||
defer r.Body.Close()
|
||||
params := request.NewUserDeleteCredentials()
|
||||
if err := params.Fill(r); err != nil {
|
||||
api.Send(w, r, err)
|
||||
return
|
||||
}
|
||||
|
||||
value, err := h.DeleteCredentials(r.Context(), params)
|
||||
if err != nil {
|
||||
api.Send(w, r, err)
|
||||
return
|
||||
}
|
||||
|
||||
api.Send(w, r, value)
|
||||
},
|
||||
Export: func(w http.ResponseWriter, r *http.Request) {
|
||||
defer r.Body.Close()
|
||||
params := request.NewUserExport()
|
||||
@@ -355,6 +391,8 @@ func (h User) MountRoutes(r chi.Router, middlewares ...func(http.Handler) http.H
|
||||
r.Delete("/users/{userID}/membership/{roleID}", h.MembershipRemove)
|
||||
r.Post("/users/{userID}/trigger", h.TriggerScript)
|
||||
r.Delete("/users/{userID}/sessions", h.SessionsRemove)
|
||||
r.Get("/users/{userID}/credentials", h.ListCredentials)
|
||||
r.Delete("/users/{userID}/credentials/{credentialsID}", h.DeleteCredentials)
|
||||
r.Get("/users/export/{filename}.zip", h.Export)
|
||||
r.Post("/users/import", h.Import)
|
||||
})
|
||||
|
||||
@@ -280,6 +280,25 @@ type (
|
||||
UserID uint64 `json:",string"`
|
||||
}
|
||||
|
||||
UserListCredentials struct {
|
||||
// UserID PATH parameter
|
||||
//
|
||||
// ID
|
||||
UserID uint64 `json:",string"`
|
||||
}
|
||||
|
||||
UserDeleteCredentials struct {
|
||||
// UserID PATH parameter
|
||||
//
|
||||
// ID
|
||||
UserID uint64 `json:",string"`
|
||||
|
||||
// CredentialsID PATH parameter
|
||||
//
|
||||
// Credentials ID
|
||||
CredentialsID uint64 `json:",string"`
|
||||
}
|
||||
|
||||
UserExport struct {
|
||||
// Filename PATH parameter
|
||||
//
|
||||
@@ -1420,6 +1439,88 @@ func (r *UserSessionsRemove) Fill(req *http.Request) (err error) {
|
||||
return err
|
||||
}
|
||||
|
||||
// NewUserListCredentials request
|
||||
func NewUserListCredentials() *UserListCredentials {
|
||||
return &UserListCredentials{}
|
||||
}
|
||||
|
||||
// Auditable returns all auditable/loggable parameters
|
||||
func (r UserListCredentials) Auditable() map[string]interface{} {
|
||||
return map[string]interface{}{
|
||||
"userID": r.UserID,
|
||||
}
|
||||
}
|
||||
|
||||
// Auditable returns all auditable/loggable parameters
|
||||
func (r UserListCredentials) GetUserID() uint64 {
|
||||
return r.UserID
|
||||
}
|
||||
|
||||
// Fill processes request and fills internal variables
|
||||
func (r *UserListCredentials) Fill(req *http.Request) (err error) {
|
||||
|
||||
{
|
||||
var val string
|
||||
// path params
|
||||
|
||||
val = chi.URLParam(req, "userID")
|
||||
r.UserID, err = payload.ParseUint64(val), nil
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// NewUserDeleteCredentials request
|
||||
func NewUserDeleteCredentials() *UserDeleteCredentials {
|
||||
return &UserDeleteCredentials{}
|
||||
}
|
||||
|
||||
// Auditable returns all auditable/loggable parameters
|
||||
func (r UserDeleteCredentials) Auditable() map[string]interface{} {
|
||||
return map[string]interface{}{
|
||||
"userID": r.UserID,
|
||||
"credentialsID": r.CredentialsID,
|
||||
}
|
||||
}
|
||||
|
||||
// Auditable returns all auditable/loggable parameters
|
||||
func (r UserDeleteCredentials) GetUserID() uint64 {
|
||||
return r.UserID
|
||||
}
|
||||
|
||||
// Auditable returns all auditable/loggable parameters
|
||||
func (r UserDeleteCredentials) GetCredentialsID() uint64 {
|
||||
return r.CredentialsID
|
||||
}
|
||||
|
||||
// Fill processes request and fills internal variables
|
||||
func (r *UserDeleteCredentials) Fill(req *http.Request) (err error) {
|
||||
|
||||
{
|
||||
var val string
|
||||
// path params
|
||||
|
||||
val = chi.URLParam(req, "userID")
|
||||
r.UserID, err = payload.ParseUint64(val), nil
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
val = chi.URLParam(req, "credentialsID")
|
||||
r.CredentialsID, err = payload.ParseUint64(val), nil
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// NewUserExport request
|
||||
func NewUserExport() *UserExport {
|
||||
return &UserExport{}
|
||||
|
||||
@@ -35,6 +35,7 @@ type (
|
||||
User struct {
|
||||
user service.UserService
|
||||
role service.RoleService
|
||||
cred userCredentials
|
||||
|
||||
userAc userAccessController
|
||||
roleAc roleAccessController
|
||||
@@ -45,6 +46,11 @@ type (
|
||||
Set types.UserSet `json:"set"`
|
||||
}
|
||||
|
||||
userCredentials interface {
|
||||
List(ctx context.Context, userID uint64) (cc types.CredentialSet, err error)
|
||||
Delete(ctx context.Context, userID, credentialsID uint64) (err error)
|
||||
}
|
||||
|
||||
userAccessController interface {
|
||||
CanCreateUser(context.Context) bool
|
||||
CanUpdateUser(context.Context, *types.User) bool
|
||||
@@ -55,6 +61,7 @@ func (User) New() *User {
|
||||
return &User{
|
||||
user: service.DefaultUser,
|
||||
role: service.DefaultRole,
|
||||
cred: service.DefaultCredentials,
|
||||
|
||||
userAc: service.DefaultAccessControl,
|
||||
roleAc: service.DefaultAccessControl,
|
||||
@@ -278,6 +285,14 @@ func (ctrl *User) SessionsRemove(ctx context.Context, r *request.UserSessionsRem
|
||||
return
|
||||
}
|
||||
|
||||
func (ctrl *User) ListCredentials(ctx context.Context, r *request.UserListCredentials) (rsp interface{}, err error) {
|
||||
return ctrl.cred.List(ctx, r.UserID)
|
||||
}
|
||||
|
||||
func (ctrl *User) DeleteCredentials(ctx context.Context, r *request.UserDeleteCredentials) (rsp interface{}, err error) {
|
||||
return true, ctrl.cred.Delete(ctx, r.UserID, r.CredentialsID)
|
||||
}
|
||||
|
||||
// Export exports users with optional role membership and related roles
|
||||
//
|
||||
// @note this is a temporary implementation; it will be reworked when we rework Envoy and related bits.
|
||||
|
||||
Generated
+21
-8
@@ -340,6 +340,11 @@ func (svc accessControl) List() (out []map[string]string) {
|
||||
"any": types.UserRbacResource(0),
|
||||
"op": "impersonate",
|
||||
},
|
||||
{
|
||||
"type": types.UserResourceType,
|
||||
"any": types.UserRbacResource(0),
|
||||
"op": "credentials.manage",
|
||||
},
|
||||
{
|
||||
"type": types.DalConnectionResourceType,
|
||||
"any": types.DalConnectionRbacResource(0),
|
||||
@@ -851,6 +856,13 @@ func (svc accessControl) CanImpersonateUser(ctx context.Context, r *types.User)
|
||||
return svc.can(ctx, "impersonate", r)
|
||||
}
|
||||
|
||||
// CanManageCredentialsOnUser checks if current user can manage user's credentials
|
||||
//
|
||||
// This function is auto-generated
|
||||
func (svc accessControl) CanManageCredentialsOnUser(ctx context.Context, r *types.User) bool {
|
||||
return svc.can(ctx, "credentials.manage", r)
|
||||
}
|
||||
|
||||
// CanReadDalConnection checks if current user can read connection
|
||||
//
|
||||
// This function is auto-generated
|
||||
@@ -1283,14 +1295,15 @@ func rbacResourceOperations(r string) map[string]bool {
|
||||
}
|
||||
case types.UserResourceType:
|
||||
return map[string]bool{
|
||||
"read": true,
|
||||
"update": true,
|
||||
"delete": true,
|
||||
"suspend": true,
|
||||
"unsuspend": true,
|
||||
"email.unmask": true,
|
||||
"name.unmask": true,
|
||||
"impersonate": true,
|
||||
"read": true,
|
||||
"update": true,
|
||||
"delete": true,
|
||||
"suspend": true,
|
||||
"unsuspend": true,
|
||||
"email.unmask": true,
|
||||
"name.unmask": true,
|
||||
"impersonate": true,
|
||||
"credentials.manage": true,
|
||||
}
|
||||
case types.DalConnectionResourceType:
|
||||
return map[string]bool{
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/cortezaproject/corteza-server/pkg/actionlog"
|
||||
"github.com/cortezaproject/corteza-server/store"
|
||||
"github.com/cortezaproject/corteza-server/system/types"
|
||||
)
|
||||
|
||||
type (
|
||||
credentials struct {
|
||||
actionlog actionlog.Recorder
|
||||
ac credentialsAccessController
|
||||
store store.Storer
|
||||
}
|
||||
|
||||
credentialsAccessController interface {
|
||||
CanManageCredentialsOnUser(context.Context, *types.User) bool
|
||||
}
|
||||
)
|
||||
|
||||
func Credentials() *credentials {
|
||||
return &credentials{
|
||||
ac: DefaultAccessControl,
|
||||
store: DefaultStore,
|
||||
actionlog: DefaultActionlog,
|
||||
}
|
||||
}
|
||||
|
||||
func (svc *credentials) List(ctx context.Context, userID uint64) (cc types.CredentialSet, err error) {
|
||||
var (
|
||||
u *types.User
|
||||
|
||||
caProps = &credentialsActionProps{user: &types.User{ID: userID}}
|
||||
)
|
||||
|
||||
err = func() error {
|
||||
u, err = loadUser(ctx, svc.store, userID)
|
||||
caProps.setUser(u)
|
||||
|
||||
if !svc.ac.CanManageCredentialsOnUser(ctx, u) {
|
||||
return CredentialsErrNotAllowedToManage()
|
||||
}
|
||||
|
||||
cc, _, err = store.SearchCredentials(ctx, svc.store, types.CredentialFilter{OwnerID: u.ID})
|
||||
return err
|
||||
}()
|
||||
|
||||
return cc, svc.recordAction(ctx, caProps, CredentialsActionSearch, err)
|
||||
}
|
||||
|
||||
func (svc *credentials) Delete(ctx context.Context, userID, credentialsID uint64) (err error) {
|
||||
var (
|
||||
c *types.Credential
|
||||
u *types.User
|
||||
caProps = &credentialsActionProps{user: &types.User{ID: userID}}
|
||||
)
|
||||
|
||||
err = func() (err error) {
|
||||
if u, err = loadUser(ctx, svc.store, userID); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if u.Kind == types.SystemUser {
|
||||
return CredentialsErrNotAllowedToManage()
|
||||
}
|
||||
|
||||
if !svc.ac.CanManageCredentialsOnUser(ctx, u) {
|
||||
return CredentialsErrNotAllowedToManage()
|
||||
}
|
||||
|
||||
if c, err = store.LookupCredentialByID(ctx, svc.store, credentialsID); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
caProps.setCredentials(c)
|
||||
c.DeletedAt = now()
|
||||
if err = store.UpdateCredential(ctx, svc.store, c); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
return nil
|
||||
}()
|
||||
|
||||
return svc.recordAction(ctx, caProps, CredentialsActionDelete, err)
|
||||
}
|
||||
+416
@@ -0,0 +1,416 @@
|
||||
package service
|
||||
|
||||
// This file is auto-generated.
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
//
|
||||
// Definitions file that controls how this file is generated:
|
||||
// system/service/credentials_actions.yaml
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/cortezaproject/corteza-server/pkg/actionlog"
|
||||
"github.com/cortezaproject/corteza-server/pkg/errors"
|
||||
"github.com/cortezaproject/corteza-server/pkg/locale"
|
||||
"github.com/cortezaproject/corteza-server/system/types"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type (
|
||||
credentialsActionProps struct {
|
||||
user *types.User
|
||||
credentials *types.Credential
|
||||
}
|
||||
|
||||
credentialsAction struct {
|
||||
timestamp time.Time
|
||||
resource string
|
||||
action string
|
||||
log string
|
||||
severity actionlog.Severity
|
||||
|
||||
// prefix for error when action fails
|
||||
errorMessage string
|
||||
|
||||
props *credentialsActionProps
|
||||
}
|
||||
|
||||
credentialsLogMetaKey struct{}
|
||||
credentialsPropsMetaKey struct{}
|
||||
)
|
||||
|
||||
var (
|
||||
// just a placeholder to cover template cases w/o fmt package use
|
||||
_ = fmt.Println
|
||||
)
|
||||
|
||||
// *********************************************************************************************************************
|
||||
// *********************************************************************************************************************
|
||||
// Props methods
|
||||
// setUser updates credentialsActionProps's user
|
||||
//
|
||||
// Allows method chaining
|
||||
//
|
||||
// This function is auto-generated.
|
||||
//
|
||||
func (p *credentialsActionProps) setUser(user *types.User) *credentialsActionProps {
|
||||
p.user = user
|
||||
return p
|
||||
}
|
||||
|
||||
// setCredentials updates credentialsActionProps's credentials
|
||||
//
|
||||
// Allows method chaining
|
||||
//
|
||||
// This function is auto-generated.
|
||||
//
|
||||
func (p *credentialsActionProps) setCredentials(credentials *types.Credential) *credentialsActionProps {
|
||||
p.credentials = credentials
|
||||
return p
|
||||
}
|
||||
|
||||
// Serialize converts credentialsActionProps to actionlog.Meta
|
||||
//
|
||||
// This function is auto-generated.
|
||||
//
|
||||
func (p credentialsActionProps) Serialize() actionlog.Meta {
|
||||
var (
|
||||
m = make(actionlog.Meta)
|
||||
)
|
||||
|
||||
if p.user != nil {
|
||||
m.Set("user.handle", p.user.Handle, true)
|
||||
m.Set("user.email", p.user.Email, true)
|
||||
m.Set("user.name", p.user.Name, true)
|
||||
m.Set("user.username", p.user.Username, true)
|
||||
m.Set("user.ID", p.user.ID, true)
|
||||
}
|
||||
if p.credentials != nil {
|
||||
m.Set("credentials.kind", p.credentials.Kind, true)
|
||||
}
|
||||
|
||||
return m
|
||||
}
|
||||
|
||||
// tr translates string and replaces meta value placeholder with values
|
||||
//
|
||||
// This function is auto-generated.
|
||||
//
|
||||
func (p credentialsActionProps) Format(in string, err error) string {
|
||||
var (
|
||||
pairs = []string{"{{err}}"}
|
||||
// first non-empty string
|
||||
fns = func(ii ...interface{}) string {
|
||||
for _, i := range ii {
|
||||
if s := fmt.Sprintf("%v", i); len(s) > 0 {
|
||||
return s
|
||||
}
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
pairs = append(pairs, err.Error())
|
||||
} else {
|
||||
pairs = append(pairs, "nil")
|
||||
}
|
||||
|
||||
if p.user != nil {
|
||||
// replacement for "{{user}}" (in order how fields are defined)
|
||||
pairs = append(
|
||||
pairs,
|
||||
"{{user}}",
|
||||
fns(
|
||||
p.user.Handle,
|
||||
p.user.Email,
|
||||
p.user.Name,
|
||||
p.user.Username,
|
||||
p.user.ID,
|
||||
),
|
||||
)
|
||||
pairs = append(pairs, "{{user.handle}}", fns(p.user.Handle))
|
||||
pairs = append(pairs, "{{user.email}}", fns(p.user.Email))
|
||||
pairs = append(pairs, "{{user.name}}", fns(p.user.Name))
|
||||
pairs = append(pairs, "{{user.username}}", fns(p.user.Username))
|
||||
pairs = append(pairs, "{{user.ID}}", fns(p.user.ID))
|
||||
}
|
||||
|
||||
if p.credentials != nil {
|
||||
// replacement for "{{credentials}}" (in order how fields are defined)
|
||||
pairs = append(
|
||||
pairs,
|
||||
"{{credentials}}",
|
||||
fns(
|
||||
p.credentials.Kind,
|
||||
),
|
||||
)
|
||||
pairs = append(pairs, "{{credentials.kind}}", fns(p.credentials.Kind))
|
||||
}
|
||||
return strings.NewReplacer(pairs...).Replace(in)
|
||||
}
|
||||
|
||||
// *********************************************************************************************************************
|
||||
// *********************************************************************************************************************
|
||||
// Action methods
|
||||
|
||||
// String returns loggable description as string
|
||||
//
|
||||
// This function is auto-generated.
|
||||
//
|
||||
func (a *credentialsAction) String() string {
|
||||
var props = &credentialsActionProps{}
|
||||
|
||||
if a.props != nil {
|
||||
props = a.props
|
||||
}
|
||||
|
||||
return props.Format(a.log, nil)
|
||||
}
|
||||
|
||||
func (e *credentialsAction) ToAction() *actionlog.Action {
|
||||
return &actionlog.Action{
|
||||
Resource: e.resource,
|
||||
Action: e.action,
|
||||
Severity: e.severity,
|
||||
Description: e.String(),
|
||||
Meta: e.props.Serialize(),
|
||||
}
|
||||
}
|
||||
|
||||
// *********************************************************************************************************************
|
||||
// *********************************************************************************************************************
|
||||
// Action constructors
|
||||
|
||||
// CredentialsActionSearch returns "system:credentials.search" action
|
||||
//
|
||||
// This function is auto-generated.
|
||||
//
|
||||
func CredentialsActionSearch(props ...*credentialsActionProps) *credentialsAction {
|
||||
a := &credentialsAction{
|
||||
timestamp: time.Now(),
|
||||
resource: "system:credentials",
|
||||
action: "search",
|
||||
log: "searched for matching users",
|
||||
severity: actionlog.Info,
|
||||
}
|
||||
|
||||
if len(props) > 0 {
|
||||
a.props = props[0]
|
||||
}
|
||||
|
||||
return a
|
||||
}
|
||||
|
||||
// CredentialsActionDelete returns "system:credentials.delete" action
|
||||
//
|
||||
// This function is auto-generated.
|
||||
//
|
||||
func CredentialsActionDelete(props ...*credentialsActionProps) *credentialsAction {
|
||||
a := &credentialsAction{
|
||||
timestamp: time.Now(),
|
||||
resource: "system:credentials",
|
||||
action: "delete",
|
||||
log: "deleted {{user}}",
|
||||
severity: actionlog.Notice,
|
||||
}
|
||||
|
||||
if len(props) > 0 {
|
||||
a.props = props[0]
|
||||
}
|
||||
|
||||
return a
|
||||
}
|
||||
|
||||
// *********************************************************************************************************************
|
||||
// *********************************************************************************************************************
|
||||
// Error constructors
|
||||
|
||||
// CredentialsErrGeneric returns "system:credentials.generic" as *errors.Error
|
||||
//
|
||||
//
|
||||
// This function is auto-generated.
|
||||
//
|
||||
func CredentialsErrGeneric(mm ...*credentialsActionProps) *errors.Error {
|
||||
var p = &credentialsActionProps{}
|
||||
if len(mm) > 0 {
|
||||
p = mm[0]
|
||||
}
|
||||
|
||||
var e = errors.New(
|
||||
errors.KindInternal,
|
||||
|
||||
p.Format("failed to complete request due to internal error", nil),
|
||||
|
||||
errors.Meta("type", "generic"),
|
||||
errors.Meta("resource", "system:credentials"),
|
||||
|
||||
// action log entry; no formatting, it will be applied inside recordAction fn.
|
||||
errors.Meta(credentialsLogMetaKey{}, "{err}"),
|
||||
errors.Meta(credentialsPropsMetaKey{}, p),
|
||||
|
||||
// translation namespace & key
|
||||
errors.Meta(locale.ErrorMetaNamespace{}, "system"),
|
||||
errors.Meta(locale.ErrorMetaKey{}, "credentials.errors.generic"),
|
||||
|
||||
errors.StackSkip(1),
|
||||
)
|
||||
|
||||
if len(mm) > 0 {
|
||||
}
|
||||
|
||||
return e
|
||||
}
|
||||
|
||||
// CredentialsErrNotFound returns "system:credentials.notFound" as *errors.Error
|
||||
//
|
||||
//
|
||||
// This function is auto-generated.
|
||||
//
|
||||
func CredentialsErrNotFound(mm ...*credentialsActionProps) *errors.Error {
|
||||
var p = &credentialsActionProps{}
|
||||
if len(mm) > 0 {
|
||||
p = mm[0]
|
||||
}
|
||||
|
||||
var e = errors.New(
|
||||
errors.KindInternal,
|
||||
|
||||
p.Format("credentials not found", nil),
|
||||
|
||||
errors.Meta("type", "notFound"),
|
||||
errors.Meta("resource", "system:credentials"),
|
||||
|
||||
errors.Meta(credentialsPropsMetaKey{}, p),
|
||||
|
||||
// translation namespace & key
|
||||
errors.Meta(locale.ErrorMetaNamespace{}, "system"),
|
||||
errors.Meta(locale.ErrorMetaKey{}, "credentials.errors.notFound"),
|
||||
|
||||
errors.StackSkip(1),
|
||||
)
|
||||
|
||||
if len(mm) > 0 {
|
||||
}
|
||||
|
||||
return e
|
||||
}
|
||||
|
||||
// CredentialsErrInvalidID returns "system:credentials.invalidID" as *errors.Error
|
||||
//
|
||||
//
|
||||
// This function is auto-generated.
|
||||
//
|
||||
func CredentialsErrInvalidID(mm ...*credentialsActionProps) *errors.Error {
|
||||
var p = &credentialsActionProps{}
|
||||
if len(mm) > 0 {
|
||||
p = mm[0]
|
||||
}
|
||||
|
||||
var e = errors.New(
|
||||
errors.KindInternal,
|
||||
|
||||
p.Format("invalid ID", nil),
|
||||
|
||||
errors.Meta("type", "invalidID"),
|
||||
errors.Meta("resource", "system:credentials"),
|
||||
|
||||
errors.Meta(credentialsPropsMetaKey{}, p),
|
||||
|
||||
// translation namespace & key
|
||||
errors.Meta(locale.ErrorMetaNamespace{}, "system"),
|
||||
errors.Meta(locale.ErrorMetaKey{}, "credentials.errors.invalidID"),
|
||||
|
||||
errors.StackSkip(1),
|
||||
)
|
||||
|
||||
if len(mm) > 0 {
|
||||
}
|
||||
|
||||
return e
|
||||
}
|
||||
|
||||
// CredentialsErrNotAllowedToManage returns "system:credentials.notAllowedToManage" as *errors.Error
|
||||
//
|
||||
//
|
||||
// This function is auto-generated.
|
||||
//
|
||||
func CredentialsErrNotAllowedToManage(mm ...*credentialsActionProps) *errors.Error {
|
||||
var p = &credentialsActionProps{}
|
||||
if len(mm) > 0 {
|
||||
p = mm[0]
|
||||
}
|
||||
|
||||
var e = errors.New(
|
||||
errors.KindInternal,
|
||||
|
||||
p.Format("not allowed to manage credentials for this user", nil),
|
||||
|
||||
errors.Meta("type", "notAllowedToManage"),
|
||||
errors.Meta("resource", "system:credentials"),
|
||||
|
||||
// action log entry; no formatting, it will be applied inside recordAction fn.
|
||||
errors.Meta(credentialsLogMetaKey{}, "failed to manage credentials for {{user.handle}}; insufficient permissions"),
|
||||
errors.Meta(credentialsPropsMetaKey{}, p),
|
||||
|
||||
// translation namespace & key
|
||||
errors.Meta(locale.ErrorMetaNamespace{}, "system"),
|
||||
errors.Meta(locale.ErrorMetaKey{}, "credentials.errors.notAllowedToManage"),
|
||||
|
||||
errors.StackSkip(1),
|
||||
)
|
||||
|
||||
if len(mm) > 0 {
|
||||
}
|
||||
|
||||
return e
|
||||
}
|
||||
|
||||
// *********************************************************************************************************************
|
||||
// *********************************************************************************************************************
|
||||
|
||||
// recordAction is a service helper function wraps function that can return error
|
||||
//
|
||||
// It will wrap unrecognized/internal errors with generic errors.
|
||||
//
|
||||
// This function is auto-generated.
|
||||
//
|
||||
func (svc credentials) recordAction(ctx context.Context, props *credentialsActionProps, actionFn func(...*credentialsActionProps) *credentialsAction, err error) error {
|
||||
if svc.actionlog == nil || actionFn == nil {
|
||||
// action log disabled or no action fn passed, return error as-is
|
||||
return err
|
||||
} else if err == nil {
|
||||
// action completed w/o error, record it
|
||||
svc.actionlog.Record(ctx, actionFn(props).ToAction())
|
||||
return nil
|
||||
}
|
||||
|
||||
a := actionFn(props).ToAction()
|
||||
|
||||
// Extracting error information and recording it as action
|
||||
a.Error = err.Error()
|
||||
|
||||
switch c := err.(type) {
|
||||
case *errors.Error:
|
||||
m := c.Meta()
|
||||
|
||||
a.Error = err.Error()
|
||||
a.Severity = actionlog.Severity(m.AsInt("severity"))
|
||||
a.Description = props.Format(m.AsString(credentialsLogMetaKey{}), err)
|
||||
|
||||
if p, has := m[credentialsPropsMetaKey{}]; has {
|
||||
a.Meta = p.(*credentialsActionProps).Serialize()
|
||||
}
|
||||
|
||||
svc.actionlog.Record(ctx, a)
|
||||
default:
|
||||
svc.actionlog.Record(ctx, a)
|
||||
}
|
||||
|
||||
// Original error is passed on
|
||||
return err
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
# List of loggable service actions
|
||||
|
||||
resource: system:credentials
|
||||
service: credentials
|
||||
|
||||
# Default sensitivity for actions
|
||||
defaultActionSeverity: notice
|
||||
|
||||
# default severity for errors
|
||||
defaultErrorSeverity: alert
|
||||
|
||||
import:
|
||||
- github.com/cortezaproject/corteza-server/system/types
|
||||
|
||||
props:
|
||||
- name: user
|
||||
type: "*types.User"
|
||||
fields: [ handle, email, name, username, ID ]
|
||||
- name: credentials
|
||||
type: "*types.Credential"
|
||||
fields: [ kind ]
|
||||
|
||||
actions:
|
||||
- action: search
|
||||
log: "searched for matching users"
|
||||
severity: info
|
||||
|
||||
- action: delete
|
||||
log: "deleted {{user}}"
|
||||
|
||||
errors:
|
||||
- error: notFound
|
||||
message: "credentials not found"
|
||||
severity: warning
|
||||
|
||||
- error: invalidID
|
||||
message: "invalid ID"
|
||||
severity: warning
|
||||
|
||||
- error: notAllowedToManage
|
||||
message: "not allowed to manage credentials for this user"
|
||||
log: "failed to manage credentials for {{user.handle}}; insufficient permissions"
|
||||
@@ -75,6 +75,7 @@ var (
|
||||
DefaultAuth *auth
|
||||
DefaultAuthClient *authClient
|
||||
DefaultUser *user
|
||||
DefaultCredentials *credentials
|
||||
DefaultDalConnection *dalConnection
|
||||
DefaultDalSensitivityLevel *dalSensitivityLevel
|
||||
DefaultRole *role
|
||||
@@ -201,6 +202,7 @@ func Initialize(ctx context.Context, log *zap.Logger, s store.Storer, ws websock
|
||||
DefaultAuth = Auth(AuthOptions{LimitUsers: c.Limit.SystemUsers})
|
||||
DefaultAuthClient = AuthClient(DefaultStore, DefaultAccessControl, DefaultActionlog, eventbus.Service(), c.Auth)
|
||||
DefaultUser = User(UserOptions{LimitUsers: c.Limit.SystemUsers})
|
||||
DefaultCredentials = Credentials()
|
||||
DefaultReport = Report(DefaultStore, DefaultAccessControl, DefaultActionlog, eventbus.Service())
|
||||
DefaultRole = Role(rbac.Global())
|
||||
DefaultApplication = Application(DefaultStore, DefaultAccessControl, DefaultActionlog, eventbus.Service())
|
||||
|
||||
@@ -50,6 +50,7 @@ user: schema.#Resource & {
|
||||
"email.unmask": description: "Unmask email"
|
||||
"name.unmask": description: "Unmask name"
|
||||
"impersonate": description: "Impersonate user"
|
||||
"credentials.manage": description: "Manage user's credentials"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user