Improve default auth client handling
Prevent default auth clients from changing their handle, being deleted, or de-activated.
This commit is contained in:
@@ -2,8 +2,10 @@ package rest
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/cortezaproject/corteza-server/pkg/api"
|
||||
"github.com/cortezaproject/corteza-server/pkg/filter"
|
||||
"github.com/cortezaproject/corteza-server/pkg/options"
|
||||
"github.com/cortezaproject/corteza-server/system/rest/request"
|
||||
"github.com/cortezaproject/corteza-server/system/service"
|
||||
"github.com/cortezaproject/corteza-server/system/types"
|
||||
@@ -16,6 +18,7 @@ type (
|
||||
AuthClient struct {
|
||||
authClient authClientService
|
||||
ac authClientAccessController
|
||||
opt options.AuthOpt
|
||||
}
|
||||
|
||||
authClientService interface {
|
||||
@@ -27,6 +30,7 @@ type (
|
||||
Undelete(ctx context.Context, ID uint64) (err error)
|
||||
ExposeSecret(ctx context.Context, ID uint64) (secret string, err error)
|
||||
RegenerateSecret(ctx context.Context, ID uint64) (secret string, err error)
|
||||
IsDefaultClient(c *types.AuthClient) bool
|
||||
}
|
||||
|
||||
authClientAccessController interface {
|
||||
@@ -39,6 +43,8 @@ type (
|
||||
authClientPayload struct {
|
||||
*types.AuthClient
|
||||
|
||||
IsDefault bool `json:"isDefault"`
|
||||
|
||||
CanGrant bool `json:"canGrant"`
|
||||
CanUpdateAuthClient bool `json:"canUpdateAuthClient"`
|
||||
CanDeleteAuthClient bool `json:"canDeleteAuthClient"`
|
||||
@@ -153,6 +159,8 @@ func (ctrl AuthClient) makePayload(ctx context.Context, m *types.AuthClient, err
|
||||
return &authClientPayload{
|
||||
AuthClient: m,
|
||||
|
||||
IsDefault: ctrl.authClient.IsDefaultClient(m),
|
||||
|
||||
CanGrant: ctrl.ac.CanGrant(ctx),
|
||||
|
||||
CanUpdateAuthClient: ctrl.ac.CanUpdateAuthClient(ctx, m),
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"github.com/cortezaproject/corteza-server/pkg/errors"
|
||||
"github.com/cortezaproject/corteza-server/pkg/filter"
|
||||
"github.com/cortezaproject/corteza-server/pkg/label"
|
||||
"github.com/cortezaproject/corteza-server/pkg/options"
|
||||
"github.com/cortezaproject/corteza-server/pkg/rand"
|
||||
"github.com/cortezaproject/corteza-server/store"
|
||||
"github.com/cortezaproject/corteza-server/system/service/event"
|
||||
@@ -20,6 +21,7 @@ type (
|
||||
eventbus eventDispatcher
|
||||
actionlog actionlog.Recorder
|
||||
store store.Storer
|
||||
opt options.AuthOpt
|
||||
}
|
||||
|
||||
authClientAccessController interface {
|
||||
@@ -32,8 +34,14 @@ type (
|
||||
)
|
||||
|
||||
// AuthClient is a default authClient service initializer
|
||||
func AuthClient(s store.Storer, ac authClientAccessController, al actionlog.Recorder, eb eventDispatcher) *authClient {
|
||||
return &authClient{store: s, ac: ac, actionlog: al, eventbus: eb}
|
||||
func AuthClient(s store.Storer, ac authClientAccessController, al actionlog.Recorder, eb eventDispatcher, opt options.AuthOpt) *authClient {
|
||||
return &authClient{
|
||||
store: s,
|
||||
ac: ac,
|
||||
actionlog: al,
|
||||
eventbus: eb,
|
||||
opt: opt,
|
||||
}
|
||||
}
|
||||
|
||||
func (svc *authClient) LookupByID(ctx context.Context, ID uint64) (client *types.AuthClient, err error) {
|
||||
@@ -80,6 +88,14 @@ func (svc *authClient) RegenerateSecret(ctx context.Context, ID uint64) (secret
|
||||
return secret, svc.recordAction(ctx, aaProps, AuthClientActionRegenerateSecret, err)
|
||||
}
|
||||
|
||||
func (svc *authClient) IsDefaultClient(c *types.AuthClient) bool {
|
||||
if c == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
return c.Handle == svc.opt.DefaultClient
|
||||
}
|
||||
|
||||
func (svc *authClient) lookupByID(ctx context.Context, ID uint64) (client *types.AuthClient, err error) {
|
||||
err = func() error {
|
||||
if ID == 0 {
|
||||
@@ -222,7 +238,24 @@ func (svc *authClient) Create(ctx context.Context, new *types.AuthClient) (app *
|
||||
|
||||
func (svc *authClient) Update(ctx context.Context, upd *types.AuthClient) (app *types.AuthClient, err error) {
|
||||
var (
|
||||
aaProps = &authClientActionProps{update: upd}
|
||||
aaProps = &authClientActionProps{update: upd}
|
||||
defaultClientValidator = func(old, upd *types.AuthClient) error {
|
||||
if old.Handle != svc.opt.DefaultClient {
|
||||
return nil
|
||||
}
|
||||
|
||||
// The handle may not change
|
||||
if old.Handle != upd.Handle {
|
||||
return AuthClientErrUnableToChangeDefaultClientHandle()
|
||||
}
|
||||
|
||||
// The client may not get disabled
|
||||
if !upd.Enabled {
|
||||
return AuthClientErrUnableToDisableDefaultClient()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
)
|
||||
|
||||
err = func() (err error) {
|
||||
@@ -247,10 +280,20 @@ func (svc *authClient) Update(ctx context.Context, upd *types.AuthClient) (app *
|
||||
return AuthClientErrNotAllowedToUpdate()
|
||||
}
|
||||
|
||||
// Firstly validate before the automation occurs
|
||||
if err = defaultClientValidator(app, upd); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err = svc.eventbus.WaitFor(ctx, event.AuthClientBeforeUpdate(upd, app)); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Next validate after the automation occurs
|
||||
if err = defaultClientValidator(app, upd); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Assign changed values after afterUpdate events are emitted
|
||||
app.Handle = upd.Handle
|
||||
app.ValidGrant = upd.ValidGrant
|
||||
@@ -309,6 +352,10 @@ func (svc *authClient) Delete(ctx context.Context, ID uint64) (err error) {
|
||||
return AuthClientErrNotAllowedToDelete()
|
||||
}
|
||||
|
||||
if app.Handle == svc.opt.DefaultClient {
|
||||
return AuthClientErrUnableToDeleteDefaultClient()
|
||||
}
|
||||
|
||||
if err = svc.eventbus.WaitFor(ctx, event.AuthClientBeforeDelete(nil, app)); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
+96
@@ -498,6 +498,102 @@ func AuthClientErrInvalidID(mm ...*authClientActionProps) *errors.Error {
|
||||
return e
|
||||
}
|
||||
|
||||
// AuthClientErrUnableToChangeDefaultClientHandle returns "system:auth-client.unableToChangeDefaultClientHandle" as *errors.Error
|
||||
//
|
||||
//
|
||||
// This function is auto-generated.
|
||||
//
|
||||
func AuthClientErrUnableToChangeDefaultClientHandle(mm ...*authClientActionProps) *errors.Error {
|
||||
var p = &authClientActionProps{}
|
||||
if len(mm) > 0 {
|
||||
p = mm[0]
|
||||
}
|
||||
|
||||
var e = errors.New(
|
||||
errors.KindInternal,
|
||||
|
||||
p.Format("unable to change the handle of the default auth client", nil),
|
||||
|
||||
errors.Meta("type", "unableToChangeDefaultClientHandle"),
|
||||
errors.Meta("resource", "system:auth-client"),
|
||||
|
||||
// action log entry; no formatting, it will be applied inside recordAction fn.
|
||||
errors.Meta(authClientLogMetaKey{}, "failed to update {authClient}; unable to change the default auth client handle"),
|
||||
errors.Meta(authClientPropsMetaKey{}, p),
|
||||
|
||||
errors.StackSkip(1),
|
||||
)
|
||||
|
||||
if len(mm) > 0 {
|
||||
}
|
||||
|
||||
return e
|
||||
}
|
||||
|
||||
// AuthClientErrUnableToDisableDefaultClient returns "system:auth-client.unableToDisableDefaultClient" as *errors.Error
|
||||
//
|
||||
//
|
||||
// This function is auto-generated.
|
||||
//
|
||||
func AuthClientErrUnableToDisableDefaultClient(mm ...*authClientActionProps) *errors.Error {
|
||||
var p = &authClientActionProps{}
|
||||
if len(mm) > 0 {
|
||||
p = mm[0]
|
||||
}
|
||||
|
||||
var e = errors.New(
|
||||
errors.KindInternal,
|
||||
|
||||
p.Format("unable to disable the default auth client", nil),
|
||||
|
||||
errors.Meta("type", "unableToDisableDefaultClient"),
|
||||
errors.Meta("resource", "system:auth-client"),
|
||||
|
||||
// action log entry; no formatting, it will be applied inside recordAction fn.
|
||||
errors.Meta(authClientLogMetaKey{}, "failed to update {authClient}; unable to disable the default auth client"),
|
||||
errors.Meta(authClientPropsMetaKey{}, p),
|
||||
|
||||
errors.StackSkip(1),
|
||||
)
|
||||
|
||||
if len(mm) > 0 {
|
||||
}
|
||||
|
||||
return e
|
||||
}
|
||||
|
||||
// AuthClientErrUnableToDeleteDefaultClient returns "system:auth-client.unableToDeleteDefaultClient" as *errors.Error
|
||||
//
|
||||
//
|
||||
// This function is auto-generated.
|
||||
//
|
||||
func AuthClientErrUnableToDeleteDefaultClient(mm ...*authClientActionProps) *errors.Error {
|
||||
var p = &authClientActionProps{}
|
||||
if len(mm) > 0 {
|
||||
p = mm[0]
|
||||
}
|
||||
|
||||
var e = errors.New(
|
||||
errors.KindInternal,
|
||||
|
||||
p.Format("unable to delete the default auth client", nil),
|
||||
|
||||
errors.Meta("type", "unableToDeleteDefaultClient"),
|
||||
errors.Meta("resource", "system:auth-client"),
|
||||
|
||||
// action log entry; no formatting, it will be applied inside recordAction fn.
|
||||
errors.Meta(authClientLogMetaKey{}, "failed to update {authClient}; unable to delete the default auth client"),
|
||||
errors.Meta(authClientPropsMetaKey{}, p),
|
||||
|
||||
errors.StackSkip(1),
|
||||
)
|
||||
|
||||
if len(mm) > 0 {
|
||||
}
|
||||
|
||||
return e
|
||||
}
|
||||
|
||||
// AuthClientErrNotAllowedToRead returns "system:auth-client.notAllowedToRead" as *errors.Error
|
||||
//
|
||||
//
|
||||
|
||||
@@ -61,6 +61,18 @@ errors:
|
||||
message: "invalid ID"
|
||||
severity: warning
|
||||
|
||||
- error: unableToChangeDefaultClientHandle
|
||||
message: "unable to change the handle of the default auth client"
|
||||
log: "failed to update {authClient}; unable to change the default auth client handle"
|
||||
|
||||
- error: unableToDisableDefaultClient
|
||||
message: "unable to disable the default auth client"
|
||||
log: "failed to update {authClient}; unable to disable the default auth client"
|
||||
|
||||
- error: unableToDeleteDefaultClient
|
||||
message: "unable to delete the default auth client"
|
||||
log: "failed to update {authClient}; unable to delete the default auth client"
|
||||
|
||||
- error: notAllowedToRead
|
||||
message: "not allowed to read this auth client"
|
||||
log: "failed to read {authClient}; insufficient permissions"
|
||||
|
||||
@@ -159,7 +159,7 @@ func Initialize(ctx context.Context, log *zap.Logger, s store.Storer, ws websock
|
||||
DefaultRenderer = Renderer(c.Template)
|
||||
DefaultAuthNotification = AuthNotification(CurrentSettings, DefaultRenderer, c.Auth)
|
||||
DefaultAuth = Auth()
|
||||
DefaultAuthClient = AuthClient(DefaultStore, DefaultAccessControl, DefaultActionlog, eventbus.Service())
|
||||
DefaultAuthClient = AuthClient(DefaultStore, DefaultAccessControl, DefaultActionlog, eventbus.Service(), c.Auth)
|
||||
DefaultUser = User()
|
||||
DefaultRole = Role()
|
||||
DefaultApplication = Application(DefaultStore, DefaultAccessControl, DefaultActionlog, eventbus.Service())
|
||||
|
||||
Reference in New Issue
Block a user