feat: allow session deletion without session token (#6889)

* fix: add resource owner of user and change the one of session to instance

* use user resource owner from session projection

* fix session permission check

* integration tests and fixes

* update api docs
This commit is contained in:
Livio Spring
2023-11-16 08:35:50 +02:00
committed by GitHub
parent 0948a0b9ae
commit 2e8c3b5a53
18 changed files with 448 additions and 301 deletions

View File

@@ -55,12 +55,12 @@ func (c *Commands) NewSessionCommands(cmds []SessionCommand, session *SessionWri
}
// CheckUser defines a user check to be executed for a session update
func CheckUser(id string) SessionCommand {
func CheckUser(id string, resourceOwner string) SessionCommand {
return func(ctx context.Context, cmd *SessionCommands) error {
if cmd.sessionWriteModel.UserID != "" && id != "" && cmd.sessionWriteModel.UserID != id {
return caos_errs.ThrowInvalidArgument(nil, "", "user change not possible")
}
return cmd.UserChecked(ctx, id, cmd.now())
return cmd.UserChecked(ctx, id, resourceOwner, cmd.now())
}
}
@@ -170,10 +170,11 @@ func (s *SessionCommands) Start(ctx context.Context, userAgent *domain.UserAgent
s.eventCommands = append(s.eventCommands, session.NewAddedEvent(ctx, s.sessionWriteModel.aggregate, userAgent))
}
func (s *SessionCommands) UserChecked(ctx context.Context, userID string, checkedAt time.Time) error {
s.eventCommands = append(s.eventCommands, session.NewUserCheckedEvent(ctx, s.sessionWriteModel.aggregate, userID, checkedAt))
func (s *SessionCommands) UserChecked(ctx context.Context, userID, resourceOwner string, checkedAt time.Time) error {
s.eventCommands = append(s.eventCommands, session.NewUserCheckedEvent(ctx, s.sessionWriteModel.aggregate, userID, resourceOwner, checkedAt))
// set the userID so other checks can use it
s.sessionWriteModel.UserID = userID
s.sessionWriteModel.UserResourceOwner = resourceOwner
return nil
}
@@ -267,7 +268,7 @@ func (s *SessionCommands) gethumanWriteModel(ctx context.Context) (*HumanWriteMo
if s.sessionWriteModel.UserID == "" {
return nil, caos_errs.ThrowPreconditionFailed(nil, "COMMAND-eeR2e", "Errors.User.UserIDMissing")
}
humanWriteModel := NewHumanWriteModel(s.sessionWriteModel.UserID, "")
humanWriteModel := NewHumanWriteModel(s.sessionWriteModel.UserID, s.sessionWriteModel.UserResourceOwner)
err := s.eventstore.FilterToQueryReducer(ctx, humanWriteModel)
if err != nil {
return nil, err
@@ -296,7 +297,7 @@ func (c *Commands) CreateSession(ctx context.Context, cmds []SessionCommand, met
if err != nil {
return nil, err
}
sessionWriteModel := NewSessionWriteModel(sessionID, authz.GetCtxData(ctx).OrgID)
sessionWriteModel := NewSessionWriteModel(sessionID, authz.GetInstance(ctx).InstanceID())
err = c.eventstore.FilterToQueryReducer(ctx, sessionWriteModel)
if err != nil {
return nil, err
@@ -307,12 +308,12 @@ func (c *Commands) CreateSession(ctx context.Context, cmds []SessionCommand, met
}
func (c *Commands) UpdateSession(ctx context.Context, sessionID, sessionToken string, cmds []SessionCommand, metadata map[string][]byte, lifetime time.Duration) (set *SessionChanged, err error) {
sessionWriteModel := NewSessionWriteModel(sessionID, authz.GetCtxData(ctx).OrgID)
sessionWriteModel := NewSessionWriteModel(sessionID, authz.GetInstance(ctx).InstanceID())
err = c.eventstore.FilterToQueryReducer(ctx, sessionWriteModel)
if err != nil {
return nil, err
}
if err := c.sessionPermission(ctx, sessionWriteModel, sessionToken, domain.PermissionSessionWrite); err != nil {
if err := c.sessionTokenVerifier(ctx, sessionToken, sessionWriteModel.AggregateID, sessionWriteModel.TokenID); err != nil {
return nil, err
}
cmd := c.NewSessionCommands(cmds, sessionWriteModel)
@@ -328,12 +329,12 @@ func (c *Commands) TerminateSessionWithoutTokenCheck(ctx context.Context, sessio
}
func (c *Commands) terminateSession(ctx context.Context, sessionID, sessionToken string, mustCheckToken bool) (*domain.ObjectDetails, error) {
sessionWriteModel := NewSessionWriteModel(sessionID, "")
sessionWriteModel := NewSessionWriteModel(sessionID, authz.GetInstance(ctx).InstanceID())
if err := c.eventstore.FilterToQueryReducer(ctx, sessionWriteModel); err != nil {
return nil, err
}
if mustCheckToken {
if err := c.sessionPermission(ctx, sessionWriteModel, sessionToken, domain.PermissionSessionDelete); err != nil {
if err := c.checkSessionTerminationPermission(ctx, sessionWriteModel, sessionToken); err != nil {
return nil, err
}
}
@@ -386,13 +387,17 @@ func (c *Commands) updateSession(ctx context.Context, checks *SessionCommands, m
return changed, nil
}
// sessionPermission will check that the provided sessionToken is correct or
// if empty, check that the caller is granted the necessary permission
func (c *Commands) sessionPermission(ctx context.Context, sessionWriteModel *SessionWriteModel, sessionToken, permission string) (err error) {
if sessionToken == "" {
return c.checkPermission(ctx, permission, authz.GetCtxData(ctx).OrgID, sessionWriteModel.AggregateID)
// checkSessionTerminationPermission will check that the provided sessionToken is correct or
// if empty, check that the caller is either terminating the own session or
// is granted the "session.delete" permission on the resource owner of the authenticated user.
func (c *Commands) checkSessionTerminationPermission(ctx context.Context, model *SessionWriteModel, token string) error {
if token != "" {
return c.sessionTokenVerifier(ctx, token, model.AggregateID, model.TokenID)
}
return c.sessionTokenVerifier(ctx, sessionToken, sessionWriteModel.AggregateID, sessionWriteModel.TokenID)
if model.UserID != "" && model.UserID == authz.GetCtxData(ctx).UserID {
return nil
}
return c.checkPermission(ctx, domain.PermissionSessionDelete, model.UserResourceOwner, model.UserID)
}
func sessionTokenCreator(idGenerator id.Generator, sessionAlg crypto.EncryptionAlgorithm) func(sessionID string) (id string, token string, err error) {