mirror of
https://github.com/zitadel/zitadel.git
synced 2025-08-11 21:37:32 +00:00
feat: add default redirect uri and handling of unknown usernames (#3616)
* feat: add possibility to ignore username errors on first login screen * console changes * fix: handling of unknown usernames (#3445) * fix: handling of unknown usernames * fix: handle HideLoginNameSuffix on unknown users * feat: add default redirect uri on login policy (#3607) * feat: add default redirect uri on login policy * fix tests * feat: Console login policy default redirect (#3613) * console default redirect * placeholder * validate default redirect uri * allow empty default redirect uri Co-authored-by: Max Peintner <max@caos.ch> * remove wonrgly cherry picked migration Co-authored-by: Max Peintner <max@caos.ch>
This commit is contained in:
@@ -27,6 +27,8 @@ import (
|
||||
user_view_model "github.com/zitadel/zitadel/internal/user/repository/view/model"
|
||||
)
|
||||
|
||||
const unknownUserID = "UNKNOWN"
|
||||
|
||||
type AuthRequestRepo struct {
|
||||
Command *command.Commands
|
||||
Query *query.Queries
|
||||
@@ -284,7 +286,7 @@ func (repo *AuthRequestRepo) SelectUser(ctx context.Context, id, userID, userAge
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
user, err := activeUserByID(ctx, repo.UserViewProvider, repo.UserEventProvider, repo.OrgViewProvider, repo.LockoutPolicyViewProvider, userID)
|
||||
user, err := activeUserByID(ctx, repo.UserViewProvider, repo.UserEventProvider, repo.OrgViewProvider, repo.LockoutPolicyViewProvider, userID, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -304,13 +306,28 @@ func (repo *AuthRequestRepo) VerifyPassword(ctx context.Context, authReqID, user
|
||||
defer func() { span.EndWithError(err) }()
|
||||
request, err := repo.getAuthRequestEnsureUser(ctx, authReqID, userAgentID, userID)
|
||||
if err != nil {
|
||||
if isIgnoreUserNotFoundError(err, request) {
|
||||
return errors.ThrowInvalidArgument(nil, "EVENT-SDe2f", "Errors.User.UsernameOrPassword.Invalid")
|
||||
}
|
||||
return err
|
||||
}
|
||||
policy, err := repo.getLockoutPolicy(ctx, resourceOwner)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return repo.Command.HumanCheckPassword(ctx, resourceOwner, userID, password, request.WithCurrentInfo(info), lockoutPolicyToDomain(policy))
|
||||
err = repo.Command.HumanCheckPassword(ctx, resourceOwner, userID, password, request.WithCurrentInfo(info), lockoutPolicyToDomain(policy))
|
||||
if isIgnoreUserInvalidPasswordError(err, request) {
|
||||
return errors.ThrowInvalidArgument(nil, "EVENT-Jsf32", "Errors.User.UsernameOrPassword.Invalid")
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func isIgnoreUserNotFoundError(err error, request *domain.AuthRequest) bool {
|
||||
return request != nil && request.LoginPolicy != nil && request.LoginPolicy.IgnoreUnknownUsernames && errors.IsNotFound(err) && errors.Contains(err, "Errors.User.NotFound")
|
||||
}
|
||||
|
||||
func isIgnoreUserInvalidPasswordError(err error, request *domain.AuthRequest) bool {
|
||||
return request != nil && request.LoginPolicy != nil && request.LoginPolicy.IgnoreUnknownUsernames && errors.IsErrorInvalidArgument(err) && errors.Contains(err, "Errors.User.Password.Invalid")
|
||||
}
|
||||
|
||||
func lockoutPolicyToDomain(policy *query.LockoutPolicy) *domain.LockoutPolicy {
|
||||
@@ -499,9 +516,9 @@ func (repo *AuthRequestRepo) getAuthRequestEnsureUser(ctx context.Context, authR
|
||||
if request.UserID != userID {
|
||||
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-GBH32", "Errors.User.NotMatchingUserID")
|
||||
}
|
||||
_, err = activeUserByID(ctx, repo.UserViewProvider, repo.UserEventProvider, repo.OrgViewProvider, repo.LockoutPolicyViewProvider, request.UserID)
|
||||
_, err = activeUserByID(ctx, repo.UserViewProvider, repo.UserEventProvider, repo.OrgViewProvider, repo.LockoutPolicyViewProvider, request.UserID, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return request, err
|
||||
}
|
||||
return request, nil
|
||||
}
|
||||
@@ -613,8 +630,8 @@ func (repo *AuthRequestRepo) tryUsingOnlyUserSession(request *domain.AuthRequest
|
||||
|
||||
func (repo *AuthRequestRepo) checkLoginName(ctx context.Context, request *domain.AuthRequest, loginName string) (err error) {
|
||||
user := new(user_view_model.UserView)
|
||||
preferredLoginName := loginName
|
||||
if request.RequestedOrgID != "" {
|
||||
preferredLoginName := loginName
|
||||
if request.RequestedOrgID != "" {
|
||||
preferredLoginName += "@" + request.RequestedPrimaryDomain
|
||||
}
|
||||
@@ -628,6 +645,15 @@ func (repo *AuthRequestRepo) checkLoginName(ctx context.Context, request *domain
|
||||
}
|
||||
}
|
||||
}
|
||||
if request.LoginPolicy.IgnoreUnknownUsernames {
|
||||
if errors.IsNotFound(err) || (user != nil && user.State == int32(domain.UserStateInactive)) {
|
||||
if request.LabelPolicy.HideLoginNameSuffix {
|
||||
preferredLoginName = loginName
|
||||
}
|
||||
request.SetUserInfo(unknownUserID, preferredLoginName, preferredLoginName, preferredLoginName, "", request.RequestedOrgID)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -675,6 +701,7 @@ func queryLoginPolicyToDomain(policy *query.LoginPolicy) *domain.LoginPolicy {
|
||||
MultiFactors: policy.MultiFactors,
|
||||
PasswordlessType: policy.PasswordlessType,
|
||||
HidePasswordReset: policy.HidePasswordReset,
|
||||
IgnoreUnknownUsernames: policy.IgnoreUnknownUsernames,
|
||||
PasswordCheckLifetime: policy.PasswordCheckLifetime,
|
||||
ExternalLoginCheckLifetime: policy.ExternalLoginCheckLifetime,
|
||||
MFAInitSkipLifetime: policy.MFAInitSkipLifetime,
|
||||
@@ -703,7 +730,7 @@ func (repo *AuthRequestRepo) checkExternalUserLogin(ctx context.Context, request
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
user, err := activeUserByID(ctx, repo.UserViewProvider, repo.UserEventProvider, repo.OrgViewProvider, repo.LockoutPolicyViewProvider, externalIDP.UserID)
|
||||
user, err := activeUserByID(ctx, repo.UserViewProvider, repo.UserEventProvider, repo.OrgViewProvider, repo.LockoutPolicyViewProvider, externalIDP.UserID, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -749,11 +776,13 @@ func (repo *AuthRequestRepo) nextSteps(ctx context.Context, request *domain.Auth
|
||||
}
|
||||
return steps, nil
|
||||
}
|
||||
user, err := activeUserByID(ctx, repo.UserViewProvider, repo.UserEventProvider, repo.OrgViewProvider, repo.LockoutPolicyViewProvider, request.UserID)
|
||||
user, err := activeUserByID(ctx, repo.UserViewProvider, repo.UserEventProvider, repo.OrgViewProvider, repo.LockoutPolicyViewProvider, request.UserID, request.LoginPolicy.IgnoreUnknownUsernames)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
request.LoginName = user.PreferredLoginName
|
||||
if user.PreferredLoginName != "" {
|
||||
request.LoginName = user.PreferredLoginName
|
||||
}
|
||||
userSession, err := userSessionByIDs(ctx, repo.UserSessionViewProvider, repo.UserEventProvider, request.AgentID, user)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -1129,10 +1158,16 @@ func userSessionByIDs(ctx context.Context, provider userSessionViewProvider, eve
|
||||
return user_view_model.UserSessionToModel(&sessionCopy, provider.PrefixAvatarURL()), nil
|
||||
}
|
||||
|
||||
func activeUserByID(ctx context.Context, userViewProvider userViewProvider, userEventProvider userEventProvider, queries orgViewProvider, lockoutPolicyProvider lockoutPolicyViewProvider, userID string) (*user_model.UserView, error) {
|
||||
func activeUserByID(ctx context.Context, userViewProvider userViewProvider, userEventProvider userEventProvider, queries orgViewProvider, lockoutPolicyProvider lockoutPolicyViewProvider, userID string, ignoreUnknownUsernames bool) (user *user_model.UserView, err error) {
|
||||
// PLANNED: Check LockoutPolicy
|
||||
user, err := userByID(ctx, userViewProvider, userEventProvider, userID)
|
||||
user, err = userByID(ctx, userViewProvider, userEventProvider, userID)
|
||||
if err != nil {
|
||||
if ignoreUnknownUsernames && errors.IsNotFound(err) {
|
||||
return &user_model.UserView{
|
||||
ID: userID,
|
||||
HumanView: &user_model.HumanView{},
|
||||
}, nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
@@ -421,7 +421,7 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
|
||||
userViewProvider: &mockViewNoUser{},
|
||||
userEventProvider: &mockEventUser{},
|
||||
},
|
||||
args{&domain.AuthRequest{UserID: "UserID"}, false},
|
||||
args{&domain.AuthRequest{UserID: "UserID", LoginPolicy: &domain.LoginPolicy{}}, false},
|
||||
nil,
|
||||
errors.IsNotFound,
|
||||
},
|
||||
@@ -443,7 +443,7 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
args{&domain.AuthRequest{UserID: "UserID"}, false},
|
||||
args{&domain.AuthRequest{UserID: "UserID", LoginPolicy: &domain.LoginPolicy{}}, false},
|
||||
nil,
|
||||
errors.IsPreconditionFailed,
|
||||
},
|
||||
@@ -464,7 +464,7 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
args{&domain.AuthRequest{UserID: "UserID"}, false},
|
||||
args{&domain.AuthRequest{UserID: "UserID", LoginPolicy: &domain.LoginPolicy{}}, false},
|
||||
nil,
|
||||
errors.IsPreconditionFailed,
|
||||
},
|
||||
@@ -480,7 +480,7 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
args{&domain.AuthRequest{UserID: "UserID"}, false},
|
||||
args{&domain.AuthRequest{UserID: "UserID", LoginPolicy: &domain.LoginPolicy{}}, false},
|
||||
nil,
|
||||
errors.IsInternal,
|
||||
},
|
||||
@@ -496,7 +496,7 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
args{&domain.AuthRequest{UserID: "UserID"}, false},
|
||||
args{&domain.AuthRequest{UserID: "UserID", LoginPolicy: &domain.LoginPolicy{}}, false},
|
||||
nil,
|
||||
errors.IsPreconditionFailed,
|
||||
},
|
||||
@@ -532,7 +532,7 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
args{&domain.AuthRequest{UserID: "UserID"}, false},
|
||||
args{&domain.AuthRequest{UserID: "UserID", LoginPolicy: &domain.LoginPolicy{}}, false},
|
||||
nil,
|
||||
errors.IsInternal,
|
||||
},
|
||||
@@ -552,7 +552,7 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
args{&domain.AuthRequest{UserID: "UserID"}, false},
|
||||
args{&domain.AuthRequest{UserID: "UserID", LoginPolicy: &domain.LoginPolicy{}}, false},
|
||||
[]domain.NextStep{&domain.InitUserStep{
|
||||
PasswordSet: true,
|
||||
}},
|
||||
|
Reference in New Issue
Block a user