3
0

Removing superuser logic

This commit is contained in:
Denis Arh
2021-05-25 15:34:44 +02:00
parent 48e1d0e4aa
commit b923953ca5
56 changed files with 590 additions and 293 deletions
+21 -1
View File
@@ -255,13 +255,31 @@ func (app *CortezaApp) Provision(ctx context.Context) (err error) {
return err
}
var (
uu []*types.User
rr []*types.Role
)
// Basic provision for system resources that we need before anything else
if rr, err = provision.SystemRoles(ctx, app.Log, app.Store); err != nil {
return
}
// Basic provision for system users that we need before anything else
if uu, err = provision.SystemUsers(ctx, app.Log, app.Store); err != nil {
return
}
// now set system users with so that the whole app knows what to use
auth.SetSystemUsers(uu, rr)
if !app.Opt.Provision.Always {
app.Log.Debug("provisioning skipped (PROVISION_ALWAYS=false)")
} else {
defer sentry.Recover()
ctx = actionlog.RequestOriginToContext(ctx, actionlog.RequestOrigin_APP_Provision)
ctx = auth.SetSuperUserContext(ctx)
ctx = auth.SetIdentityToContext(ctx, auth.ProvisionUser())
if err = provision.Run(ctx, app.Log, app.Store, app.Opt.Provision, app.Opt.Auth); err != nil {
return err
@@ -282,6 +300,8 @@ func (app *CortezaApp) InitServices(ctx context.Context) (err error) {
return err
}
// Load users
app.WsServer = websocket.Server(app.Log, app.Opt.Websocket)
ctx = actionlog.RequestOriginToContext(ctx, actionlog.RequestOrigin_APP_Init)
+9 -9
View File
@@ -81,18 +81,18 @@ func (app *CortezaApp) InitCLI() {
}
app.Command.AddCommand(
systemCommands.Users(app),
systemCommands.Roles(app),
systemCommands.RBAC(app),
systemCommands.Sink(app),
systemCommands.Settings(app),
systemCommands.Import(storeInit),
systemCommands.Export(storeInit),
systemCommands.Users(ctx, app),
systemCommands.Roles(ctx, app),
systemCommands.RBAC(ctx, app),
systemCommands.Sink(ctx, app),
systemCommands.Settings(ctx, app),
systemCommands.Import(ctx, storeInit),
systemCommands.Export(ctx, storeInit),
serveCmd,
upgradeCmd,
provisionCmd,
authCommands.Command(app, storeInit),
federationCommands.Sync(app),
authCommands.Command(ctx, app, storeInit),
federationCommands.Sync(ctx, app),
cli.EnvCommand(),
cli.VersionCommand(),
)
+1 -5
View File
@@ -26,7 +26,7 @@ func commandPreRunInitService(app serviceInitializer) func(*cobra.Command, []str
}
}
func Command(app serviceInitializer, storeInit func(ctx context.Context) (store.Storer, error)) *cobra.Command {
func Command(ctx context.Context, app serviceInitializer, storeInit func(ctx context.Context) (store.Storer, error)) *cobra.Command {
var (
enableDiscoveredProvider bool
skipValidationOnAutoDiscoveredProvider bool
@@ -88,8 +88,6 @@ func Command(app serviceInitializer, storeInit func(ctx context.Context) (store.
PreRunE: commandPreRunInitService(app),
Run: func(cmd *cobra.Command, args []string) {
var (
ctx = auth.SetSuperUserContext(cli.Context())
user *types.User
err error
@@ -112,9 +110,7 @@ func Command(app serviceInitializer, storeInit func(ctx context.Context) (store.
Args: cobra.ExactArgs(1),
PreRunE: commandPreRunInitService(app),
Run: func(cmd *cobra.Command, args []string) {
var (
ctx = auth.SetSuperUserContext(cli.Context())
err error
ntf = service.DefaultAuthNotification
)
+1 -6
View File
@@ -3,8 +3,6 @@ package commands
import (
"context"
"github.com/cortezaproject/corteza-server/pkg/cli"
"github.com/spf13/cobra"
)
@@ -14,10 +12,7 @@ type (
}
)
func Sync(app serviceInitializer) *cobra.Command {
ctx := cli.Context()
func Sync(ctx context.Context, app serviceInitializer) *cobra.Command {
// Sync commands.
cmd := &cobra.Command{
Use: "sync",
+2 -3
View File
@@ -12,6 +12,7 @@ import (
"github.com/cortezaproject/corteza-server/federation/rest/request"
"github.com/cortezaproject/corteza-server/federation/service"
"github.com/cortezaproject/corteza-server/federation/types"
"github.com/cortezaproject/corteza-server/pkg/auth"
"github.com/cortezaproject/corteza-server/pkg/errors"
"github.com/cortezaproject/corteza-server/pkg/federation"
"github.com/cortezaproject/corteza-server/pkg/filter"
@@ -193,9 +194,7 @@ func (ctrl SyncData) readExposed(ctx context.Context, r *request.SyncDataReadExp
return strings.Contains(u.Handle, "federation_"), nil
})
// TODO - remove once the federation users are doing the persist
// on the data sync, for now, it's superuser
users = append(users, &st.User{ID: 10000000000000000})
users = append(users, auth.FederationUser())
query := buildLastSyncQuery(r.LastSync)
ignoredUsersQuery := buildIgnoredUsersQuery(users)
+3 -3
View File
@@ -271,6 +271,9 @@ func (svc node) Pair(ctx context.Context, nodeID uint64) error {
return NodeErrNotAllowedToPair()
}
// elevate permissions for user lookup & creation!
ctx = auth.SetIdentityToContext(ctx, auth.FederationUser())
_, err := svc.updater(
ctx,
nodeID,
@@ -460,9 +463,6 @@ func (svc node) fetchFederatedUser(ctx context.Context, n *types.Node) (*sysType
// Generate handle for user that se this node
uHandle := fmt.Sprintf("federation_%d", n.ID)
// elevate permissions for user lookup & creation!
ctx = auth.SetSuperUserContext(ctx)
u, err := svc.sysUser.FindByHandle(ctx, uHandle)
if err == nil {
// Reuse existing user
+1 -1
View File
@@ -48,7 +48,7 @@ func (dp *dataProcesser) Process(ctx context.Context, payload []byte) (Processer
}, nil
}
ctx = auth.SetSuperUserContext(ctx)
ctx = auth.SetIdentityToContext(ctx, auth.FederationUser())
for _, er := range o {
var (
@@ -4,7 +4,6 @@ import (
"context"
"github.com/cortezaproject/corteza-server/federation/types"
"github.com/cortezaproject/corteza-server/pkg/auth"
"github.com/cortezaproject/corteza-server/pkg/decoder"
st "github.com/cortezaproject/corteza-server/system/types"
)
@@ -41,8 +40,6 @@ func (dp *structureProcesser) Process(ctx context.Context, payload []byte) (Proc
}, nil
}
ctx = auth.SetSuperUserContext(ctx)
for _, em := range o {
new := &types.SharedModule{
NodeID: dp.Node.ID,
+3
View File
@@ -10,6 +10,7 @@ import (
cs "github.com/cortezaproject/corteza-server/compose/service"
ct "github.com/cortezaproject/corteza-server/compose/types"
"github.com/cortezaproject/corteza-server/federation/types"
"github.com/cortezaproject/corteza-server/pkg/auth"
"github.com/cortezaproject/corteza-server/pkg/filter"
ss "github.com/cortezaproject/corteza-server/system/service"
st "github.com/cortezaproject/corteza-server/system/types"
@@ -62,6 +63,8 @@ func (s *Sync) CanUpdateSharedModule(ctx context.Context, new *types.SharedModul
// ProcessPayload passes the payload to the syncer lib
func (s *Sync) ProcessPayload(ctx context.Context, payload []byte, out chan Url, url types.SyncerURI, processer Processer) (ProcesserResponse, error) {
ctx = auth.SetIdentityToContext(ctx, auth.FederationUser())
return s.syncer.Process(ctx, payload, out, url, processer)
}
+1 -1
View File
@@ -163,7 +163,7 @@ func (w *syncWorkerData) Watch(ctx context.Context, delay time.Duration, limit i
ctx, cancel := context.WithCancel(ctx)
defer cancel()
ctx = auth.SetSuperUserContext(ctx)
ctx = auth.SetIdentityToContext(ctx, auth.FederationUser())
ticker := time.NewTicker(delay)
+1 -1
View File
@@ -106,7 +106,7 @@ func (w *syncWorkerStructure) Watch(ctx context.Context, delay time.Duration, li
ctx, cancel := context.WithCancel(ctx)
defer cancel()
ctx = auth.SetSuperUserContext(ctx)
ctx = auth.SetIdentityToContext(ctx, auth.FederationUser())
ticker := time.NewTicker(delay)
-12
View File
@@ -13,10 +13,6 @@ type (
}
)
const (
superUserID uint64 = 10000000000000000
)
func NewIdentity(id uint64, rr ...uint64) *Identity {
return &Identity{
id: id,
@@ -40,14 +36,6 @@ func (i Identity) String() string {
return fmt.Sprintf("%d", i.Identity())
}
func NewSuperUserIdentity() *Identity {
return NewIdentity(superUserID)
}
func IsSuperUser(i Identifiable) bool {
return i != nil && superUserID == i.Identity()
}
func ExtractUserIDFromSubClaim(sub string) uint64 {
userID, _ := ExtractFromSubClaim(sub)
return userID
-8
View File
@@ -19,11 +19,3 @@ func GetIdentityFromContext(ctx context.Context) Identifiable {
return NewIdentity(0)
}
}
// SetSuperUserContext stores system user as identity
// and accompanying JWT for it to the context
func SetSuperUserContext(ctx context.Context) context.Context {
su := NewSuperUserIdentity()
return SetIdentityToContext(ctx, su)
}
+58
View File
@@ -0,0 +1,58 @@
package auth
import (
"github.com/cortezaproject/corteza-server/system/types"
)
const (
ProvisionUserHandle = "corteza-provisioner"
ServiceUserHandle = "corteza-service"
FederationUserHandle = "corteza-federation"
BypassRoleHandle = "super-admin"
AuthenticatedRoleHandle = "authenticated"
AnonymousRoleHandle = "anonymous"
)
var (
provisionUser *types.User
serviceUser *types.User
federationUser *types.User
)
// SetSystemUsers takes list of users and sets/updates appropriate
// provision, service & fed users
//
// These are then accessed via special *User() fn.
func SetSystemUsers(uu types.UserSet, rr types.RoleSet) {
bpr := rr.FindByHandle(BypassRoleHandle)
for _, u := range uu {
switch u.Handle {
case ProvisionUserHandle:
provisionUser = u.Clone()
federationUser.SetRoles([]uint64{bpr.ID})
case ServiceUserHandle:
serviceUser = u.Clone()
federationUser.SetRoles([]uint64{bpr.ID})
case FederationUserHandle:
federationUser = u.Clone()
federationUser.SetRoles([]uint64{bpr.ID})
}
}
}
// ProvisionUser returns clone of system provision user
func ProvisionUser() *types.User {
return provisionUser.Clone()
}
// ServiceUser returns clone of system service user
func ServiceUser() *types.User {
return serviceUser.Clone()
}
// FederationUser returns clone of system federation user
func FederationUser() *types.User {
return federationUser.Clone()
}
+5 -8
View File
@@ -3,6 +3,10 @@ package corredor
import (
"context"
"fmt"
"strings"
"sync"
"time"
"github.com/cortezaproject/corteza-server/pkg/auth"
"github.com/cortezaproject/corteza-server/pkg/errors"
"github.com/cortezaproject/corteza-server/pkg/eventbus"
@@ -16,9 +20,6 @@ import (
"google.golang.org/grpc/codes"
"google.golang.org/grpc/metadata"
"google.golang.org/grpc/status"
"strings"
"sync"
"time"
)
type (
@@ -396,12 +397,8 @@ func (svc service) Exec(ctx context.Context, scriptName string, args ScriptArgs)
// This is used only in case of explicit execution (onManual) and never when
// scripts are executed implicitly (deferred, before/after...)
func (svc service) canExec(ctx context.Context, script string) bool {
u := auth.GetIdentityFromContext(ctx)
if auth.IsSuperUser(u) {
return true
}
// @todo RBACv2 convert roles u.Roles()...
//u := auth.GetIdentityFromContext(ctx)
//return svc.permissions.Check(nil, script, permOpExec) != rbac.Deny
return true
}
+3 -3
View File
@@ -20,7 +20,7 @@ func TestUser_Merger(t *testing.T) {
Email: "email",
Name: "name",
Handle: "handle",
Kind: types.BotUser,
Kind: types.SystemUser,
Meta: &types.UserMeta{},
CreatedAt: now,
UpdatedAt: nowP,
@@ -34,7 +34,7 @@ func TestUser_Merger(t *testing.T) {
req.Equal("email", c.Email)
req.Equal("name", c.Name)
req.Equal("handle", c.Handle)
req.Equal(types.BotUser, c.Kind)
req.Equal(types.SystemUser, c.Kind)
req.Equal(&types.UserMeta{}, c.Meta)
req.Equal(now, c.CreatedAt)
req.Equal(nowP, c.UpdatedAt)
@@ -48,7 +48,7 @@ func TestUser_Merger(t *testing.T) {
req.Equal("email", c.Email)
req.Equal("name", c.Name)
req.Equal("handle", c.Handle)
req.Equal(types.BotUser, c.Kind)
req.Equal(types.SystemUser, c.Kind)
req.Equal(&types.UserMeta{}, c.Meta)
req.Equal(now, c.CreatedAt)
req.Equal(nowP, c.UpdatedAt)
+7 -4
View File
@@ -152,6 +152,8 @@ func TestHandler_RegOps(t *testing.T) {
func TestHandlerHandler(t *testing.T) {
var (
identity uint64 = 42
a = assert.New(t)
ctx = context.Background()
ev = &mockEvent{}
@@ -160,18 +162,19 @@ func TestHandlerHandler(t *testing.T) {
trSimple = &handler{
handler: func(ctx context.Context, ev Event) error {
passedthrough = true
a.True(auth.IsSuperUser(ev.(*mockEvent).identity))
a.Equal(identity, ev.(*mockEvent).identity.Identity())
return nil
},
}
)
a.False(passedthrough)
a.False(auth.IsSuperUser(ev.identity))
a.Nil(ev.identity)
trSimple.Handle(auth.SetSuperUserContext(ctx), ev)
a.NoError(trSimple.Handle(auth.SetIdentityToContext(ctx, auth.NewIdentity(identity)), ev))
a.True(auth.IsSuperUser(ev.identity))
a.NotNil(ev.identity)
a.Equal(identity, ev.identity.Identity())
a.True(passedthrough, "expecting to pass through simple handler")
}
+3 -5
View File
@@ -8,12 +8,8 @@ props:
# description: When disabled all operations on all resources are allowed
- name: serviceUser
default: "corteza"
description: |-
Used at boot time, for provisioning and other service-level operations.
Service user is automatically member of all bypass roles.
- name: bypassRoles
# Using literal string instead of DefaultBypassRole constant for clarity & documentation
default: "super-admin"
description: |-
Space delimited list of role handles.
@@ -21,6 +17,7 @@ props:
System will refuse to start if check-bypassing roles are also listed as authenticated or anonymous auto-assigned roles.
- name: authenticatedRoles
# Using literal string instead of DefaultAuthenticatedRole constant for clarity & documentation
default: "authenticated"
description: |-
Space delimited list of role handles.
@@ -29,6 +26,7 @@ props:
System will refuse to start if roles listed here are also listed under anonymous roles
- name: anonymousRoles
# Using literal string instead of DefaultAnonymousRole constant for clarity & documentation
default: "anonymous"
description: |-
Space delimited list of role handles.
-2
View File
@@ -22,8 +22,6 @@ func authSettingsAutoDiscovery(ctx context.Context, log *zap.Logger, s store.Sto
boolWrapper func() bool
)
log = log.Named("auth.settings-discovery")
var (
// Setter
//
-3
View File
@@ -7,7 +7,6 @@ import (
"strings"
"github.com/cortezaproject/corteza-server/auth/external"
"github.com/cortezaproject/corteza-server/pkg/auth"
"github.com/cortezaproject/corteza-server/pkg/options"
"github.com/cortezaproject/corteza-server/store"
"github.com/cortezaproject/corteza-server/system/types"
@@ -127,8 +126,6 @@ func authAddExternals(ctx context.Context, log *zap.Logger, s store.Settings) (e
eap.Handle = kind
}
ctx = auth.SetSuperUserContext(ctx)
_ = external.AddProvider(ctx, s, eap, false)
}
+8 -8
View File
@@ -14,21 +14,21 @@ import (
)
func Run(ctx context.Context, log *zap.Logger, s store.Storer, provisionOpt options.ProvisionOpt, authOpt options.AuthOpt) error {
ffn := []func() error{
func() error { return roles(ctx, log, s) },
log = log.Named("provision")
ffn := []func() error{
// Migrations:
func() error { return migrateApplications(ctx, s) },
func() error { return migrateEmailTemplates(ctx, log, s) },
func() error { return migrateEmailTemplates(ctx, log.Named("email-templates"), s) },
// Config (full & partial)
func() error { return importConfig(ctx, log, s, provisionOpt.Path) },
func() error { return importConfig(ctx, log.Named("config"), s, provisionOpt.Path) },
// Auto-discoveries and other parts that cannot be imported from static files
func() error { return authSettingsAutoDiscovery(ctx, log, s) },
func() error { return authAddExternals(ctx, log, s) },
func() error { return oidcAutoDiscovery(ctx, log, s, authOpt) },
func() error { return defaultAuthClient(ctx, log, s, authOpt) },
func() error { return authSettingsAutoDiscovery(ctx, log.Named("auth.settings-discovery"), s) },
func() error { return authAddExternals(ctx, log.Named("auth.externals"), s) },
func() error { return oidcAutoDiscovery(ctx, log.Named("auth.oidc-auto-discovery"), s, authOpt) },
func() error { return defaultAuthClient(ctx, log.Named("auth.clients"), s, authOpt) },
}
for _, fn := range ffn {
+68 -56
View File
@@ -2,6 +2,7 @@ package provision
import (
"context"
"fmt"
"time"
"github.com/cortezaproject/corteza-server/pkg/filter"
@@ -11,56 +12,48 @@ import (
"go.uber.org/zap"
)
func roles(ctx context.Context, log *zap.Logger, s store.Storer) error {
// SystemRoles creates system roles
func SystemRoles(ctx context.Context, log *zap.Logger, s store.Storer) (rr []*types.Role, err error) {
const (
obsoleteEveryoneID uint64 = 1
obsoleteAdminsID uint64 = 2
)
var (
f = types.RoleFilter{
Archived: filter.StateInclusive,
Deleted: filter.StateInclusive,
}
now = time.Now().Round(time.Second)
rr = types.RoleSet{
&types.Role{
Name: "Super administrator",
Handle: "super-admin",
Meta: &types.RoleMeta{
Description: "Super admin is a 'bypass' role that allows all actions it's members",
Context: nil,
},
},
&types.Role{
Name: "Authenticated",
Handle: "authenticated",
Meta: &types.RoleMeta{
Description: "Authenticated role is auto-assigned to all authenticated sessions",
Context: nil,
},
},
&types.Role{
Name: "Anonymous",
Handle: "anonymous",
Meta: &types.RoleMeta{
Description: "Authenticated role is auto-assigned to all non-authenticated sessions",
Context: nil,
}},
}
)
m := make(map[string]*types.Role)
if set, _, err := store.SearchRoles(ctx, s, f); err != nil {
return err
} else {
for _, r := range set {
m[r.Handle] = r
}
rr = types.RoleSet{
&types.Role{
Name: "Super administrator",
Handle: "super-admin",
Meta: &types.RoleMeta{
Description: "Super admin is a 'bypass' role that allows all actions it's members",
Context: nil,
},
},
&types.Role{
Name: "Authenticated",
Handle: "authenticated",
Meta: &types.RoleMeta{
Description: "Authenticated role is auto-assigned to all authenticated sessions",
Context: nil,
},
},
&types.Role{
Name: "Anonymous",
Handle: "anonymous",
Meta: &types.RoleMeta{
Description: "Authenticated role is auto-assigned to all non-authenticated sessions",
Context: nil,
}},
}
m, err := loadRoles(ctx, s)
if err != nil {
return
}
for i := range rr {
@@ -78,7 +71,7 @@ func roles(ctx context.Context, log *zap.Logger, s store.Storer) error {
rr[i] = m[r.Handle]
// make sure it's not deleted or archived
// and left other props as they are
// and leave other props as they are
r.DeletedAt = nil
r.ArchivedAt = nil
@@ -86,7 +79,7 @@ func roles(ctx context.Context, log *zap.Logger, s store.Storer) error {
}
if err := store.UpsertRole(ctx, s, rr...); err != nil {
return err
return nil, fmt.Errorf("failed to provision roles: %w", err)
}
// let's see if everyone role is still here:
@@ -95,13 +88,13 @@ func roles(ctx context.Context, log *zap.Logger, s store.Storer) error {
// everyone role still present and it is using "hardcoded" ID
// we can remove it
if err := store.DeleteRoleByID(ctx, s, obsoleteEveryoneID); err != nil {
return err
if err = store.DeleteRoleByID(ctx, s, obsoleteEveryoneID); err != nil {
return
}
// transfer all rbac rules
if err := s.TransferRbacRules(ctx, obsoleteEveryoneID, m["authenticated"].ID); err != nil {
return nil
if err = s.TransferRbacRules(ctx, obsoleteEveryoneID, m["authenticated"].ID); err != nil {
return
}
}
@@ -114,24 +107,43 @@ func roles(ctx context.Context, log *zap.Logger, s store.Storer) error {
m["admins"].ID = id.Next()
m["admins"].UpdatedAt = &now
if err := store.DeleteRoleByID(ctx, s, obsoleteAdminsID); err != nil {
return err
if err = store.DeleteRoleByID(ctx, s, obsoleteAdminsID); err != nil {
return
}
if err := store.CreateRole(ctx, s, m["admins"]); err != nil {
return err
if err = store.CreateRole(ctx, s, m["admins"]); err != nil {
return
}
// transfer all rbac rules
if err := s.TransferRoleMembers(ctx, obsoleteAdminsID, m["admins"].ID); err != nil {
return nil
if err = s.TransferRoleMembers(ctx, obsoleteAdminsID, m["admins"].ID); err != nil {
return
}
// transfer all rbac rules
if err := s.TransferRbacRules(ctx, obsoleteAdminsID, m["admins"].ID); err != nil {
return nil
if err = s.TransferRbacRules(ctx, obsoleteAdminsID, m["admins"].ID); err != nil {
return
}
}
return nil
return
}
func loadRoles(ctx context.Context, s store.Roles) (m map[string]*types.Role, err error) {
var (
f = types.RoleFilter{
Archived: filter.StateInclusive,
Deleted: filter.StateInclusive,
}
)
m = make(map[string]*types.Role)
if set, _, err := store.SearchRoles(ctx, s, f); err == nil {
for _, r := range set {
m[r.Handle] = r
}
}
return
}
+92
View File
@@ -0,0 +1,92 @@
package provision
import (
"context"
"fmt"
"time"
"github.com/cortezaproject/corteza-server/pkg/auth"
"github.com/cortezaproject/corteza-server/pkg/filter"
"github.com/cortezaproject/corteza-server/pkg/id"
"github.com/cortezaproject/corteza-server/store"
"github.com/cortezaproject/corteza-server/system/types"
"go.uber.org/zap"
)
// SystemUsers creates or updates system users
func SystemUsers(ctx context.Context, log *zap.Logger, s store.Users) (uu []*types.User, err error) {
var (
now = time.Now().Round(time.Second)
)
uu = types.UserSet{
&types.User{
Email: "provision@corteza.local",
Name: "Corteza Provisioner",
Handle: auth.ProvisionUserHandle,
Kind: types.SystemUser,
},
&types.User{
Email: "service@corteza.local",
Name: "Corteza Service",
Handle: auth.ServiceUserHandle,
Kind: types.SystemUser,
},
&types.User{
Email: "federation@corteza.local",
Name: "Corteza Federation",
Handle: auth.FederationUserHandle,
Kind: types.SystemUser,
},
}
m, err := loadUsers(ctx, s)
if err != nil {
return
}
for i := range uu {
u := uu[i]
if m[u.Handle] == nil {
log.Info("creating user", zap.String("handle", u.Handle))
// this is a new user
u.ID = id.Next()
u.CreatedAt = now
if err := store.UpsertUser(ctx, s, u); err != nil {
return nil, fmt.Errorf("failed to provision user %s: %w", u.Handle, err)
}
} else {
u.ID = m[u.Handle].ID
u.Email = m[u.Handle].Email
u.Name = m[u.Handle].Name
u.SuspendedAt = nil
u.DeletedAt = nil
if err := store.UpsertUser(ctx, s, u); err != nil {
return nil, fmt.Errorf("failed to provision user %s: %w", u.Handle, err)
}
}
}
return
}
func loadUsers(ctx context.Context, s store.Users) (m map[string]*types.User, err error) {
var (
f = types.UserFilter{
Suspended: filter.StateInclusive,
Deleted: filter.StateInclusive,
}
)
m = make(map[string]*types.User)
if set, _, err := store.SearchUsers(ctx, s, f); err == nil {
for _, r := range set {
m[r.Handle] = r
}
}
return
}
+4 -3
View File
@@ -3,6 +3,7 @@ package rdbms
import (
"context"
"fmt"
"github.com/Masterminds/squirrel"
"github.com/cortezaproject/corteza-server/pkg/filter"
"github.com/cortezaproject/corteza-server/system/types"
@@ -58,9 +59,9 @@ func (s Store) convertUserFilter(f types.UserFilter) (query squirrel.SelectBuild
query = query.Where(squirrel.Eq{"usr.handle": f.Handle})
}
if f.Kind != "" {
query = query.Where(squirrel.Eq{"usr.kind": f.Kind})
}
//if f.Kind != "" {
// query = query.Where(squirrel.Eq{"usr.kind": f.Kind})
//}
return
}
+1 -4
View File
@@ -10,14 +10,13 @@ import (
"github.com/cortezaproject/corteza-server/pkg/envoy/yaml"
"github.com/spf13/cobra"
"github.com/cortezaproject/corteza-server/pkg/auth"
"github.com/cortezaproject/corteza-server/pkg/cli"
"github.com/cortezaproject/corteza-server/pkg/envoy"
su "github.com/cortezaproject/corteza-server/pkg/envoy/store"
"github.com/cortezaproject/corteza-server/store"
)
func Export(storeInit func(ctx context.Context) (store.Storer, error)) *cobra.Command {
func Export(ctx context.Context, storeInit func(ctx context.Context) (store.Storer, error)) *cobra.Command {
var (
output string
)
@@ -29,8 +28,6 @@ func Export(storeInit func(ctx context.Context) (store.Storer, error)) *cobra.Co
Run: func(cmd *cobra.Command, args []string) {
var (
ctx = auth.SetSuperUserContext(cli.Context())
f = su.NewDecodeFilter()
)
+1 -6
View File
@@ -6,7 +6,6 @@ import (
"github.com/spf13/cobra"
"github.com/cortezaproject/corteza-server/pkg/auth"
"github.com/cortezaproject/corteza-server/pkg/cli"
"github.com/cortezaproject/corteza-server/pkg/envoy"
"github.com/cortezaproject/corteza-server/pkg/envoy/directory"
@@ -16,7 +15,7 @@ import (
"github.com/cortezaproject/corteza-server/store"
)
func Import(storeInit func(ctx context.Context) (store.Storer, error)) *cobra.Command {
func Import(ctx context.Context, storeInit func(ctx context.Context) (store.Storer, error)) *cobra.Command {
var (
replaceOnExisting bool
mergeLeftOnExisting bool
@@ -28,10 +27,6 @@ func Import(storeInit func(ctx context.Context) (store.Storer, error)) *cobra.Co
Short: "Import data from yaml sources.",
Run: func(cmd *cobra.Command, args []string) {
var (
ctx = auth.SetSuperUserContext(cli.Context())
)
s, err := storeInit(ctx)
cli.HandleError(err)
+3 -1
View File
@@ -1,6 +1,8 @@
package commands
import (
"context"
"github.com/spf13/cobra"
)
@@ -39,7 +41,7 @@ import (
// }
//)
func RBAC(app serviceInitializer) *cobra.Command {
func RBAC(ctx context.Context, app serviceInitializer) *cobra.Command {
cmd := &cobra.Command{
Use: "rbac",
Short: "RBAC tools",
+3 -4
View File
@@ -1,14 +1,15 @@
package commands
import (
"github.com/cortezaproject/corteza-server/pkg/auth"
"context"
"github.com/cortezaproject/corteza-server/pkg/cli"
"github.com/cortezaproject/corteza-server/system/service"
"github.com/cortezaproject/corteza-server/system/types"
"github.com/spf13/cobra"
)
func Roles(app serviceInitializer) *cobra.Command {
func Roles(ctx context.Context, app serviceInitializer) *cobra.Command {
cmd := &cobra.Command{
Use: "roles",
Short: "Role management",
@@ -21,8 +22,6 @@ func Roles(app serviceInitializer) *cobra.Command {
PreRunE: commandPreRunInitService(app),
Run: func(cmd *cobra.Command, args []string) {
var (
ctx = auth.SetSuperUserContext(cli.Context())
roleStr, userStr = args[0], args[1]
role *types.Role
+6 -23
View File
@@ -1,19 +1,20 @@
package commands
import (
"context"
"encoding/json"
"github.com/cortezaproject/corteza-server/system/types"
"os"
"strings"
"github.com/cortezaproject/corteza-server/system/types"
"github.com/spf13/cobra"
"github.com/cortezaproject/corteza-server/pkg/auth"
"github.com/cortezaproject/corteza-server/pkg/cli"
"github.com/cortezaproject/corteza-server/system/service"
)
func Settings(app serviceInitializer) *cobra.Command {
func Settings(ctx context.Context, app serviceInitializer) *cobra.Command {
var (
cmd = &cobra.Command{
Use: "settings",
@@ -26,10 +27,6 @@ func Settings(app serviceInitializer) *cobra.Command {
Short: "List all",
PreRunE: commandPreRunInitService(app),
Run: func(cmd *cobra.Command, args []string) {
var (
ctx = auth.SetSuperUserContext(cli.Context())
)
prefix := cmd.Flags().Lookup("prefix").Value.String()
if kv, err := service.DefaultSettings.FindByPrefix(ctx, prefix); err != nil {
cli.HandleError(err)
@@ -57,10 +54,6 @@ func Settings(app serviceInitializer) *cobra.Command {
Args: cobra.ExactArgs(1),
PreRunE: commandPreRunInitService(app),
Run: func(cmd *cobra.Command, args []string) {
var (
ctx = auth.SetSuperUserContext(cli.Context())
)
if v, err := service.DefaultSettings.Get(ctx, args[0], 0); err != nil {
cli.HandleError(err)
} else if v != nil {
@@ -75,11 +68,6 @@ func Settings(app serviceInitializer) *cobra.Command {
Args: cobra.ExactArgs(2),
PreRunE: commandPreRunInitService(app),
Run: func(cmd *cobra.Command, args []string) {
var (
err error
ctx = auth.SetSuperUserContext(cli.Context())
)
value := args[1]
v := &types.SettingValue{
@@ -87,16 +75,14 @@ func Settings(app serviceInitializer) *cobra.Command {
}
if cmd.Flags().Lookup("as-string").Changed {
err = v.SetValue(value)
cli.HandleError(v.SetValue(value))
} else {
err = v.SetRawValue(value)
err := v.SetRawValue(value)
if _, is := err.(*json.SyntaxError); is {
// Quote the raw value and re-parse
err = v.SetRawValue(`"` + value + `"`)
}
}
if err != nil {
cli.HandleError(err)
}
@@ -113,7 +99,6 @@ func Settings(app serviceInitializer) *cobra.Command {
PreRunE: commandPreRunInitService(app),
Run: func(cmd *cobra.Command, args []string) {
var (
ctx = auth.SetSuperUserContext(cli.Context())
fh *os.File
err error
)
@@ -153,7 +138,6 @@ func Settings(app serviceInitializer) *cobra.Command {
PreRunE: commandPreRunInitService(app),
Run: func(cmd *cobra.Command, args []string) {
var (
ctx = auth.SetSuperUserContext(cli.Context())
fh *os.File
err error
)
@@ -186,7 +170,6 @@ func Settings(app serviceInitializer) *cobra.Command {
PreRunE: commandPreRunInitService(app),
Run: func(cmd *cobra.Command, args []string) {
var (
ctx = auth.SetSuperUserContext(cli.Context())
names = []string{}
)
+4 -2
View File
@@ -1,13 +1,15 @@
package commands
import (
"context"
"time"
"github.com/cortezaproject/corteza-server/system/service"
"github.com/spf13/cobra"
"time"
)
// Will perform OpenID connect auto-configuration
func Sink(app serviceInitializer) *cobra.Command {
func Sink(ctx context.Context, app serviceInitializer) *cobra.Command {
var (
expires string
srup = service.SinkRequestUrlParams{}
+2 -8
View File
@@ -1,11 +1,11 @@
package commands
import (
"context"
"fmt"
"strconv"
"syscall"
"github.com/cortezaproject/corteza-server/pkg/auth"
"github.com/cortezaproject/corteza-server/pkg/cli"
"github.com/cortezaproject/corteza-server/pkg/filter"
"github.com/cortezaproject/corteza-server/system/service"
@@ -14,7 +14,7 @@ import (
"golang.org/x/crypto/ssh/terminal"
)
func Users(app serviceInitializer) *cobra.Command {
func Users(ctx context.Context, app serviceInitializer) *cobra.Command {
var (
flagNoPassword bool
)
@@ -33,8 +33,6 @@ func Users(app serviceInitializer) *cobra.Command {
PreRunE: commandPreRunInitService(app),
Run: func(cmd *cobra.Command, args []string) {
var (
ctx = auth.SetSuperUserContext(cli.Context())
queryFlag = cmd.Flags().Lookup("query").Value.String()
limitFlag = cmd.Flags().Lookup("limit").Value.String()
@@ -88,8 +86,6 @@ func Users(app serviceInitializer) *cobra.Command {
PreRunE: commandPreRunInitService(app),
Run: func(cmd *cobra.Command, args []string) {
var (
ctx = auth.SetSuperUserContext(cli.Context())
authSvc = service.Auth()
// @todo email validation
@@ -139,8 +135,6 @@ func Users(app serviceInitializer) *cobra.Command {
PreRunE: commandPreRunInitService(app),
Run: func(cmd *cobra.Command, args []string) {
var (
ctx = auth.SetSuperUserContext(cli.Context())
user *types.User
err error
password []byte
+57 -2
View File
@@ -12,9 +12,13 @@ import (
)
type (
actionlogUserSearcher interface {
Find(context.Context, types.UserFilter) (types.UserSet, types.UserFilter, error)
}
Actionlog struct {
actionSvc actionlog.Recorder
userSvc service.UserService
userSvc actionlogUserSearcher
}
// Extend actionlog.Action so we can
@@ -70,8 +74,9 @@ func (ctrl Actionlog) makeFilterPayload(ctx context.Context, ee []*actionlog.Act
pp[e] = &actionlogActionPayload{Action: ee[e]}
}
err = ctrl.userSvc.Preloader(
err = userPreloader(
ctx,
ctrl.userSvc,
func(c chan uint64) {
for e := range ee {
c <- ee[e].ActorID
@@ -103,3 +108,53 @@ func (ctrl Actionlog) makeFilterPayload(ctx context.Context, ee []*actionlog.Act
return &actionlogPayload{Filter: f, Set: pp}, nil
}
// Preloader collects all ids of users, loads them and sets them back
//
//
// @todo this kind of preloader is useful and can be implemented in bunch
// of places and replace old code
func userPreloader(ctx context.Context, svc actionlogUserSearcher, g func(chan uint64), f types.UserFilter, s func(*types.User) error) error {
var (
// channel that will collect the IDs in the getter
ch = make(chan uint64, 0)
// unique index for IDs
unq = make(map[uint64]bool)
)
// Reset the collection of the IDs
f.UserID = make([]uint64, 0)
// Call getter and collect the IDs
go g(ch)
rangeLoop:
for {
select {
case <-ctx.Done():
close(ch)
break rangeLoop
case id, ok := <-ch:
if !ok {
// Channel closed
break rangeLoop
}
if !unq[id] {
unq[id] = true
f.UserID = append(f.UserID, id)
}
}
}
// Load all users (even if deleted, suspended) from the given list of IDs
uu, _, err := svc.Find(ctx, f)
if err != nil {
return err
}
return uu.Walk(s)
}
+3 -2
View File
@@ -1,12 +1,13 @@
package scim
import (
"net/http"
"regexp"
"github.com/cortezaproject/corteza-server/pkg/options"
"github.com/cortezaproject/corteza-server/system/service"
"github.com/go-chi/chi"
"go.uber.org/zap"
"net/http"
"regexp"
)
type (
+4 -4
View File
@@ -2,16 +2,16 @@ package scim
import (
"context"
"github.com/cortezaproject/corteza-server/pkg/auth"
"net/http"
"github.com/cortezaproject/corteza-server/pkg/auth"
)
type (
getSecurityContextFn func(r *http.Request) context.Context
)
// All actions are in security context of a superuser for now
//
// Set service user to request's identity
func getSecurityContext(r *http.Request) context.Context {
return auth.SetSuperUserContext(r.Context())
return auth.SetIdentityToContext(r.Context(), auth.ServiceUser())
}
+3
View File
@@ -815,6 +815,9 @@ func (svc auth) procLogin(ctx context.Context, s store.Storer, u *types.User, c
return AuthErrFailedForSuspendedUser()
case u.DeletedAt != nil:
return AuthErrFailedForDeletedUser()
case u.Kind == types.SystemUser:
return AuthErrFailedForSystemUser()
}
if err = svc.LoadRoleMemberships(ctx, u); err != nil {
+36
View File
@@ -851,6 +851,42 @@ func AuthErrFailedForSuspendedUser(mm ...*authActionProps) *errors.Error {
return e
}
// AuthErrFailedForSystemUser returns "system:auth.failedForSystemUser" as *errors.Error
//
// Note: This error will be wrapped with safe (system:auth.invalidCredentials) error!
//
// This function is auto-generated.
//
func AuthErrFailedForSystemUser(mm ...*authActionProps) *errors.Error {
var p = &authActionProps{}
if len(mm) > 0 {
p = mm[0]
}
var e = errors.New(
errors.KindInternal,
"failedForSystemUser",
errors.Meta("type", "failedForSystemUser"),
errors.Meta("resource", "system:auth"),
// action log entry; no formatting, it will be applied inside recordAction fn.
errors.Meta(authLogMetaKey{}, "system user {user} tried to log-in with {credentials.kind}"),
errors.Meta(authPropsMetaKey{}, p),
errors.StackSkip(1),
)
if len(mm) > 0 {
}
// Wrap with safe error
e = AuthErrInvalidCredentials().Wrap(e)
return e
}
// AuthErrFailedUnconfirmedEmail returns "system:auth.failedUnconfirmedEmail" as *errors.Error
//
//
+5
View File
@@ -107,6 +107,11 @@ errors:
log: "suspended user {user} tried to log-in with {credentials.kind}"
severity: warning
- error: failedForSystemUser
maskedWith: invalidCredentials
log: "system user {user} tried to log-in with {credentials.kind}"
severity: warning
- error: failedUnconfirmedEmail
message: "system requires confirmed email before logging in"
log: "failed to log-in with with unconfirmed email"
+11 -1
View File
@@ -7,6 +7,7 @@ import (
"strings"
"github.com/cortezaproject/corteza-server/pkg/actionlog"
intAuth "github.com/cortezaproject/corteza-server/pkg/auth"
"github.com/cortezaproject/corteza-server/pkg/errors"
"github.com/cortezaproject/corteza-server/pkg/eventbus"
"github.com/cortezaproject/corteza-server/pkg/expr"
@@ -18,6 +19,7 @@ import (
"github.com/cortezaproject/corteza-server/store"
"github.com/cortezaproject/corteza-server/system/service/event"
"github.com/cortezaproject/corteza-server/system/types"
"go.uber.org/zap"
)
@@ -92,7 +94,7 @@ func Role() *role {
}
}
// SetImmutable sets list of handles for all system roles
// SetSystem sets list of handles for all system roles
//
// System roles can not be changed or deleted
func (svc role) SetSystem(hh ...string) {
@@ -725,12 +727,20 @@ func initRoles(ctx context.Context, log *zap.Logger, opt options.RBACOpt, eb eve
if bypass, err = s(opt.BypassRoles); err != nil {
return fmt.Errorf("failed to process list of bypass roles (RBAC_BYPASS_ROLES): %w", err)
} else if !bypass[intAuth.BypassRoleHandle] {
return fmt.Errorf("default bypass role %s (DefaultBypassRole) not in bypass role list (RBAC_BYPASS_ROLES)", intAuth.BypassRoleHandle)
}
if authenticated, err = s(opt.AuthenticatedRoles); err != nil {
return fmt.Errorf("failed to process list of authenticated roles (RBAC_AUTHENTICATED_ROLES): %w", err)
} else if !authenticated[intAuth.AuthenticatedRoleHandle] {
return fmt.Errorf("default authenticated role %s (DefaultAuthenticatedRole) not in authenticated role list (RBAC_AUTHENTICATED_ROLES)", intAuth.AuthenticatedRoleHandle)
}
if anonymous, err = s(opt.AnonymousRoles); err != nil {
return fmt.Errorf("failed to process list of anonymous roles (RBAC_ANONYMOUS_ROLES): %w", err)
} else if !anonymous[intAuth.AnonymousRoleHandle] {
return fmt.Errorf("default anonymous role %s (DefaultAnonymousRole) not in anonymous role list (RBAC_ANONYMOUS_ROLES)", intAuth.AnonymousRoleHandle)
}
for r := range authenticated {
+3 -4
View File
@@ -7,7 +7,6 @@ import (
automationService "github.com/cortezaproject/corteza-server/automation/service"
"github.com/cortezaproject/corteza-server/pkg/actionlog"
intAuth "github.com/cortezaproject/corteza-server/pkg/auth"
"github.com/cortezaproject/corteza-server/pkg/eventbus"
"github.com/cortezaproject/corteza-server/pkg/healthcheck"
"github.com/cortezaproject/corteza-server/pkg/id"
@@ -69,7 +68,7 @@ var (
DefaultAuth *auth
DefaultAuthClient *authClient
DefaultUser UserService
DefaultUser *user
DefaultRole *role
DefaultApplication *application
DefaultReminder ReminderService
@@ -161,7 +160,7 @@ func Initialize(ctx context.Context, log *zap.Logger, s store.Storer, ws websock
DefaultAuthNotification = AuthNotification(CurrentSettings, DefaultRenderer, c.Auth)
DefaultAuth = Auth()
DefaultAuthClient = AuthClient(DefaultStore, DefaultAccessControl, DefaultActionlog, eventbus.Service())
DefaultUser = User(ctx)
DefaultUser = User()
DefaultRole = Role()
DefaultApplication = Application(DefaultStore, DefaultAccessControl, DefaultActionlog, eventbus.Service())
DefaultReminder = Reminder(ctx, DefaultLogger.Named("reminder"), ws)
@@ -204,7 +203,7 @@ func Initialize(ctx context.Context, log *zap.Logger, s store.Storer, ws websock
func Activate(ctx context.Context) (err error) {
// Run initial update of current settings with super-user credentials
err = DefaultSettings.UpdateCurrent(intAuth.SetSuperUserContext(ctx))
err = DefaultSettings.UpdateCurrent(ctx)
if err != nil {
return
}
+46 -61
View File
@@ -37,6 +37,11 @@ type (
eventbus eventDispatcher
store store.Storer
// List (cache) of preloaded users, accessible by handle
//
// It also does negative caching by assigning empty User structs
preloaded map[string]*types.User
}
userAuth interface {
@@ -55,10 +60,6 @@ type (
CanUnmaskNameOnUser(context.Context, *types.User) bool
}
// Temp types to support user.Preloader
userIdGetter func(chan uint64)
userSetter func(*types.User) error
UserService interface {
FindByUsername(ctx context.Context, username string) (*types.User, error)
FindByEmail(ctx context.Context, email string) (*types.User, error)
@@ -81,14 +82,12 @@ type (
SetPassword(ctx context.Context, userID uint64, password string) error
Preloader(context.Context, userIdGetter, types.UserFilter, userSetter) error
DeleteAuthTokensByUserID(ctx context.Context, userID uint64) (err error)
DeleteAuthSessionsByUserID(ctx context.Context, userID uint64) (err error)
}
)
func User(ctx context.Context) *user {
func User() *user {
return &user{
eventbus: eventbus.Service(),
ac: DefaultAccessControl,
@@ -98,6 +97,8 @@ func User(ctx context.Context) *user {
store: DefaultStore,
actionlog: DefaultActionlog,
preloaded: make(map[string]*types.User),
}
}
@@ -111,16 +112,6 @@ func (svc user) FindByID(ctx context.Context, userID uint64) (u *types.User, err
return UserErrInvalidID()
}
su := internalAuth.NewIdentity(userID)
if internalAuth.IsSuperUser(su) {
// Handling case when looking for a super-user
//
// Currently, superuser is a virtual entity
// and does not exists in the db
u = &types.User{ID: userID}
return nil
}
u, err = store.LookupUserByID(ctx, svc.store, userID)
if u, err = svc.proc(ctx, u, err); err != nil {
return err
@@ -349,6 +340,10 @@ func (svc user) Create(ctx context.Context, new *types.User) (u *types.User, err
return UserErrNotAllowedToCreate()
}
if new.Kind == types.SystemUser {
return UserErrNotAllowedToCreateSystem()
}
if !handle.IsValid(new.Handle) {
return UserErrInvalidHandle()
}
@@ -420,6 +415,11 @@ func (svc user) Update(ctx context.Context, upd *types.User) (u *types.User, err
uaProps.setUser(u)
if upd.Kind == types.SystemUser || u.Kind == types.SystemUser {
return UserErrNotAllowedToUpdateSystem()
}
// @todo RBACv2 this could/should be solved via context roles
if upd.ID != internalAuth.GetIdentityFromContext(ctx).Identity() {
if !svc.ac.CanUpdateUser(ctx, u) {
return UserErrNotAllowedToUpdate()
@@ -519,6 +519,10 @@ func (svc user) Delete(ctx context.Context, userID uint64) (err error) {
return
}
if u.Kind == types.SystemUser {
return UserErrNotAllowedToDelete()
}
if !svc.ac.CanDeleteUser(ctx, u) {
return UserErrNotAllowedToDelete()
}
@@ -560,6 +564,10 @@ func (svc user) Undelete(ctx context.Context, userID uint64) (err error) {
return err
}
if u.Kind == types.SystemUser {
return UserErrNotAllowedToDelete()
}
if !svc.ac.CanDeleteUser(ctx, u) {
return UserErrNotAllowedToDelete()
}
@@ -593,6 +601,10 @@ func (svc user) Suspend(ctx context.Context, userID uint64) (err error) {
uaProps.setUser(u)
if u.Kind == types.SystemUser {
return UserErrNotAllowedToSuspend()
}
if !svc.ac.CanSuspendUser(ctx, u) {
return UserErrNotAllowedToSuspend()
}
@@ -634,6 +646,10 @@ func (svc user) Unsuspend(ctx context.Context, userID uint64) (err error) {
uaProps.setUser(u)
if u.Kind == types.SystemUser {
return UserErrNotAllowedToUnsuspend()
}
if !svc.ac.CanUnsuspendUser(ctx, u) {
return UserErrNotAllowedToUnsuspend()
}
@@ -646,7 +662,6 @@ func (svc user) Unsuspend(ctx context.Context, userID uint64) (err error) {
}()
return svc.recordAction(ctx, uaProps, UserActionUnsuspend, err)
}
// SetPassword sets new password for a user
@@ -665,6 +680,10 @@ func (svc user) SetPassword(ctx context.Context, userID uint64, newPassword stri
uaProps.setUser(u)
if u.Kind == types.SystemUser {
return UserErrNotAllowedToUpdateSystem()
}
if !svc.ac.CanUpdateUser(ctx, u) {
return UserErrNotAllowedToUpdate()
}
@@ -703,54 +722,20 @@ func (svc user) maskName(ctx context.Context, u *types.User) bool {
return svc.settings.Privacy.Mask.Name && !svc.ac.CanUnmaskNameOnUser(ctx, u)
}
// Preloader collects all ids of users, loads them and sets them back
//
//
// @todo this kind of preloader is useful and can be implemented in bunch
// of places and replace old code
func (svc user) Preloader(ctx context.Context, g userIdGetter, f types.UserFilter, s userSetter) error {
var (
// channel that will collect the IDs in the getter
ch = make(chan uint64, 0)
// unique index for IDs
unq = make(map[uint64]bool)
)
// Reset the collection of the IDs
f.UserID = make([]uint64, 0)
// Call getter and collect the IDs
go g(ch)
rangeLoop:
for {
select {
case <-ctx.Done():
close(ch)
break rangeLoop
case id, ok := <-ch:
if !ok {
// Channel closed
break rangeLoop
}
if !unq[id] {
unq[id] = true
f.UserID = append(f.UserID, id)
}
func (svc *user) Get(ctx context.Context, h string) (u *types.User, err error) {
if svc.preloaded[h] == nil {
svc.preloaded[h], err = svc.FindByHandle(ctx, h)
if err != nil {
svc.preloaded[h] = &types.User{}
return
}
}
// Load all users (even if deleted, suspended) from the given list of IDs
uu, _, err := svc.Find(ctx, f)
if err != nil {
return err
if svc.preloaded[h] == nil || svc.preloaded[h].ID == 0 {
return nil, UserErrNotFound()
}
return uu.Walk(s)
return svc.preloaded[h], nil
}
// DeleteAuthTokensByUserID will delete all auth tokens of user which will un-authorize all auth clients of user
+64
View File
@@ -798,6 +798,38 @@ func UserErrNotAllowedToCreate(mm ...*userActionProps) *errors.Error {
return e
}
// UserErrNotAllowedToCreateSystem returns "system:user.notAllowedToCreateSystem" as *errors.Error
//
//
// This function is auto-generated.
//
func UserErrNotAllowedToCreateSystem(mm ...*userActionProps) *errors.Error {
var p = &userActionProps{}
if len(mm) > 0 {
p = mm[0]
}
var e = errors.New(
errors.KindInternal,
p.Format("not allowed to create system users", nil),
errors.Meta("type", "notAllowedToCreateSystem"),
errors.Meta("resource", "system:user"),
// action log entry; no formatting, it will be applied inside recordAction fn.
errors.Meta(userLogMetaKey{}, "failed to create system users"),
errors.Meta(userPropsMetaKey{}, p),
errors.StackSkip(1),
)
if len(mm) > 0 {
}
return e
}
// UserErrNotAllowedToUpdate returns "system:user.notAllowedToUpdate" as *errors.Error
//
//
@@ -830,6 +862,38 @@ func UserErrNotAllowedToUpdate(mm ...*userActionProps) *errors.Error {
return e
}
// UserErrNotAllowedToUpdateSystem returns "system:user.notAllowedToUpdateSystem" as *errors.Error
//
//
// This function is auto-generated.
//
func UserErrNotAllowedToUpdateSystem(mm ...*userActionProps) *errors.Error {
var p = &userActionProps{}
if len(mm) > 0 {
p = mm[0]
}
var e = errors.New(
errors.KindInternal,
p.Format("not allowed to update system users", nil),
errors.Meta("type", "notAllowedToUpdateSystem"),
errors.Meta("resource", "system:user"),
// action log entry; no formatting, it will be applied inside recordAction fn.
errors.Meta(userLogMetaKey{}, "failed to update system users"),
errors.Meta(userPropsMetaKey{}, p),
errors.StackSkip(1),
)
if len(mm) > 0 {
}
return e
}
// UserErrNotAllowedToDelete returns "system:user.notAllowedToDelete" as *errors.Error
//
//
+8 -1
View File
@@ -82,7 +82,6 @@ errors:
message: "invalid email"
severity: warning
- error: notAllowedToRead
message: "not allowed to read this user"
log: "failed to read {user.handle}; insufficient permissions"
@@ -95,10 +94,18 @@ errors:
message: "not allowed to create users"
log: "failed to create users; insufficient permissions"
- error: notAllowedToCreateSystem
message: "not allowed to create system users"
log: "failed to create system users"
- error: notAllowedToUpdate
message: "not allowed to update this user"
log: "failed to update {user.handle}; insufficient permissions"
- error: notAllowedToUpdateSystem
message: "not allowed to update system users"
log: "failed to update system users"
- error: notAllowedToDelete
message: "not allowed to delete this user"
log: "failed to delete {user.handle}; insufficient permissions"
+20 -1
View File
@@ -105,7 +105,7 @@ type (
const (
NormalUser UserKind = ""
BotUser UserKind = "bot"
SystemUser UserKind = "sys"
)
func (u User) String() string {
@@ -128,6 +128,25 @@ func (u *User) SetRoles(rr []uint64) {
u.roles = rr
}
func (u *User) Clone() *User {
return &User{
ID: u.ID,
Username: u.Username,
Email: u.Email,
Name: u.Name,
Handle: u.Handle,
Kind: u.Kind,
Meta: u.Meta,
EmailConfirmed: u.EmailConfirmed,
Labels: u.Labels,
CreatedAt: u.CreatedAt,
UpdatedAt: u.UpdatedAt,
SuspendedAt: u.SuspendedAt,
DeletedAt: u.DeletedAt,
roles: u.roles,
}
}
func (meta *UserMeta) Scan(value interface{}) error {
//lint:ignore S1034 This typecast is intentional, we need to get []byte out of a []uint8
switch value.(type) {
-1
View File
@@ -7,7 +7,6 @@ import (
func TestProvisioning(t *testing.T) {
t.SkipNow()
//h := newHelper(t)
//ctx := auth.SetSuperUserContext(h.secCtx())
//
//readers, err := impAux.ReadStatic(provision.Asset)
//h.noError(err)
-1
View File
@@ -7,7 +7,6 @@ import (
func TestProvisioning(t *testing.T) {
t.SkipNow()
//h := newHelper(t)
//ctx := auth.SetSuperUserContext(h.secCtx())
//
//readers, err := impAux.ReadStatic(provision.Asset)
//h.noError(err)
+8 -8
View File
@@ -17,7 +17,7 @@ import (
func TestDataShaping(t *testing.T) {
var (
ctx = auth.SetSuperUserContext(context.Background())
ctx = context.Background()
s = initStore(ctx, t)
err error
@@ -88,7 +88,7 @@ func TestDataShaping(t *testing.T) {
func TestDataShaping_large(t *testing.T) {
var (
ctx = auth.SetSuperUserContext(context.Background())
ctx = context.Background()
s = initStore(ctx, t)
err error
@@ -154,7 +154,7 @@ func TestDataShaping_large(t *testing.T) {
func TestDataShaping_fieldTypes(t *testing.T) {
var (
ctx = auth.SetSuperUserContext(context.Background())
ctx = context.Background()
s = initStore(ctx, t)
err error
@@ -232,7 +232,7 @@ func TestDataShaping_fieldTypes(t *testing.T) {
func TestDataShaping_refs(t *testing.T) {
var (
ctx = auth.SetSuperUserContext(context.Background())
ctx = context.Background()
s = initStore(ctx, t)
err error
@@ -320,7 +320,7 @@ func TestDataShaping_refs(t *testing.T) {
func TestDataShaping_xrefsPeer(t *testing.T) {
var (
ctx = auth.SetSuperUserContext(context.Background())
ctx = context.Background()
s = initStore(ctx, t)
err error
@@ -408,7 +408,7 @@ func TestDataShaping_xrefsPeer(t *testing.T) {
func TestDataShaping_xrefsStore(t *testing.T) {
var (
ctx = auth.SetSuperUserContext(context.Background())
ctx = context.Background()
s = initStore(ctx, t)
err error
@@ -501,7 +501,7 @@ func TestDataShaping_xrefsStore(t *testing.T) {
func TestDataShaping_xrefsMix(t *testing.T) {
var (
ctx = auth.SetSuperUserContext(context.Background())
ctx = context.Background()
s = initStore(ctx, t)
err error
@@ -600,7 +600,7 @@ func TestDataShaping_xrefsMix(t *testing.T) {
func TestDataShaping_update(t *testing.T) {
var (
ctx = auth.SetSuperUserContext(context.Background())
ctx = context.Background()
s = initStore(ctx, t)
err error
+2 -2
View File
@@ -35,7 +35,7 @@ func TestStoreCsv_records(t *testing.T) {
}
)
ctx := auth.SetSuperUserContext(context.Background())
ctx := context.Background()
s := initStore(ctx, t)
ni := uint64(10)
@@ -255,7 +255,7 @@ func TestStoreCsv_records_fieldTypes(t *testing.T) {
}
)
ctx := auth.SetSuperUserContext(context.Background())
ctx := context.Background()
s := initStore(ctx, t)
ni := uint64(10)
+2 -2
View File
@@ -36,7 +36,7 @@ func TestStoreJsonl_records(t *testing.T) {
}
)
ctx := auth.SetSuperUserContext(context.Background())
ctx := context.Background()
s := initStore(ctx, t)
ni := uint64(10)
@@ -255,7 +255,7 @@ func TestStoreJsonl_records_fieldTypes(t *testing.T) {
}
)
ctx := auth.SetSuperUserContext(context.Background())
ctx := context.Background()
s := initStore(ctx, t)
ni := uint64(10)
+1 -1
View File
@@ -39,7 +39,7 @@ func TestStoreYaml_base(t *testing.T) {
}
)
ctx := auth.SetSuperUserContext(context.Background())
ctx := context.Background()
s := initStore(ctx, t)
ni := uint64(10)
+1 -1
View File
@@ -30,7 +30,7 @@ func TestStoreYaml_moduleFieldRefs(t *testing.T) {
}
)
ctx := auth.SetSuperUserContext(context.Background())
ctx := context.Background()
s := initStore(ctx, t)
ni := uint64(10)
+1 -1
View File
@@ -31,7 +31,7 @@ func TestStoreYaml_pageRefs(t *testing.T) {
}
)
ctx := auth.SetSuperUserContext(context.Background())
ctx := context.Background()
s := initStore(ctx, t)
ni := uint64(10)
+1 -1
View File
@@ -15,7 +15,7 @@ import (
func TestStamps(t *testing.T) {
var (
ctx = auth.SetSuperUserContext(context.Background())
ctx = context.Background()
s = initStore(ctx, t)
req = require.New(t)
+1 -2
View File
@@ -9,7 +9,6 @@ import (
atypes "github.com/cortezaproject/corteza-server/automation/types"
ctypes "github.com/cortezaproject/corteza-server/compose/types"
"github.com/cortezaproject/corteza-server/pkg/auth"
"github.com/cortezaproject/corteza-server/pkg/envoy/resource"
su "github.com/cortezaproject/corteza-server/pkg/envoy/store"
"github.com/cortezaproject/corteza-server/pkg/rbac"
@@ -35,7 +34,7 @@ func TestYamlStore_base(t *testing.T) {
)
var (
ctx = auth.SetSuperUserContext(context.Background())
ctx = context.Background()
namespace = "base"
s = initStore(ctx, t)
err error
+1 -1
View File
@@ -18,7 +18,7 @@ import (
func TestYamlStore_provision(t *testing.T) {
var (
ctx = auth.SetSuperUserContext(context.Background())
ctx = context.Background()
s = initStore(ctx, t)
)
+1 -2
View File
@@ -7,7 +7,6 @@ import (
"testing"
"github.com/cortezaproject/corteza-server/compose/types"
"github.com/cortezaproject/corteza-server/pkg/auth"
su "github.com/cortezaproject/corteza-server/pkg/envoy/store"
"github.com/cortezaproject/corteza-server/store"
"github.com/stretchr/testify/require"
@@ -29,7 +28,7 @@ func TestYamlStore_relations(t *testing.T) {
)
var (
ctx = auth.SetSuperUserContext(context.Background())
ctx = context.Background()
namespace = "relations"
s = initStore(ctx, t)
err error
-1
View File
@@ -7,7 +7,6 @@ import (
func TestProvisioning(t *testing.T) {
t.SkipNow()
//h := newHelper(t)
//ctx := auth.SetSuperUserContext(h.secCtx())
//
//readers, err := impAux.ReadStatic(provision.Asset)
//h.a.NoError(err)