mirror of
https://github.com/zitadel/zitadel.git
synced 2025-02-28 20:57:24 +00:00
fix: idp usage (#4571)
* fix: send email verification instead of init code for idp users * fix: select single idp of external only users * fix: use single idp on login
This commit is contained in:
parent
e7bc887a47
commit
3270a94291
@ -16,6 +16,7 @@ import (
|
||||
"google.golang.org/protobuf/types/known/durationpb"
|
||||
|
||||
"github.com/zitadel/logging"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/api/authz"
|
||||
action_grpc "github.com/zitadel/zitadel/internal/api/grpc/action"
|
||||
"github.com/zitadel/zitadel/internal/api/grpc/management"
|
||||
@ -306,6 +307,10 @@ func (s *Server) importData(ctx context.Context, orgs []*admin_pb.DataOrg) (*adm
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
emailCodeGenerator, err := s.query.InitEncryptionGenerator(ctx, domain.SecretGeneratorTypeVerifyEmailCode, s.userCodeAlg)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
phoneCodeGenerator, err := s.query.InitEncryptionGenerator(ctx, domain.SecretGeneratorTypeVerifyPhoneCode, s.userCodeAlg)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
@ -521,7 +526,7 @@ func (s *Server) importData(ctx context.Context, orgs []*admin_pb.DataOrg) (*adm
|
||||
logging.Debugf("import user: %s", user.GetUserId())
|
||||
human, passwordless := management.ImportHumanUserRequestToDomain(user.User)
|
||||
human.AggregateID = user.UserId
|
||||
_, _, err := s.command.ImportHuman(ctx, org.GetOrgId(), human, passwordless, initCodeGenerator, phoneCodeGenerator, passwordlessInitCode)
|
||||
_, _, err := s.command.ImportHuman(ctx, org.GetOrgId(), human, passwordless, initCodeGenerator, emailCodeGenerator, phoneCodeGenerator, passwordlessInitCode)
|
||||
if err != nil {
|
||||
errors = append(errors, &admin_pb.ImportDataError{Type: "human_user", Id: user.GetUserId(), Message: err.Error()})
|
||||
if isCtxTimeout(ctx) {
|
||||
|
@ -235,6 +235,10 @@ func (s *Server) ImportHumanUser(ctx context.Context, req *mgmt_pb.ImportHumanUs
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
emailCodeGenerator, err := s.query.InitEncryptionGenerator(ctx, domain.SecretGeneratorTypeVerifyEmailCode, s.userCodeAlg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
phoneCodeGenerator, err := s.query.InitEncryptionGenerator(ctx, domain.SecretGeneratorTypeVerifyPhoneCode, s.userCodeAlg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -243,7 +247,7 @@ func (s *Server) ImportHumanUser(ctx context.Context, req *mgmt_pb.ImportHumanUs
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
addedHuman, code, err := s.command.ImportHuman(ctx, authz.GetCtxData(ctx).OrgID, human, passwordless, initCodeGenerator, phoneCodeGenerator, passwordlessInitCode)
|
||||
addedHuman, code, err := s.command.ImportHuman(ctx, authz.GetCtxData(ctx).OrgID, human, passwordless, initCodeGenerator, phoneCodeGenerator, emailCodeGenerator, passwordlessInitCode)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -155,12 +155,17 @@ func (l *Login) registerExternalUser(w http.ResponseWriter, r *http.Request, aut
|
||||
l.renderRegisterOption(w, r, authReq, err)
|
||||
return
|
||||
}
|
||||
emailCodeGenerator, err := l.query.InitEncryptionGenerator(r.Context(), domain.SecretGeneratorTypeVerifyEmailCode, l.userCodeAlg)
|
||||
if err != nil {
|
||||
l.renderRegisterOption(w, r, authReq, err)
|
||||
return
|
||||
}
|
||||
phoneCodeGenerator, err := l.query.InitEncryptionGenerator(r.Context(), domain.SecretGeneratorTypeVerifyPhoneCode, l.userCodeAlg)
|
||||
if err != nil {
|
||||
l.renderRegisterOption(w, r, authReq, err)
|
||||
return
|
||||
}
|
||||
_, err = l.command.RegisterHuman(setContext(r.Context(), resourceOwner), resourceOwner, user, externalIDP, nil, initCodeGenerator, phoneCodeGenerator)
|
||||
_, err = l.command.RegisterHuman(setContext(r.Context(), resourceOwner), resourceOwner, user, externalIDP, nil, initCodeGenerator, emailCodeGenerator, phoneCodeGenerator)
|
||||
if err != nil {
|
||||
l.renderRegisterOption(w, r, authReq, err)
|
||||
return
|
||||
@ -230,12 +235,17 @@ func (l *Login) handleExternalRegisterCheck(w http.ResponseWriter, r *http.Reque
|
||||
l.renderRegisterOption(w, r, authReq, err)
|
||||
return
|
||||
}
|
||||
emailCodeGenerator, err := l.query.InitEncryptionGenerator(r.Context(), domain.SecretGeneratorTypeVerifyEmailCode, l.userCodeAlg)
|
||||
if err != nil {
|
||||
l.renderRegisterOption(w, r, authReq, err)
|
||||
return
|
||||
}
|
||||
phoneCodeGenerator, err := l.query.InitEncryptionGenerator(r.Context(), domain.SecretGeneratorTypeVerifyPhoneCode, l.userCodeAlg)
|
||||
if err != nil {
|
||||
l.renderRegisterOption(w, r, authReq, err)
|
||||
return
|
||||
}
|
||||
_, err = l.command.RegisterHuman(setContext(r.Context(), resourceOwner), resourceOwner, user, externalIDP, nil, initCodeGenerator, phoneCodeGenerator)
|
||||
_, err = l.command.RegisterHuman(setContext(r.Context(), resourceOwner), resourceOwner, user, externalIDP, nil, initCodeGenerator, emailCodeGenerator, phoneCodeGenerator)
|
||||
if err != nil {
|
||||
l.renderRegisterOption(w, r, authReq, err)
|
||||
return
|
||||
|
@ -95,6 +95,10 @@ func (l *Login) renderLogin(w http.ResponseWriter, r *http.Request, authReq *dom
|
||||
if err != nil {
|
||||
errID, errMessage = l.getErrorMessage(r, err)
|
||||
}
|
||||
if singleIDPAllowed(authReq) {
|
||||
l.handleIDP(w, r, authReq, authReq.AllowedExternalIDPs[0].IDPConfigID)
|
||||
return
|
||||
}
|
||||
data := l.getUserData(r, authReq, "Login", errID, errMessage)
|
||||
funcs := map[string]interface{}{
|
||||
"hasUsernamePasswordLogin": func() bool {
|
||||
@ -109,3 +113,7 @@ func (l *Login) renderLogin(w http.ResponseWriter, r *http.Request, authReq *dom
|
||||
}
|
||||
l.renderer.RenderTemplate(w, r, l.getTranslator(r.Context(), authReq), l.renderer.Templates[tmplLogin], data, funcs)
|
||||
}
|
||||
|
||||
func singleIDPAllowed(authReq *domain.AuthRequest) bool {
|
||||
return authReq != nil && authReq.LoginPolicy != nil && !authReq.LoginPolicy.AllowUsernamePassword && authReq.LoginPolicy.AllowExternalIDP && len(authReq.AllowedExternalIDPs) == 1
|
||||
}
|
||||
|
@ -73,12 +73,17 @@ func (l *Login) handleRegisterCheck(w http.ResponseWriter, r *http.Request) {
|
||||
l.renderRegister(w, r, authRequest, data, err)
|
||||
return
|
||||
}
|
||||
emailCodeGenerator, err := l.query.InitEncryptionGenerator(r.Context(), domain.SecretGeneratorTypeVerifyEmailCode, l.userCodeAlg)
|
||||
if err != nil {
|
||||
l.renderRegister(w, r, authRequest, data, err)
|
||||
return
|
||||
}
|
||||
phoneCodeGenerator, err := l.query.InitEncryptionGenerator(r.Context(), domain.SecretGeneratorTypeVerifyPhoneCode, l.userCodeAlg)
|
||||
if err != nil {
|
||||
l.renderRegister(w, r, authRequest, data, err)
|
||||
return
|
||||
}
|
||||
user, err := l.command.RegisterHuman(setContext(r.Context(), resourceOwner), resourceOwner, data.toHumanDomain(), nil, nil, initCodeGenerator, phoneCodeGenerator)
|
||||
user, err := l.command.RegisterHuman(setContext(r.Context(), resourceOwner), resourceOwner, data.toHumanDomain(), nil, nil, initCodeGenerator, emailCodeGenerator, phoneCodeGenerator)
|
||||
if err != nil {
|
||||
l.renderRegister(w, r, authRequest, data, err)
|
||||
return
|
||||
|
@ -48,6 +48,7 @@ type AuthRequestRepo struct {
|
||||
LockoutPolicyViewProvider lockoutPolicyViewProvider
|
||||
PrivacyPolicyProvider privacyPolicyProvider
|
||||
IDPProviderViewProvider idpProviderViewProvider
|
||||
IDPUserLinksProvider idpUserLinksProvider
|
||||
UserGrantProvider userGrantProvider
|
||||
ProjectProvider projectProvider
|
||||
ApplicationProvider applicationProvider
|
||||
@ -83,6 +84,10 @@ type idpProviderViewProvider interface {
|
||||
IDPProvidersByAggregateIDAndState(string, string, iam_model.IDPConfigState) ([]*iam_view_model.IDPProviderView, error)
|
||||
}
|
||||
|
||||
type idpUserLinksProvider interface {
|
||||
IDPUserLinks(ctx context.Context, queries *query.IDPUserLinksSearchQuery) (*query.IDPUserLinks, error)
|
||||
}
|
||||
|
||||
type userEventProvider interface {
|
||||
UserEventsByID(ctx context.Context, id string, sequence uint64) ([]*es_models.Event, error)
|
||||
}
|
||||
@ -469,11 +474,15 @@ func (repo *AuthRequestRepo) AutoRegisterExternalUser(ctx context.Context, regis
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
emailCodeGenerator, err := repo.Query.InitEncryptionGenerator(ctx, domain.SecretGeneratorTypeVerifyEmailCode, repo.UserCodeAlg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
phoneCodeGenerator, err := repo.Query.InitEncryptionGenerator(ctx, domain.SecretGeneratorTypeVerifyPhoneCode, repo.UserCodeAlg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
human, err := repo.Command.RegisterHuman(ctx, resourceOwner, registerUser, externalIDP, orgMemberRoles, initCodeGenerator, phoneCodeGenerator)
|
||||
human, err := repo.Command.RegisterHuman(ctx, resourceOwner, registerUser, externalIDP, orgMemberRoles, initCodeGenerator, emailCodeGenerator, phoneCodeGenerator)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -909,11 +918,18 @@ func (repo *AuthRequestRepo) nextSteps(ctx context.Context, request *domain.Auth
|
||||
}
|
||||
|
||||
isInternalLogin := request.SelectedIDPConfigID == "" && userSession.SelectedIDPConfigID == ""
|
||||
if !isInternalLogin && len(request.LinkingUsers) == 0 && !checkVerificationTimeMaxAge(userSession.ExternalLoginVerification, request.LoginPolicy.ExternalLoginCheckLifetime, request) {
|
||||
idps, err := checkExternalIDPsOfUser(ctx, repo.IDPUserLinksProvider, user.ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if (!isInternalLogin || len(idps.Links) > 0) && len(request.LinkingUsers) == 0 && !checkVerificationTimeMaxAge(userSession.ExternalLoginVerification, request.LoginPolicy.ExternalLoginCheckLifetime, request) {
|
||||
selectedIDPConfigID := request.SelectedIDPConfigID
|
||||
if selectedIDPConfigID == "" {
|
||||
selectedIDPConfigID = userSession.SelectedIDPConfigID
|
||||
}
|
||||
if selectedIDPConfigID == "" {
|
||||
selectedIDPConfigID = idps.Links[0].IDPID
|
||||
}
|
||||
return append(steps, &domain.ExternalLoginStep{SelectedIDPConfigID: selectedIDPConfigID}), nil
|
||||
}
|
||||
if isInternalLogin || (!isInternalLogin && len(request.LinkingUsers) > 0) {
|
||||
@ -976,6 +992,14 @@ func (repo *AuthRequestRepo) nextSteps(ctx context.Context, request *domain.Auth
|
||||
return append(steps, &domain.RedirectToCallbackStep{}), nil
|
||||
}
|
||||
|
||||
func checkExternalIDPsOfUser(ctx context.Context, idpUserLinksProvider idpUserLinksProvider, userID string) (*query.IDPUserLinks, error) {
|
||||
userIDQuery, err := query.NewIDPUserLinksUserIDSearchQuery(userID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return idpUserLinksProvider.IDPUserLinks(ctx, &query.IDPUserLinksSearchQuery{Queries: []query.SearchQuery{userIDQuery}})
|
||||
}
|
||||
|
||||
func (repo *AuthRequestRepo) usersForUserSelection(request *domain.AuthRequest) ([]domain.UserSelection, error) {
|
||||
userSessions, err := userSessionsByUserAgentID(repo.UserSessionViewProvider, request.AgentID, request.InstanceID)
|
||||
if err != nil {
|
||||
|
@ -234,6 +234,14 @@ func (m *mockApp) AppByOIDCClientID(ctx context.Context, id string) (*query.App,
|
||||
return nil, errors.ThrowNotFound(nil, "ERROR", "error")
|
||||
}
|
||||
|
||||
type mockIDPUserLinks struct {
|
||||
idps []*query.IDPUserLink
|
||||
}
|
||||
|
||||
func (m *mockIDPUserLinks) IDPUserLinks(ctx context.Context, queries *query.IDPUserLinksSearchQuery) (*query.IDPUserLinks, error) {
|
||||
return &query.IDPUserLinks{Links: m.idps}, nil
|
||||
}
|
||||
|
||||
func TestAuthRequestRepo_nextSteps(t *testing.T) {
|
||||
type fields struct {
|
||||
AuthRequests *cache.AuthRequestCache
|
||||
@ -247,6 +255,7 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
|
||||
applicationProvider applicationProvider
|
||||
loginPolicyProvider loginPolicyViewProvider
|
||||
lockoutPolicyProvider lockoutPolicyViewProvider
|
||||
idpUserLinksProvider idpUserLinksProvider
|
||||
}
|
||||
type args struct {
|
||||
request *domain.AuthRequest
|
||||
@ -498,6 +507,7 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
|
||||
ShowFailures: true,
|
||||
},
|
||||
},
|
||||
idpUserLinksProvider: &mockIDPUserLinks{},
|
||||
},
|
||||
args{&domain.AuthRequest{UserID: "UserID", LoginPolicy: &domain.LoginPolicy{}}, false},
|
||||
[]domain.NextStep{&domain.PasswordStep{}},
|
||||
@ -515,6 +525,7 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
|
||||
ShowFailures: true,
|
||||
},
|
||||
},
|
||||
idpUserLinksProvider: &mockIDPUserLinks{},
|
||||
},
|
||||
args{&domain.AuthRequest{UserID: "UserID", LoginPolicy: &domain.LoginPolicy{}}, false},
|
||||
nil,
|
||||
@ -535,6 +546,7 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
|
||||
ShowFailures: true,
|
||||
},
|
||||
},
|
||||
idpUserLinksProvider: &mockIDPUserLinks{},
|
||||
},
|
||||
args{&domain.AuthRequest{UserID: "UserID", LoginPolicy: &domain.LoginPolicy{}}, false},
|
||||
[]domain.NextStep{&domain.InitUserStep{
|
||||
@ -561,6 +573,7 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
|
||||
MultiFactorCheckLifetime: 10 * time.Hour,
|
||||
},
|
||||
},
|
||||
idpUserLinksProvider: &mockIDPUserLinks{},
|
||||
},
|
||||
args{&domain.AuthRequest{UserID: "UserID", LoginPolicy: &domain.LoginPolicy{PasswordlessType: domain.PasswordlessTypeAllowed}}, false},
|
||||
[]domain.NextStep{&domain.PasswordlessRegistrationPromptStep{}},
|
||||
@ -585,6 +598,7 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
|
||||
MultiFactorCheckLifetime: 10 * time.Hour,
|
||||
},
|
||||
},
|
||||
idpUserLinksProvider: &mockIDPUserLinks{},
|
||||
},
|
||||
args{&domain.AuthRequest{UserID: "UserID", LoginPolicy: &domain.LoginPolicy{PasswordlessType: domain.PasswordlessTypeAllowed}}, false},
|
||||
[]domain.NextStep{&domain.PasswordlessStep{}},
|
||||
@ -610,6 +624,7 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
|
||||
MultiFactorCheckLifetime: 10 * time.Hour,
|
||||
},
|
||||
},
|
||||
idpUserLinksProvider: &mockIDPUserLinks{},
|
||||
},
|
||||
args{&domain.AuthRequest{UserID: "UserID", LoginPolicy: &domain.LoginPolicy{PasswordlessType: domain.PasswordlessTypeAllowed}}, false},
|
||||
[]domain.NextStep{&domain.PasswordlessStep{PasswordSet: true}},
|
||||
@ -636,6 +651,7 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
|
||||
},
|
||||
},
|
||||
orgViewProvider: &mockViewOrg{State: domain.OrgStateActive},
|
||||
idpUserLinksProvider: &mockIDPUserLinks{},
|
||||
},
|
||||
args{&domain.AuthRequest{
|
||||
UserID: "UserID",
|
||||
@ -662,13 +678,14 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
|
||||
},
|
||||
},
|
||||
orgViewProvider: &mockViewOrg{State: domain.OrgStateActive},
|
||||
idpUserLinksProvider: &mockIDPUserLinks{},
|
||||
},
|
||||
args{&domain.AuthRequest{UserID: "UserID", LoginPolicy: &domain.LoginPolicy{}}, false},
|
||||
[]domain.NextStep{&domain.InitPasswordStep{}},
|
||||
nil,
|
||||
},
|
||||
{
|
||||
"external user (no external verification), external login step",
|
||||
"external user (idp selected, no external verification), external login step",
|
||||
fields{
|
||||
userSessionViewProvider: &mockViewUserSession{
|
||||
SecondFactorVerification: testNow.Add(-5 * time.Minute),
|
||||
@ -689,6 +706,7 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
|
||||
SecondFactorCheckLifetime: 18 * time.Hour,
|
||||
},
|
||||
},
|
||||
idpUserLinksProvider: &mockIDPUserLinks{},
|
||||
},
|
||||
args{&domain.AuthRequest{
|
||||
UserID: "UserID",
|
||||
@ -699,6 +717,40 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
|
||||
[]domain.NextStep{&domain.ExternalLoginStep{SelectedIDPConfigID: "IDPConfigID"}},
|
||||
nil,
|
||||
},
|
||||
{
|
||||
"external user (only idp available, no external verification), external login step",
|
||||
fields{
|
||||
userSessionViewProvider: &mockViewUserSession{
|
||||
SecondFactorVerification: testNow.Add(-5 * time.Minute),
|
||||
},
|
||||
userViewProvider: &mockViewUser{
|
||||
IsEmailVerified: true,
|
||||
MFAMaxSetUp: int32(domain.MFALevelSecondFactor),
|
||||
},
|
||||
userEventProvider: &mockEventUser{},
|
||||
lockoutPolicyProvider: &mockLockoutPolicy{
|
||||
policy: &query.LockoutPolicy{
|
||||
ShowFailures: true,
|
||||
},
|
||||
},
|
||||
orgViewProvider: &mockViewOrg{State: domain.OrgStateActive},
|
||||
loginPolicyProvider: &mockLoginPolicy{
|
||||
policy: &query.LoginPolicy{
|
||||
SecondFactorCheckLifetime: 18 * time.Hour,
|
||||
},
|
||||
},
|
||||
idpUserLinksProvider: &mockIDPUserLinks{
|
||||
idps: []*query.IDPUserLink{{IDPID: "IDPConfigID"}},
|
||||
},
|
||||
},
|
||||
args{&domain.AuthRequest{
|
||||
UserID: "UserID",
|
||||
LoginPolicy: &domain.LoginPolicy{
|
||||
SecondFactorCheckLifetime: 18 * time.Hour,
|
||||
}}, false},
|
||||
[]domain.NextStep{&domain.ExternalLoginStep{SelectedIDPConfigID: "IDPConfigID"}},
|
||||
nil,
|
||||
},
|
||||
{
|
||||
"external user (external verification set), callback",
|
||||
fields{
|
||||
@ -720,6 +772,7 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
|
||||
ShowFailures: true,
|
||||
},
|
||||
},
|
||||
idpUserLinksProvider: &mockIDPUserLinks{},
|
||||
},
|
||||
args{
|
||||
&domain.AuthRequest{
|
||||
@ -754,6 +807,7 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
|
||||
PasswordCheckLifetime: 10 * 24 * time.Hour,
|
||||
},
|
||||
},
|
||||
idpUserLinksProvider: &mockIDPUserLinks{},
|
||||
},
|
||||
args{&domain.AuthRequest{UserID: "UserID", LoginPolicy: &domain.LoginPolicy{}}, false},
|
||||
[]domain.NextStep{&domain.PasswordStep{}},
|
||||
@ -781,6 +835,7 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
|
||||
ShowFailures: true,
|
||||
},
|
||||
},
|
||||
idpUserLinksProvider: &mockIDPUserLinks{},
|
||||
},
|
||||
args{
|
||||
&domain.AuthRequest{
|
||||
@ -814,6 +869,7 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
|
||||
ShowFailures: true,
|
||||
},
|
||||
},
|
||||
idpUserLinksProvider: &mockIDPUserLinks{},
|
||||
},
|
||||
args{
|
||||
&domain.AuthRequest{
|
||||
@ -847,6 +903,7 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
|
||||
ShowFailures: true,
|
||||
},
|
||||
},
|
||||
idpUserLinksProvider: &mockIDPUserLinks{},
|
||||
},
|
||||
args{
|
||||
&domain.AuthRequest{
|
||||
@ -881,6 +938,7 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
|
||||
ShowFailures: true,
|
||||
},
|
||||
},
|
||||
idpUserLinksProvider: &mockIDPUserLinks{},
|
||||
},
|
||||
args{
|
||||
&domain.AuthRequest{
|
||||
@ -918,6 +976,7 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
|
||||
ShowFailures: true,
|
||||
},
|
||||
},
|
||||
idpUserLinksProvider: &mockIDPUserLinks{},
|
||||
},
|
||||
args{
|
||||
&domain.AuthRequest{
|
||||
@ -949,6 +1008,7 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
|
||||
ShowFailures: true,
|
||||
},
|
||||
},
|
||||
idpUserLinksProvider: &mockIDPUserLinks{},
|
||||
},
|
||||
args{&domain.AuthRequest{
|
||||
UserID: "UserID",
|
||||
@ -980,6 +1040,7 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
|
||||
ShowFailures: true,
|
||||
},
|
||||
},
|
||||
idpUserLinksProvider: &mockIDPUserLinks{},
|
||||
},
|
||||
args{&domain.AuthRequest{
|
||||
UserID: "UserID",
|
||||
@ -1014,6 +1075,7 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
|
||||
ShowFailures: true,
|
||||
},
|
||||
},
|
||||
idpUserLinksProvider: &mockIDPUserLinks{},
|
||||
},
|
||||
args{&domain.AuthRequest{
|
||||
UserID: "UserID",
|
||||
@ -1049,6 +1111,7 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
|
||||
ShowFailures: true,
|
||||
},
|
||||
},
|
||||
idpUserLinksProvider: &mockIDPUserLinks{},
|
||||
},
|
||||
args{&domain.AuthRequest{
|
||||
UserID: "UserID",
|
||||
@ -1085,6 +1148,7 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
|
||||
ShowFailures: true,
|
||||
},
|
||||
},
|
||||
idpUserLinksProvider: &mockIDPUserLinks{},
|
||||
},
|
||||
args{&domain.AuthRequest{
|
||||
UserID: "UserID",
|
||||
@ -1123,6 +1187,7 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
|
||||
ShowFailures: true,
|
||||
},
|
||||
},
|
||||
idpUserLinksProvider: &mockIDPUserLinks{},
|
||||
},
|
||||
args{&domain.AuthRequest{
|
||||
UserID: "UserID",
|
||||
@ -1162,6 +1227,7 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
|
||||
ShowFailures: true,
|
||||
},
|
||||
},
|
||||
idpUserLinksProvider: &mockIDPUserLinks{},
|
||||
},
|
||||
args{&domain.AuthRequest{
|
||||
UserID: "UserID",
|
||||
@ -1200,6 +1266,7 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
|
||||
ShowFailures: true,
|
||||
},
|
||||
},
|
||||
idpUserLinksProvider: &mockIDPUserLinks{},
|
||||
},
|
||||
args{&domain.AuthRequest{
|
||||
UserID: "UserID",
|
||||
@ -1239,6 +1306,7 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
|
||||
ShowFailures: true,
|
||||
},
|
||||
},
|
||||
idpUserLinksProvider: &mockIDPUserLinks{},
|
||||
},
|
||||
args{&domain.AuthRequest{
|
||||
UserID: "UserID",
|
||||
@ -1276,6 +1344,7 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
|
||||
},
|
||||
userEventProvider: &mockEventUser{},
|
||||
orgViewProvider: &mockViewOrg{State: domain.OrgStateActive},
|
||||
idpUserLinksProvider: &mockIDPUserLinks{},
|
||||
},
|
||||
args{
|
||||
&domain.AuthRequest{
|
||||
@ -1306,6 +1375,7 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
|
||||
ShowFailures: true,
|
||||
},
|
||||
},
|
||||
idpUserLinksProvider: &mockIDPUserLinks{},
|
||||
},
|
||||
args{
|
||||
&domain.AuthRequest{
|
||||
@ -1336,6 +1406,7 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
|
||||
ApplicationProvider: tt.fields.applicationProvider,
|
||||
LoginPolicyViewProvider: tt.fields.loginPolicyProvider,
|
||||
LockoutPolicyViewProvider: tt.fields.lockoutPolicyProvider,
|
||||
IDPUserLinksProvider: tt.fields.idpUserLinksProvider,
|
||||
}
|
||||
got, err := repo.nextSteps(context.Background(), tt.args.request, tt.args.checkLoggedIn)
|
||||
if (err != nil && tt.wantErr == nil) || (tt.wantErr != nil && !tt.wantErr(err)) {
|
||||
|
@ -80,6 +80,7 @@ func Start(conf Config, systemDefaults sd.SystemDefaults, command *command.Comma
|
||||
UserCommandProvider: command,
|
||||
UserEventProvider: &userRepo,
|
||||
IDPProviderViewProvider: view,
|
||||
IDPUserLinksProvider: queries,
|
||||
LockoutPolicyViewProvider: queries,
|
||||
LoginPolicyViewProvider: queries,
|
||||
UserGrantProvider: queryView,
|
||||
|
@ -272,7 +272,7 @@ func (h *AddHuman) ensureDisplayName() {
|
||||
h.DisplayName = h.FirstName + " " + h.LastName
|
||||
}
|
||||
|
||||
//shouldAddInitCode returns true for all added Humans which:
|
||||
// shouldAddInitCode returns true for all added Humans which:
|
||||
// - were not added from an external IDP
|
||||
// - and either:
|
||||
// - have no verified email
|
||||
@ -285,7 +285,7 @@ func (h *AddHuman) shouldAddInitCode() bool {
|
||||
h.Password == ""
|
||||
}
|
||||
|
||||
func (c *Commands) ImportHuman(ctx context.Context, orgID string, human *domain.Human, passwordless bool, initCodeGenerator crypto.Generator, phoneCodeGenerator crypto.Generator, passwordlessCodeGenerator crypto.Generator) (_ *domain.Human, passwordlessCode *domain.PasswordlessInitCode, err error) {
|
||||
func (c *Commands) ImportHuman(ctx context.Context, orgID string, human *domain.Human, passwordless bool, initCodeGenerator, emailCodeGenerator, phoneCodeGenerator, passwordlessCodeGenerator crypto.Generator) (_ *domain.Human, passwordlessCode *domain.PasswordlessInitCode, err error) {
|
||||
if orgID == "" {
|
||||
return nil, nil, errors.ThrowInvalidArgument(nil, "COMMAND-5N8fs", "Errors.ResourceOwnerMissing")
|
||||
}
|
||||
@ -309,7 +309,7 @@ func (c *Commands) ImportHuman(ctx context.Context, orgID string, human *domain.
|
||||
}
|
||||
}
|
||||
|
||||
events, addedHuman, addedCode, code, err := c.importHuman(ctx, orgID, human, passwordless, domainPolicy, pwPolicy, initCodeGenerator, phoneCodeGenerator, passwordlessCodeGenerator)
|
||||
events, addedHuman, addedCode, code, err := c.importHuman(ctx, orgID, human, passwordless, domainPolicy, pwPolicy, initCodeGenerator, emailCodeGenerator, phoneCodeGenerator, passwordlessCodeGenerator)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
@ -333,7 +333,7 @@ func (c *Commands) ImportHuman(ctx context.Context, orgID string, human *domain.
|
||||
return writeModelToHuman(addedHuman), passwordlessCode, nil
|
||||
}
|
||||
|
||||
func (c *Commands) RegisterHuman(ctx context.Context, orgID string, human *domain.Human, link *domain.UserIDPLink, orgMemberRoles []string, initCodeGenerator crypto.Generator, phoneCodeGenerator crypto.Generator) (*domain.Human, error) {
|
||||
func (c *Commands) RegisterHuman(ctx context.Context, orgID string, human *domain.Human, link *domain.UserIDPLink, orgMemberRoles []string, initCodeGenerator, emailCodeGenerator, phoneCodeGenerator crypto.Generator) (*domain.Human, error) {
|
||||
if orgID == "" {
|
||||
return nil, errors.ThrowInvalidArgument(nil, "COMMAND-GEdf2", "Errors.ResourceOwnerMissing")
|
||||
}
|
||||
@ -352,7 +352,7 @@ func (c *Commands) RegisterHuman(ctx context.Context, orgID string, human *domai
|
||||
if !loginPolicy.AllowRegister {
|
||||
return nil, errors.ThrowPreconditionFailed(err, "COMMAND-SAbr3", "Errors.Org.LoginPolicy.RegistrationNotAllowed")
|
||||
}
|
||||
userEvents, registeredHuman, err := c.registerHuman(ctx, orgID, human, link, domainPolicy, pwPolicy, initCodeGenerator, phoneCodeGenerator)
|
||||
userEvents, registeredHuman, err := c.registerHuman(ctx, orgID, human, link, domainPolicy, pwPolicy, initCodeGenerator, emailCodeGenerator, phoneCodeGenerator)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -386,21 +386,21 @@ func (c *Commands) RegisterHuman(ctx context.Context, orgID string, human *domai
|
||||
return writeModelToHuman(registeredHuman), nil
|
||||
}
|
||||
|
||||
func (c *Commands) addHuman(ctx context.Context, orgID string, human *domain.Human, domainPolicy *domain.DomainPolicy, pwPolicy *domain.PasswordComplexityPolicy, initCodeGenerator crypto.Generator, phoneCodeGenerator crypto.Generator) ([]eventstore.Command, *HumanWriteModel, error) {
|
||||
func (c *Commands) addHuman(ctx context.Context, orgID string, human *domain.Human, domainPolicy *domain.DomainPolicy, pwPolicy *domain.PasswordComplexityPolicy, initCodeGenerator, emailCodeGenerator, phoneCodeGenerator crypto.Generator) ([]eventstore.Command, *HumanWriteModel, error) {
|
||||
if orgID == "" || !human.IsValid() {
|
||||
return nil, nil, errors.ThrowInvalidArgument(nil, "COMMAND-67Ms8", "Errors.User.Invalid")
|
||||
}
|
||||
if human.Password != nil && human.Password.SecretString != "" {
|
||||
human.Password.ChangeRequired = true
|
||||
}
|
||||
return c.createHuman(ctx, orgID, human, nil, false, false, domainPolicy, pwPolicy, initCodeGenerator, phoneCodeGenerator)
|
||||
return c.createHuman(ctx, orgID, human, nil, false, false, domainPolicy, pwPolicy, initCodeGenerator, emailCodeGenerator, phoneCodeGenerator)
|
||||
}
|
||||
|
||||
func (c *Commands) importHuman(ctx context.Context, orgID string, human *domain.Human, passwordless bool, domainPolicy *domain.DomainPolicy, pwPolicy *domain.PasswordComplexityPolicy, initCodeGenerator crypto.Generator, phoneCodeGenerator crypto.Generator, passwordlessCodeGenerator crypto.Generator) (events []eventstore.Command, humanWriteModel *HumanWriteModel, passwordlessCodeWriteModel *HumanPasswordlessInitCodeWriteModel, code string, err error) {
|
||||
func (c *Commands) importHuman(ctx context.Context, orgID string, human *domain.Human, passwordless bool, domainPolicy *domain.DomainPolicy, pwPolicy *domain.PasswordComplexityPolicy, initCodeGenerator, emailCodeGenerator, phoneCodeGenerator, passwordlessCodeGenerator crypto.Generator) (events []eventstore.Command, humanWriteModel *HumanWriteModel, passwordlessCodeWriteModel *HumanPasswordlessInitCodeWriteModel, code string, err error) {
|
||||
if orgID == "" || !human.IsValid() {
|
||||
return nil, nil, nil, "", errors.ThrowInvalidArgument(nil, "COMMAND-00p2b", "Errors.User.Invalid")
|
||||
}
|
||||
events, humanWriteModel, err = c.createHuman(ctx, orgID, human, nil, false, passwordless, domainPolicy, pwPolicy, initCodeGenerator, phoneCodeGenerator)
|
||||
events, humanWriteModel, err = c.createHuman(ctx, orgID, human, nil, false, passwordless, domainPolicy, pwPolicy, initCodeGenerator, emailCodeGenerator, phoneCodeGenerator)
|
||||
if err != nil {
|
||||
return nil, nil, nil, "", err
|
||||
}
|
||||
@ -415,7 +415,7 @@ func (c *Commands) importHuman(ctx context.Context, orgID string, human *domain.
|
||||
return events, humanWriteModel, passwordlessCodeWriteModel, code, nil
|
||||
}
|
||||
|
||||
func (c *Commands) registerHuman(ctx context.Context, orgID string, human *domain.Human, link *domain.UserIDPLink, domainPolicy *domain.DomainPolicy, pwPolicy *domain.PasswordComplexityPolicy, initCodeGenerator crypto.Generator, phoneCodeGenerator crypto.Generator) ([]eventstore.Command, *HumanWriteModel, error) {
|
||||
func (c *Commands) registerHuman(ctx context.Context, orgID string, human *domain.Human, link *domain.UserIDPLink, domainPolicy *domain.DomainPolicy, pwPolicy *domain.PasswordComplexityPolicy, initCodeGenerator, emailCodeGenerator, phoneCodeGenerator crypto.Generator) ([]eventstore.Command, *HumanWriteModel, error) {
|
||||
if human == nil {
|
||||
return nil, nil, errors.ThrowInvalidArgument(nil, "COMMAND-JKefw", "Errors.User.Invalid")
|
||||
}
|
||||
@ -428,10 +428,10 @@ func (c *Commands) registerHuman(ctx context.Context, orgID string, human *domai
|
||||
if human.Password != nil && human.Password.SecretString != "" {
|
||||
human.Password.ChangeRequired = false
|
||||
}
|
||||
return c.createHuman(ctx, orgID, human, link, true, false, domainPolicy, pwPolicy, initCodeGenerator, phoneCodeGenerator)
|
||||
return c.createHuman(ctx, orgID, human, link, true, false, domainPolicy, pwPolicy, initCodeGenerator, emailCodeGenerator, phoneCodeGenerator)
|
||||
}
|
||||
|
||||
func (c *Commands) createHuman(ctx context.Context, orgID string, human *domain.Human, link *domain.UserIDPLink, selfregister, passwordless bool, domainPolicy *domain.DomainPolicy, pwPolicy *domain.PasswordComplexityPolicy, initCodeGenerator crypto.Generator, phoneCodeGenerator crypto.Generator) (events []eventstore.Command, addedHuman *HumanWriteModel, err error) {
|
||||
func (c *Commands) createHuman(ctx context.Context, orgID string, human *domain.Human, link *domain.UserIDPLink, selfregister, passwordless bool, domainPolicy *domain.DomainPolicy, pwPolicy *domain.PasswordComplexityPolicy, initCodeGenerator, emailCodeGenerator, phoneCodeGenerator crypto.Generator) (events []eventstore.Command, addedHuman *HumanWriteModel, err error) {
|
||||
if err := human.CheckDomainPolicy(domainPolicy); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
@ -490,10 +490,16 @@ func (c *Commands) createHuman(ctx context.Context, orgID string, human *domain.
|
||||
return nil, nil, err
|
||||
}
|
||||
events = append(events, user.NewHumanInitialCodeAddedEvent(ctx, userAgg, initCode.Code, initCode.Expiry))
|
||||
}
|
||||
|
||||
} else {
|
||||
if human.Email != nil && human.EmailAddress != "" && human.IsEmailVerified {
|
||||
events = append(events, user.NewHumanEmailVerifiedEvent(ctx, userAgg))
|
||||
} else {
|
||||
emailCode, err := domain.NewEmailCode(emailCodeGenerator)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
events = append(events, user.NewHumanEmailCodeAddedEvent(ctx, userAgg, emailCode.Code, emailCode.Expiry))
|
||||
}
|
||||
}
|
||||
|
||||
if human.Phone != nil && human.PhoneNumber != "" && !human.IsPhoneVerified {
|
||||
@ -527,7 +533,7 @@ func (c *Commands) HumanSkipMFAInit(ctx context.Context, userID, resourceowner s
|
||||
return err
|
||||
}
|
||||
|
||||
///TODO: adlerhurst maybe we can simplify createAddHumanEvent and createRegisterHumanEvent
|
||||
// TODO: adlerhurst maybe we can simplify createAddHumanEvent and createRegisterHumanEvent
|
||||
func createAddHumanEvent(ctx context.Context, aggregate *eventstore.Aggregate, human *domain.Human, userLoginMustBeDomain bool) *user.HumanAddedEvent {
|
||||
addEvent := user.NewHumanAddedEvent(
|
||||
ctx,
|
||||
|
@ -1460,7 +1460,7 @@ func TestCommandSide_ImportHuman(t *testing.T) {
|
||||
idGenerator: tt.fields.idGenerator,
|
||||
userPasswordAlg: tt.fields.userPasswordAlg,
|
||||
}
|
||||
gotHuman, gotCode, err := r.ImportHuman(tt.args.ctx, tt.args.orgID, tt.args.human, tt.args.passwordless, tt.args.secretGenerator, tt.args.secretGenerator, tt.args.secretGenerator)
|
||||
gotHuman, gotCode, err := r.ImportHuman(tt.args.ctx, tt.args.orgID, tt.args.human, tt.args.passwordless, tt.args.secretGenerator, tt.args.secretGenerator, tt.args.secretGenerator, tt.args.secretGenerator)
|
||||
if tt.res.err == nil {
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
@ -2487,7 +2487,7 @@ func TestCommandSide_RegisterHuman(t *testing.T) {
|
||||
idGenerator: tt.fields.idGenerator,
|
||||
userPasswordAlg: tt.fields.userPasswordAlg,
|
||||
}
|
||||
got, err := r.RegisterHuman(tt.args.ctx, tt.args.orgID, tt.args.human, tt.args.link, tt.args.orgMemberRoles, tt.args.secretGenerator, tt.args.secretGenerator)
|
||||
got, err := r.RegisterHuman(tt.args.ctx, tt.args.orgID, tt.args.human, tt.args.link, tt.args.orgMemberRoles, tt.args.secretGenerator, tt.args.secretGenerator, tt.args.secretGenerator)
|
||||
if tt.res.err == nil {
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
@ -89,7 +89,10 @@ func (u *Human) HashPasswordIfExisting(policy *PasswordComplexityPolicy, passwor
|
||||
}
|
||||
|
||||
func (u *Human) IsInitialState(passwordless, externalIDPs bool) bool {
|
||||
return u.Email == nil || !u.IsEmailVerified || !externalIDPs && !passwordless && (u.Password == nil || u.Password.SecretString == "") && (u.HashedPassword == nil || u.HashedPassword.SecretString == "")
|
||||
if externalIDPs {
|
||||
return false
|
||||
}
|
||||
return u.Email == nil || !u.IsEmailVerified || !passwordless && (u.Password == nil || u.Password.SecretString == "") && (u.HashedPassword == nil || u.HashedPassword.SecretString == "")
|
||||
}
|
||||
|
||||
func NewInitUserCode(generator crypto.Generator) (*InitUserCode, error) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user