fix: check if session is reused on reauthentication (#6322)

* fix: check if session is reused on reauth steps

* add nolint directive

---------

Co-authored-by: Silvan <silvan.reusser@gmail.com>
This commit is contained in:
Livio Spring 2023-08-07 10:01:24 +02:00 committed by GitHub
parent d937ee3dda
commit 57857b8d30
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -547,6 +547,13 @@ func (repo *AuthRequestRepo) getAuthRequestEnsureUser(ctx context.Context, authR
if err != nil { if err != nil {
return nil, err return nil, err
} }
// If there's no user, checks if the user could be reused (from the session).
// (the nextStepsUser will update the userID in the request in that case)
if request.UserID == "" {
if _, err = repo.nextStepsUser(request); err != nil {
return nil, err
}
}
if request.UserID != userID { if request.UserID != userID {
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-GBH32", "Errors.User.NotMatchingUserID") return nil, errors.ThrowPreconditionFailed(nil, "EVENT-GBH32", "Errors.User.NotMatchingUserID")
} }
@ -913,50 +920,19 @@ func (repo *AuthRequestRepo) checkExternalUserLogin(ctx context.Context, request
return nil return nil
} }
func (repo *AuthRequestRepo) nextSteps(ctx context.Context, request *domain.AuthRequest, checkLoggedIn bool) ([]domain.NextStep, error) { //nolint:gocognit
func (repo *AuthRequestRepo) nextSteps(ctx context.Context, request *domain.AuthRequest, checkLoggedIn bool) (steps []domain.NextStep, err error) {
if request == nil { if request == nil {
return nil, errors.ThrowInvalidArgument(nil, "EVENT-ds27a", "Errors.Internal") return nil, errors.ThrowInvalidArgument(nil, "EVENT-ds27a", "Errors.Internal")
} }
steps := make([]domain.NextStep, 0) steps = make([]domain.NextStep, 0)
if !checkLoggedIn && domain.IsPrompt(request.Prompt, domain.PromptNone) { if !checkLoggedIn && domain.IsPrompt(request.Prompt, domain.PromptNone) {
return append(steps, &domain.RedirectToCallbackStep{}), nil return append(steps, &domain.RedirectToCallbackStep{}), nil
} }
if request.UserID == "" { if request.UserID == "" {
if request.LinkingUsers != nil && len(request.LinkingUsers) > 0 { steps, err = repo.nextStepsUser(request)
steps = append(steps, new(domain.ExternalNotFoundOptionStep)) if err != nil || len(steps) > 0 {
return steps, nil return steps, err
}
if domain.IsPrompt(request.Prompt, domain.PromptCreate) {
return append(steps, &domain.RegistrationStep{}), nil
}
// if there's a login or consent prompt, but not select account, just return the login step
if len(request.Prompt) > 0 && !domain.IsPrompt(request.Prompt, domain.PromptSelectAccount) {
return append(steps, new(domain.LoginStep)), nil
} else {
// if no user was specified, no prompt or select_account was provided,
// then check the active user sessions (of the user agent)
users, err := repo.usersForUserSelection(request)
if err != nil {
return nil, err
}
if domain.IsPrompt(request.Prompt, domain.PromptSelectAccount) {
steps = append(steps, &domain.SelectUserStep{Users: users})
}
if request.SelectedIDPConfigID != "" {
steps = append(steps, &domain.RedirectToExternalIDPStep{})
}
if len(request.Prompt) == 0 && len(users) == 0 {
steps = append(steps, new(domain.LoginStep))
}
// if no prompt was provided, but there are multiple user sessions, then the user must decide which to use
if len(request.Prompt) == 0 && len(users) > 1 {
steps = append(steps, &domain.SelectUserStep{Users: users})
}
if len(steps) > 0 {
return steps, nil
}
// a single user session was found, use that automatically
request.UserID = users[0].UserID
} }
} }
user, err := activeUserByID(ctx, repo.UserViewProvider, repo.UserEventProvider, repo.OrgViewProvider, repo.LockoutPolicyViewProvider, request.UserID, request.LoginPolicy.IgnoreUnknownUsernames) user, err := activeUserByID(ctx, repo.UserViewProvider, repo.UserEventProvider, repo.OrgViewProvider, repo.LockoutPolicyViewProvider, request.UserID, request.LoginPolicy.IgnoreUnknownUsernames)
@ -1046,6 +1022,47 @@ func (repo *AuthRequestRepo) nextSteps(ctx context.Context, request *domain.Auth
return append(steps, &domain.RedirectToCallbackStep{}), nil return append(steps, &domain.RedirectToCallbackStep{}), nil
} }
func (repo *AuthRequestRepo) nextStepsUser(request *domain.AuthRequest) ([]domain.NextStep, error) {
steps := make([]domain.NextStep, 0)
if request.LinkingUsers != nil && len(request.LinkingUsers) > 0 {
steps = append(steps, new(domain.ExternalNotFoundOptionStep))
return steps, nil
}
if domain.IsPrompt(request.Prompt, domain.PromptCreate) {
return append(steps, &domain.RegistrationStep{}), nil
}
// if there's a login or consent prompt, but not select account, just return the login step
if len(request.Prompt) > 0 && !domain.IsPrompt(request.Prompt, domain.PromptSelectAccount) {
return append(steps, new(domain.LoginStep)), nil
} else {
// if no user was specified, no prompt or select_account was provided,
// then check the active user sessions (of the user agent)
users, err := repo.usersForUserSelection(request)
if err != nil {
return nil, err
}
if domain.IsPrompt(request.Prompt, domain.PromptSelectAccount) {
steps = append(steps, &domain.SelectUserStep{Users: users})
}
if request.SelectedIDPConfigID != "" {
steps = append(steps, &domain.RedirectToExternalIDPStep{})
}
if len(request.Prompt) == 0 && len(users) == 0 {
steps = append(steps, new(domain.LoginStep))
}
// if no prompt was provided, but there are multiple user sessions, then the user must decide which to use
if len(request.Prompt) == 0 && len(users) > 1 {
steps = append(steps, &domain.SelectUserStep{Users: users})
}
if len(steps) > 0 {
return steps, nil
}
// a single user session was found, use that automatically
request.SetUserInfo(users[0].UserID, users[0].UserName, users[0].LoginName, users[0].DisplayName, users[0].AvatarKey, users[0].ResourceOwner)
}
return steps, nil
}
func checkExternalIDPsOfUser(ctx context.Context, idpUserLinksProvider idpUserLinksProvider, userID string) (*query.IDPUserLinks, error) { func checkExternalIDPsOfUser(ctx context.Context, idpUserLinksProvider idpUserLinksProvider, userID string) (*query.IDPUserLinks, error) {
userIDQuery, err := query.NewIDPUserLinksUserIDSearchQuery(userID) userIDQuery, err := query.NewIDPUserLinksUserIDSearchQuery(userID)
if err != nil { if err != nil {