mirror of
https://github.com/zitadel/zitadel.git
synced 2024-12-12 02:54:20 +00:00
feat(login): reuse existing session if no prompt is provided and only single session exists (#6272)
* feat: reuse existing session if no prompt is provided and only single session exists * fix tests
This commit is contained in:
parent
782f7ad647
commit
dd480f8a8d
@ -921,11 +921,15 @@ func (repo *AuthRequestRepo) nextSteps(ctx context.Context, request *domain.Auth
|
|||||||
steps = append(steps, new(domain.ExternalNotFoundOptionStep))
|
steps = append(steps, new(domain.ExternalNotFoundOptionStep))
|
||||||
return steps, nil
|
return steps, nil
|
||||||
}
|
}
|
||||||
steps = append(steps, new(domain.LoginStep))
|
|
||||||
if domain.IsPrompt(request.Prompt, domain.PromptCreate) {
|
if domain.IsPrompt(request.Prompt, domain.PromptCreate) {
|
||||||
return append(steps, &domain.RegistrationStep{}), nil
|
return append(steps, &domain.RegistrationStep{}), nil
|
||||||
}
|
}
|
||||||
if len(request.Prompt) == 0 || domain.IsPrompt(request.Prompt, domain.PromptSelectAccount) {
|
// 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)
|
users, err := repo.usersForUserSelection(request)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -936,11 +940,19 @@ func (repo *AuthRequestRepo) nextSteps(ctx context.Context, request *domain.Auth
|
|||||||
if request.SelectedIDPConfigID != "" {
|
if request.SelectedIDPConfigID != "" {
|
||||||
steps = append(steps, &domain.RedirectToExternalIDPStep{})
|
steps = append(steps, &domain.RedirectToExternalIDPStep{})
|
||||||
}
|
}
|
||||||
if len(request.Prompt) == 0 && len(users) > 0 {
|
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})
|
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
|
||||||
}
|
}
|
||||||
return steps, nil
|
|
||||||
}
|
}
|
||||||
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)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -296,6 +296,28 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
|
|||||||
[]domain.NextStep{&domain.RedirectToCallbackStep{}},
|
[]domain.NextStep{&domain.RedirectToCallbackStep{}},
|
||||||
nil,
|
nil,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"user not set prompt create, registration step",
|
||||||
|
fields{
|
||||||
|
userSessionViewProvider: &mockViewNoUserSession{},
|
||||||
|
},
|
||||||
|
args{&domain.AuthRequest{
|
||||||
|
Prompt: []domain.Prompt{domain.PromptCreate},
|
||||||
|
}, false},
|
||||||
|
[]domain.NextStep{&domain.RegistrationStep{}},
|
||||||
|
nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"user not set, prompts other than select account, create step",
|
||||||
|
fields{
|
||||||
|
userSessionViewProvider: &mockViewNoUserSession{},
|
||||||
|
},
|
||||||
|
args{&domain.AuthRequest{
|
||||||
|
Prompt: []domain.Prompt{domain.PromptLogin, domain.PromptConsent},
|
||||||
|
}, false},
|
||||||
|
[]domain.NextStep{&domain.LoginStep{}},
|
||||||
|
nil,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"user not set no active session, login step",
|
"user not set no active session, login step",
|
||||||
fields{
|
fields{
|
||||||
@ -333,7 +355,7 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
|
|||||||
errors.IsInternal,
|
errors.IsInternal,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"user not set, prompt select account, login and select account steps",
|
"user not set, prompt select account, select account step",
|
||||||
fields{
|
fields{
|
||||||
userSessionViewProvider: &mockViewUserSession{
|
userSessionViewProvider: &mockViewUserSession{
|
||||||
Users: []mockUser{
|
Users: []mockUser{
|
||||||
@ -353,7 +375,6 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
|
|||||||
},
|
},
|
||||||
args{&domain.AuthRequest{Prompt: []domain.Prompt{domain.PromptSelectAccount}}, false},
|
args{&domain.AuthRequest{Prompt: []domain.Prompt{domain.PromptSelectAccount}}, false},
|
||||||
[]domain.NextStep{
|
[]domain.NextStep{
|
||||||
&domain.LoginStep{},
|
|
||||||
&domain.SelectUserStep{
|
&domain.SelectUserStep{
|
||||||
Users: []domain.UserSelection{
|
Users: []domain.UserSelection{
|
||||||
{
|
{
|
||||||
@ -373,7 +394,7 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
|
|||||||
nil,
|
nil,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"user not set, primary domain set, prompt select account, login and select account steps",
|
"user not set, primary domain set, prompt select account, select account step",
|
||||||
fields{
|
fields{
|
||||||
userSessionViewProvider: &mockViewUserSession{
|
userSessionViewProvider: &mockViewUserSession{
|
||||||
Users: []mockUser{
|
Users: []mockUser{
|
||||||
@ -393,7 +414,6 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
|
|||||||
},
|
},
|
||||||
args{&domain.AuthRequest{Prompt: []domain.Prompt{domain.PromptSelectAccount}, RequestedOrgID: "orgID1"}, false},
|
args{&domain.AuthRequest{Prompt: []domain.Prompt{domain.PromptSelectAccount}, RequestedOrgID: "orgID1"}, false},
|
||||||
[]domain.NextStep{
|
[]domain.NextStep{
|
||||||
&domain.LoginStep{},
|
|
||||||
&domain.SelectUserStep{
|
&domain.SelectUserStep{
|
||||||
Users: []domain.UserSelection{
|
Users: []domain.UserSelection{
|
||||||
{
|
{
|
||||||
@ -407,7 +427,7 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
|
|||||||
nil,
|
nil,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"user not set, prompt select account, no active session, login and select account steps",
|
"user not set, prompt select account, no active session, select account step",
|
||||||
fields{
|
fields{
|
||||||
userSessionViewProvider: &mockViewUserSession{
|
userSessionViewProvider: &mockViewUserSession{
|
||||||
Users: nil,
|
Users: nil,
|
||||||
@ -416,12 +436,113 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
|
|||||||
},
|
},
|
||||||
args{&domain.AuthRequest{Prompt: []domain.Prompt{domain.PromptSelectAccount}}, false},
|
args{&domain.AuthRequest{Prompt: []domain.Prompt{domain.PromptSelectAccount}}, false},
|
||||||
[]domain.NextStep{
|
[]domain.NextStep{
|
||||||
&domain.LoginStep{},
|
|
||||||
&domain.SelectUserStep{
|
&domain.SelectUserStep{
|
||||||
Users: []domain.UserSelection{},
|
Users: []domain.UserSelection{},
|
||||||
}},
|
}},
|
||||||
nil,
|
nil,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"user not set single active session, callback step",
|
||||||
|
fields{
|
||||||
|
userSessionViewProvider: &mockViewUserSession{
|
||||||
|
PasswordVerification: time.Now().Add(-5 * time.Minute),
|
||||||
|
SecondFactorVerification: time.Now().Add(-5 * time.Minute),
|
||||||
|
Users: []mockUser{
|
||||||
|
{
|
||||||
|
"id1",
|
||||||
|
"loginname1",
|
||||||
|
"orgID1",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
userViewProvider: &mockViewUser{
|
||||||
|
PasswordSet: true,
|
||||||
|
IsEmailVerified: true,
|
||||||
|
MFAMaxSetUp: int32(domain.MFALevelSecondFactor),
|
||||||
|
},
|
||||||
|
userEventProvider: &mockEventUser{},
|
||||||
|
orgViewProvider: &mockViewOrg{State: domain.OrgStateActive},
|
||||||
|
userGrantProvider: &mockUserGrants{},
|
||||||
|
projectProvider: &mockProject{},
|
||||||
|
applicationProvider: &mockApp{app: &query.App{OIDCConfig: &query.OIDCApp{AppType: domain.OIDCApplicationTypeWeb}}},
|
||||||
|
lockoutPolicyProvider: &mockLockoutPolicy{
|
||||||
|
policy: &query.LockoutPolicy{
|
||||||
|
ShowFailures: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
idpUserLinksProvider: &mockIDPUserLinks{},
|
||||||
|
},
|
||||||
|
args{&domain.AuthRequest{
|
||||||
|
Request: &domain.AuthRequestOIDC{},
|
||||||
|
LoginPolicy: &domain.LoginPolicy{
|
||||||
|
SecondFactors: []domain.SecondFactorType{domain.SecondFactorTypeTOTP},
|
||||||
|
PasswordCheckLifetime: 10 * 24 * time.Hour,
|
||||||
|
SecondFactorCheckLifetime: 18 * time.Hour,
|
||||||
|
},
|
||||||
|
}, false},
|
||||||
|
[]domain.NextStep{&domain.RedirectToCallbackStep{}},
|
||||||
|
nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"user not set multiple active sessions, select account step",
|
||||||
|
fields{
|
||||||
|
userSessionViewProvider: &mockViewUserSession{
|
||||||
|
Users: []mockUser{
|
||||||
|
{
|
||||||
|
"id1",
|
||||||
|
"loginname1",
|
||||||
|
"orgID1",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id2",
|
||||||
|
"loginname2",
|
||||||
|
"orgID2",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
userViewProvider: &mockViewUser{
|
||||||
|
PasswordSet: true,
|
||||||
|
IsEmailVerified: true,
|
||||||
|
MFAMaxSetUp: int32(domain.MFALevelSecondFactor),
|
||||||
|
},
|
||||||
|
userEventProvider: &mockEventUser{},
|
||||||
|
orgViewProvider: &mockViewOrg{State: domain.OrgStateActive},
|
||||||
|
userGrantProvider: &mockUserGrants{},
|
||||||
|
projectProvider: &mockProject{},
|
||||||
|
applicationProvider: &mockApp{app: &query.App{OIDCConfig: &query.OIDCApp{AppType: domain.OIDCApplicationTypeWeb}}},
|
||||||
|
lockoutPolicyProvider: &mockLockoutPolicy{
|
||||||
|
policy: &query.LockoutPolicy{
|
||||||
|
ShowFailures: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
idpUserLinksProvider: &mockIDPUserLinks{},
|
||||||
|
},
|
||||||
|
args{&domain.AuthRequest{
|
||||||
|
Request: &domain.AuthRequestOIDC{},
|
||||||
|
LoginPolicy: &domain.LoginPolicy{
|
||||||
|
SecondFactors: []domain.SecondFactorType{domain.SecondFactorTypeTOTP},
|
||||||
|
PasswordCheckLifetime: 10 * 24 * time.Hour,
|
||||||
|
SecondFactorCheckLifetime: 18 * time.Hour,
|
||||||
|
},
|
||||||
|
}, false},
|
||||||
|
[]domain.NextStep{&domain.SelectUserStep{
|
||||||
|
Users: []domain.UserSelection{
|
||||||
|
{
|
||||||
|
UserID: "id1",
|
||||||
|
LoginName: "loginname1",
|
||||||
|
SelectionPossible: true,
|
||||||
|
ResourceOwner: "orgID1",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
UserID: "id2",
|
||||||
|
LoginName: "loginname2",
|
||||||
|
SelectionPossible: true,
|
||||||
|
ResourceOwner: "orgID2",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}},
|
||||||
|
nil,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"user not found, not found error",
|
"user not found, not found error",
|
||||||
fields{
|
fields{
|
||||||
|
Loading…
Reference in New Issue
Block a user