diff --git a/console/src/app/modules/policies/login-policy/login-policy.component.html b/console/src/app/modules/policies/login-policy/login-policy.component.html
index 003f6464f..82a006483 100644
--- a/console/src/app/modules/policies/login-policy/login-policy.component.html
+++ b/console/src/app/modules/policies/login-policy/login-policy.component.html
@@ -329,6 +329,50 @@
+
+
+ {{ 'POLICY.DATA.DISABLELOGINWITHEMAIL' | translate }}
+
+
+
+
+
+ {{ 'POLICY.DATA.DISABLELOGINWITHPHONE' | translate }}
+
+
+
{{ 'POLICY.DATA.DEFAULTREDIRECTURI' | translate }}
diff --git a/console/src/app/modules/policies/login-policy/login-policy.component.ts b/console/src/app/modules/policies/login-policy/login-policy.component.ts
index 40ff25d8d..dfea83083 100644
--- a/console/src/app/modules/policies/login-policy/login-policy.component.ts
+++ b/console/src/app/modules/policies/login-policy/login-policy.component.ts
@@ -155,6 +155,8 @@ export class LoginPolicyComponent implements OnInit {
mgmtreq.setHidePasswordReset(this.loginData.hidePasswordReset);
mgmtreq.setMultiFactorsList(this.loginData.multiFactorsList);
mgmtreq.setSecondFactorsList(this.loginData.secondFactorsList);
+ mgmtreq.setDisableLoginWithEmail(this.loginData.disableLoginWithEmail);
+ mgmtreq.setDisableLoginWithPhone(this.loginData.disableLoginWithPhone);
const pcl = new Duration().setSeconds((this.passwordCheckLifetime?.value ?? 240) * 60 * 60);
mgmtreq.setPasswordCheckLifetime(pcl);
@@ -184,6 +186,8 @@ export class LoginPolicyComponent implements OnInit {
mgmtreq.setForceMfa(this.loginData.forceMfa);
mgmtreq.setPasswordlessType(this.loginData.passwordlessType);
mgmtreq.setHidePasswordReset(this.loginData.hidePasswordReset);
+ mgmtreq.setDisableLoginWithEmail(this.loginData.disableLoginWithEmail);
+ mgmtreq.setDisableLoginWithPhone(this.loginData.disableLoginWithPhone);
const pcl = new Duration().setSeconds((this.passwordCheckLifetime?.value ?? 240) * 60 * 60);
mgmtreq.setPasswordCheckLifetime(pcl);
@@ -214,6 +218,8 @@ export class LoginPolicyComponent implements OnInit {
adminreq.setForceMfa(this.loginData.forceMfa);
adminreq.setPasswordlessType(this.loginData.passwordlessType);
adminreq.setHidePasswordReset(this.loginData.hidePasswordReset);
+ adminreq.setDisableLoginWithEmail(this.loginData.disableLoginWithEmail);
+ adminreq.setDisableLoginWithPhone(this.loginData.disableLoginWithPhone);
const admin_pcl = new Duration().setSeconds((this.passwordCheckLifetime?.value ?? 240) * 60 * 60);
adminreq.setPasswordCheckLifetime(admin_pcl);
diff --git a/console/src/assets/i18n/de.json b/console/src/assets/i18n/de.json
index 0264e1829..abfff4ca0 100644
--- a/console/src/assets/i18n/de.json
+++ b/console/src/assets/i18n/de.json
@@ -1173,6 +1173,8 @@
"IGNOREUNKNOWNUSERNAMES_DESC": "Ist die Option gewählt, wird der Passwort Schritt im Login auch angezeigt wenn der User nicht gefunden wurde. Dem Benutzer wird auf bei der Passwortprüfung nicht angezeigt ob der Username oder das Passwort falsch war.",
"ALLOWDOMAINDISCOVERY": "Domänenentdeckung erlauben",
"ALLOWDOMAINDISCOVERY_DESC": "Ist die Option gewählt, wird die Endung (@domain.com) eines unbekannten Benutzernamens im Login mit den Organisationsdomänen verglichen. Bei Übereinstimmung wird der Benutzer auf die Registrierung dieser Organisation weitergeleitet.",
+ "DISABLELOGINWITHEMAIL": "Login mittels E-Mailadresse deaktivieren",
+ "DISABLELOGINWITHPHONE": "Login mittels Telefonnummer deaktivieren",
"DEFAULTREDIRECTURI": "Default Redirect URI",
"DEFAULTREDIRECTURI_DESC": "Definiert, wohin der Benutzer umgeleitet wird, wenn die Anmeldung ohne App-Kontext gestartet wurde (z. B. von Mail)",
"ERRORMSGPOPUP": "Fehler als Dialog Fenster",
diff --git a/console/src/assets/i18n/en.json b/console/src/assets/i18n/en.json
index 5c54b2f02..bf4984571 100644
--- a/console/src/assets/i18n/en.json
+++ b/console/src/assets/i18n/en.json
@@ -1173,6 +1173,8 @@
"IGNOREUNKNOWNUSERNAMES_DESC": "If the option is selected, the password screen will be displayed in the login process even if the user was not found. The error on the password check will not disclose if the username or password was wrong.",
"ALLOWDOMAINDISCOVERY": "Domain discovery allowed",
"ALLOWDOMAINDISCOVERY_DESC": "If the option is selected, the suffix (@domain.com) of an unknown username input on the login screen will be matched against the organization domains and will redirect to the registration of that organisation on success.",
+ "DISABLELOGINWITHEMAIL": "Disable login with email address",
+ "DISABLELOGINWITHPHONE": "Disable login with phone number",
"DEFAULTREDIRECTURI": "Default Redirect URI",
"DEFAULTREDIRECTURI_DESC": "Defines where the user will be redirected to if the login has started without an app context (e.g. from mail)",
"ERRORMSGPOPUP": "Show Error in Dialog",
diff --git a/console/src/assets/i18n/fr.json b/console/src/assets/i18n/fr.json
index de409e950..c37ddf174 100644
--- a/console/src/assets/i18n/fr.json
+++ b/console/src/assets/i18n/fr.json
@@ -1173,6 +1173,8 @@
"IGNOREUNKNOWNUSERNAMES_DESC": "Si l'option est sélectionnée, l'écran du mot de passe sera affiché dans le processus de connexion même si l'utilisateur n'a pas été trouvé. L'erreur sur la vérification du mot de passe ne révélera pas si le nom d'utilisateur ou le mot de passe était erroné.",
"ALLOWDOMAINDISCOVERY": "Découverte du domaine autorisée",
"ALLOWDOMAINDISCOVERY_DESC": "Si l'option est sélectionnée, le suffixe (@domain.com) d'un nom d'utilisateur inconnu saisi sur l'écran de connexion sera comparé aux domaines organisation et redirigera vers l'enregistrement de cette organisation en cas de succès.",
+ "DISABLELOGINWITHEMAIL": "Désactiver la connexion avec l'adresse e-mail",
+ "DISABLELOGINWITHPHONE": "Désactiver la connexion avec le numéro de téléphone",
"DEFAULTREDIRECTURI": "URI de redirection par défaut",
"DEFAULTREDIRECTURI_DESC": "Définit l'endroit où l'utilisateur sera redirigé si la connexion a commencé sans contexte d'application (par exemple, à partir du courrier électronique).",
"ERRORMSGPOPUP": "Afficher l'erreur dans la boîte de dialogue",
diff --git a/console/src/assets/i18n/it.json b/console/src/assets/i18n/it.json
index 779325339..fd5409f7c 100644
--- a/console/src/assets/i18n/it.json
+++ b/console/src/assets/i18n/it.json
@@ -1173,6 +1173,8 @@
"IGNOREUNKNOWNUSERNAMES_DESC": "Se l'opzione \u00e8 selezionata, l'inserimento della password viene mostrato anche se nessun utente è stato trovato. Nota che dopo il controllo della password, non viene mostrato se il nome utente o la password erano errati.",
"ALLOWDOMAINDISCOVERY": "Scoperta del dominio consentita",
"ALLOWDOMAINDISCOVERY_DESC": "Se l'opzione è selezionata, il suffisso (@domain.com) di un nome utente sconosciuto inserito nel login verrà confrontato con i domini organizzazione e, in caso di successo, verrà reindirizzato alla registrazione di tale organizzazione",
+ "DISABLELOGINWITHEMAIL": "Disabilita il login con l'indirizzo e-mail",
+ "DISABLELOGINWITHPHONE": "Disabilita l'accesso con il numero di telefono",
"DEFAULTREDIRECTURI": "Default Redirect URI",
"DEFAULTREDIRECTURI_DESC": "Definisce dove verrà reindirizzato l'utente se l'accesso è stato avviato senza un contesto dell'app (ad es. dall' email)",
"ERRORMSGPOPUP": "Mostra l'errore nella finestra di dialogo",
diff --git a/console/src/assets/i18n/zh.json b/console/src/assets/i18n/zh.json
index 9e67158b0..fa86d9497 100644
--- a/console/src/assets/i18n/zh.json
+++ b/console/src/assets/i18n/zh.json
@@ -1172,6 +1172,8 @@
"IGNOREUNKNOWNUSERNAMES_DESC": "如果选择该选项,即使未找到用户,登录过程中也会显示密码屏幕。如果用户名或密码错误,密码检查的错误不会透露。",
"ALLOWDOMAINDISCOVERY": "允许域名发现",
"ALLOWDOMAINDISCOVERY_DESC": "如果选择该选项,在登录屏幕上输入的未知用户名的后缀(@domain.com)将与组织的域名进行匹配,成功后将重定向到组织的注册。",
+ "DISABLELOGINWITHEMAIL": "禁止用电子邮件地址登录",
+ "DISABLELOGINWITHPHONE": "禁止用电话号码登录",
"DEFAULTREDIRECTURI": "默认重定向 URI",
"DEFAULTREDIRECTURI_DESC": "定义如果在没有应用程序上下文的情况下开始登录(例如来自邮件),用户将被重定向到哪里。",
"ERRORMSGPOPUP": "在对话框中显示错误",
diff --git a/docs/docs/apis/proto/admin.md b/docs/docs/apis/proto/admin.md
index 2c5c57d82..72c0ab5f8 100644
--- a/docs/docs/apis/proto/admin.md
+++ b/docs/docs/apis/proto/admin.md
@@ -4360,6 +4360,8 @@ this is en empty request
| second_factor_check_lifetime | google.protobuf.Duration | - | |
| multi_factor_check_lifetime | google.protobuf.Duration | - | |
| allow_domain_discovery | bool | If set to true, the suffix (@domain.com) of an unknown username input on the login screen will be matched against the org domains and will redirect to the registration of that organisation on success. | |
+| disable_login_with_email | bool | - | |
+| disable_login_with_phone | bool | - | |
diff --git a/docs/docs/apis/proto/management.md b/docs/docs/apis/proto/management.md
index e267eceb8..43eebe443 100644
--- a/docs/docs/apis/proto/management.md
+++ b/docs/docs/apis/proto/management.md
@@ -3184,6 +3184,8 @@ This is an empty request
| multi_factors | repeated zitadel.policy.v1.MultiFactorType | - | |
| idps | repeated AddCustomLoginPolicyRequest.IDP | - | |
| allow_domain_discovery | bool | If set to true, the suffix (@domain.com) of an unknown username input on the login screen will be matched against the org domains and will redirect to the registration of that organisation on success. | |
+| disable_login_with_email | bool | - | |
+| disable_login_with_phone | bool | - | |
@@ -8171,6 +8173,8 @@ This is an empty request
| second_factor_check_lifetime | google.protobuf.Duration | - | |
| multi_factor_check_lifetime | google.protobuf.Duration | - | |
| allow_domain_discovery | bool | If set to true, the suffix (@domain.com) of an unknown username input on the login screen will be matched against the org domains and will redirect to the registration of that organisation on success. | |
+| disable_login_with_email | bool | - | |
+| disable_login_with_phone | bool | - | |
diff --git a/docs/docs/apis/proto/policy.md b/docs/docs/apis/proto/policy.md
index 28d0a5312..8af9ffbda 100644
--- a/docs/docs/apis/proto/policy.md
+++ b/docs/docs/apis/proto/policy.md
@@ -89,6 +89,8 @@ title: zitadel/policy.proto
| multi_factors | repeated MultiFactorType | - | |
| idps | repeated zitadel.idp.v1.IDPLoginPolicyLink | - | |
| allow_domain_discovery | bool | If set to true, the suffix (@domain.com) of an unknown username input on the login screen will be matched against the org domains and will redirect to the registration of that organisation on success. | |
+| disable_login_with_email | bool | - | |
+| disable_login_with_phone | bool | - | |
diff --git a/internal/api/grpc/admin/import.go b/internal/api/grpc/admin/import.go
index 60b29619d..42b3d25a5 100644
--- a/internal/api/grpc/admin/import.go
+++ b/internal/api/grpc/admin/import.go
@@ -442,7 +442,7 @@ func (s *Server) importData(ctx context.Context, orgs []*admin_pb.DataOrg) (*adm
}
}
if org.LoginPolicy != nil {
- _, err = s.command.AddLoginPolicy(ctx, org.GetOrgId(), management.AddLoginPolicyToDomain(org.GetLoginPolicy()))
+ _, err = s.command.AddLoginPolicy(ctx, org.GetOrgId(), management.AddLoginPolicyToCommand(org.GetLoginPolicy()))
if err != nil {
errors = append(errors, &admin_pb.ImportDataError{Type: "login_policy", Id: org.GetOrgId(), Message: err.Error()})
}
diff --git a/internal/api/grpc/admin/login_policy.go b/internal/api/grpc/admin/login_policy.go
index 4a8c2cbd6..aa39ac736 100644
--- a/internal/api/grpc/admin/login_policy.go
+++ b/internal/api/grpc/admin/login_policy.go
@@ -22,14 +22,14 @@ func (s *Server) GetLoginPolicy(ctx context.Context, _ *admin_pb.GetLoginPolicyR
}
func (s *Server) UpdateLoginPolicy(ctx context.Context, p *admin_pb.UpdateLoginPolicyRequest) (*admin_pb.UpdateLoginPolicyResponse, error) {
- policy, err := s.command.ChangeDefaultLoginPolicy(ctx, updateLoginPolicyToDomain(p))
+ policy, err := s.command.ChangeDefaultLoginPolicy(ctx, updateLoginPolicyToCommand(p))
if err != nil {
return nil, err
}
return &admin_pb.UpdateLoginPolicyResponse{
Details: object.ChangeToDetailsPb(
policy.Sequence,
- policy.ChangeDate,
+ policy.EventDate,
policy.ResourceOwner,
),
}, nil
diff --git a/internal/api/grpc/admin/login_policy_converter.go b/internal/api/grpc/admin/login_policy_converter.go
index e6b97ebc4..24fee2d00 100644
--- a/internal/api/grpc/admin/login_policy_converter.go
+++ b/internal/api/grpc/admin/login_policy_converter.go
@@ -3,13 +3,13 @@ package admin
import (
"github.com/zitadel/zitadel/internal/api/grpc/object"
policy_grpc "github.com/zitadel/zitadel/internal/api/grpc/policy"
- "github.com/zitadel/zitadel/internal/domain"
+ "github.com/zitadel/zitadel/internal/command"
"github.com/zitadel/zitadel/internal/query"
admin_pb "github.com/zitadel/zitadel/pkg/grpc/admin"
)
-func updateLoginPolicyToDomain(p *admin_pb.UpdateLoginPolicyRequest) *domain.LoginPolicy {
- return &domain.LoginPolicy{
+func updateLoginPolicyToCommand(p *admin_pb.UpdateLoginPolicyRequest) *command.ChangeLoginPolicy {
+ return &command.ChangeLoginPolicy{
AllowUsernamePassword: p.AllowUsernamePassword,
AllowRegister: p.AllowRegister,
AllowExternalIDP: p.AllowExternalIdp,
@@ -18,6 +18,8 @@ func updateLoginPolicyToDomain(p *admin_pb.UpdateLoginPolicyRequest) *domain.Log
HidePasswordReset: p.HidePasswordReset,
IgnoreUnknownUsernames: p.IgnoreUnknownUsernames,
AllowDomainDiscovery: p.AllowDomainDiscovery,
+ DisableLoginWithEmail: p.DisableLoginWithEmail,
+ DisableLoginWithPhone: p.DisableLoginWithPhone,
DefaultRedirectURI: p.DefaultRedirectUri,
PasswordCheckLifetime: p.PasswordCheckLifetime.AsDuration(),
ExternalLoginCheckLifetime: p.ExternalLoginCheckLifetime.AsDuration(),
diff --git a/internal/api/grpc/management/policy_login.go b/internal/api/grpc/management/policy_login.go
index 78029c79a..ecfa3073b 100644
--- a/internal/api/grpc/management/policy_login.go
+++ b/internal/api/grpc/management/policy_login.go
@@ -30,28 +30,28 @@ func (s *Server) GetDefaultLoginPolicy(ctx context.Context, req *mgmt_pb.GetDefa
}
func (s *Server) AddCustomLoginPolicy(ctx context.Context, req *mgmt_pb.AddCustomLoginPolicyRequest) (*mgmt_pb.AddCustomLoginPolicyResponse, error) {
- policy, err := s.command.AddLoginPolicy(ctx, authz.GetCtxData(ctx).OrgID, AddLoginPolicyToDomain(req))
+ policy, err := s.command.AddLoginPolicy(ctx, authz.GetCtxData(ctx).OrgID, AddLoginPolicyToCommand(req))
if err != nil {
return nil, err
}
return &mgmt_pb.AddCustomLoginPolicyResponse{
Details: object.AddToDetailsPb(
policy.Sequence,
- policy.ChangeDate,
+ policy.EventDate,
policy.ResourceOwner,
),
}, nil
}
func (s *Server) UpdateCustomLoginPolicy(ctx context.Context, req *mgmt_pb.UpdateCustomLoginPolicyRequest) (*mgmt_pb.UpdateCustomLoginPolicyResponse, error) {
- policy, err := s.command.ChangeLoginPolicy(ctx, authz.GetCtxData(ctx).OrgID, updateLoginPolicyToDomain(req))
+ policy, err := s.command.ChangeLoginPolicy(ctx, authz.GetCtxData(ctx).OrgID, updateLoginPolicyToCommand(req))
if err != nil {
return nil, err
}
return &mgmt_pb.UpdateCustomLoginPolicyResponse{
Details: object.ChangeToDetailsPb(
policy.Sequence,
- policy.ChangeDate,
+ policy.EventDate,
policy.ResourceOwner,
),
}, nil
diff --git a/internal/api/grpc/management/policy_login_converter.go b/internal/api/grpc/management/policy_login_converter.go
index 3cf1d0a97..2e41d1c8f 100644
--- a/internal/api/grpc/management/policy_login_converter.go
+++ b/internal/api/grpc/management/policy_login_converter.go
@@ -4,13 +4,13 @@ import (
idp_grpc "github.com/zitadel/zitadel/internal/api/grpc/idp"
"github.com/zitadel/zitadel/internal/api/grpc/object"
policy_grpc "github.com/zitadel/zitadel/internal/api/grpc/policy"
- "github.com/zitadel/zitadel/internal/domain"
+ "github.com/zitadel/zitadel/internal/command"
"github.com/zitadel/zitadel/internal/query"
mgmt_pb "github.com/zitadel/zitadel/pkg/grpc/management"
)
-func AddLoginPolicyToDomain(p *mgmt_pb.AddCustomLoginPolicyRequest) *domain.LoginPolicy {
- return &domain.LoginPolicy{
+func AddLoginPolicyToCommand(p *mgmt_pb.AddCustomLoginPolicyRequest) *command.AddLoginPolicy {
+ return &command.AddLoginPolicy{
AllowUsernamePassword: p.AllowUsernamePassword,
AllowRegister: p.AllowRegister,
AllowExternalIDP: p.AllowExternalIdp,
@@ -27,22 +27,24 @@ func AddLoginPolicyToDomain(p *mgmt_pb.AddCustomLoginPolicyRequest) *domain.Logi
MultiFactorCheckLifetime: p.MultiFactorCheckLifetime.AsDuration(),
SecondFactors: policy_grpc.SecondFactorsTypesToDomain(p.SecondFactors),
MultiFactors: policy_grpc.MultiFactorsTypesToDomain(p.MultiFactors),
- IDPProviders: addLoginPolicyIDPsToDomain(p.Idps),
+ IDPProviders: addLoginPolicyIDPsToCommand(p.Idps),
+ DisableLoginWithEmail: p.DisableLoginWithEmail,
+ DisableLoginWithPhone: p.DisableLoginWithPhone,
}
}
-func addLoginPolicyIDPsToDomain(idps []*mgmt_pb.AddCustomLoginPolicyRequest_IDP) []*domain.IDPProvider {
- providers := make([]*domain.IDPProvider, len(idps))
+func addLoginPolicyIDPsToCommand(idps []*mgmt_pb.AddCustomLoginPolicyRequest_IDP) []*command.AddLoginPolicyIDP {
+ providers := make([]*command.AddLoginPolicyIDP, len(idps))
for i, idp := range idps {
- providers[i] = &domain.IDPProvider{
- Type: idp_grpc.IDPProviderTypeFromPb(idp.OwnerType),
- IDPConfigID: idp.IdpId,
+ providers[i] = &command.AddLoginPolicyIDP{
+ Type: idp_grpc.IDPProviderTypeFromPb(idp.OwnerType),
+ ConfigID: idp.IdpId,
}
}
return providers
}
-func updateLoginPolicyToDomain(p *mgmt_pb.UpdateCustomLoginPolicyRequest) *domain.LoginPolicy {
- return &domain.LoginPolicy{
+func updateLoginPolicyToCommand(p *mgmt_pb.UpdateCustomLoginPolicyRequest) *command.ChangeLoginPolicy {
+ return &command.ChangeLoginPolicy{
AllowUsernamePassword: p.AllowUsernamePassword,
AllowRegister: p.AllowRegister,
AllowExternalIDP: p.AllowExternalIdp,
@@ -51,6 +53,8 @@ func updateLoginPolicyToDomain(p *mgmt_pb.UpdateCustomLoginPolicyRequest) *domai
HidePasswordReset: p.HidePasswordReset,
IgnoreUnknownUsernames: p.IgnoreUnknownUsernames,
AllowDomainDiscovery: p.AllowDomainDiscovery,
+ DisableLoginWithEmail: p.DisableLoginWithEmail,
+ DisableLoginWithPhone: p.DisableLoginWithPhone,
DefaultRedirectURI: p.DefaultRedirectUri,
PasswordCheckLifetime: p.PasswordCheckLifetime.AsDuration(),
ExternalLoginCheckLifetime: p.ExternalLoginCheckLifetime.AsDuration(),
diff --git a/internal/api/grpc/policy/login_policy.go b/internal/api/grpc/policy/login_policy.go
index 498005f06..3cd191a91 100644
--- a/internal/api/grpc/policy/login_policy.go
+++ b/internal/api/grpc/policy/login_policy.go
@@ -22,6 +22,8 @@ func ModelLoginPolicyToPb(policy *query.LoginPolicy) *policy_pb.LoginPolicy {
HidePasswordReset: policy.HidePasswordReset,
IgnoreUnknownUsernames: policy.IgnoreUnknownUsernames,
AllowDomainDiscovery: policy.AllowDomainDiscovery,
+ DisableLoginWithEmail: policy.DisableLoginWithEmail,
+ DisableLoginWithPhone: policy.DisableLoginWithPhone,
DefaultRedirectUri: policy.DefaultRedirectURI,
PasswordCheckLifetime: durationpb.New(policy.PasswordCheckLifetime),
ExternalLoginCheckLifetime: durationpb.New(policy.ExternalLoginCheckLifetime),
diff --git a/internal/auth/repository/eventsourcing/eventstore/auth_request.go b/internal/auth/repository/eventsourcing/eventstore/auth_request.go
index 30e0cb05a..88d4e337b 100644
--- a/internal/auth/repository/eventsourcing/eventstore/auth_request.go
+++ b/internal/auth/repository/eventsourcing/eventstore/auth_request.go
@@ -641,15 +641,9 @@ func (repo *AuthRequestRepo) checkLoginName(ctx context.Context, request *domain
preferredLoginName += "@" + request.RequestedPrimaryDomain
}
}
- user, err = repo.View.UserByLoginNameAndResourceOwner(preferredLoginName, request.RequestedOrgID, request.InstanceID)
+ user, err = repo.checkLoginNameInputForResourceOwner(request, preferredLoginName)
} else {
- user, err = repo.View.UserByLoginName(loginName, request.InstanceID)
- if err == nil {
- err = repo.checkLoginPolicyWithResourceOwner(ctx, request, user)
- if err != nil {
- return err
- }
- }
+ user, err = repo.checkLoginNameInput(ctx, request, preferredLoginName)
}
// return any error apart from not found ones directly
if err != nil && !errors.IsNotFound(err) {
@@ -720,8 +714,74 @@ func (repo *AuthRequestRepo) checkDomainDiscovery(ctx context.Context, request *
return true
}
-func (repo *AuthRequestRepo) checkLoginPolicyWithResourceOwner(ctx context.Context, request *domain.AuthRequest, user *user_view_model.UserView) error {
- loginPolicy, idpProviders, err := repo.getLoginPolicyAndIDPProviders(ctx, user.ResourceOwner)
+func (repo *AuthRequestRepo) checkLoginNameInput(ctx context.Context, request *domain.AuthRequest, loginNameInput string) (*user_view_model.UserView, error) {
+ // always check the loginname first
+ user, err := repo.View.UserByLoginName(loginNameInput, request.InstanceID)
+ if err == nil {
+ // and take the user regardless if there would be a user with that email or phone
+ return user, repo.checkLoginPolicyWithResourceOwner(ctx, request, user.ResourceOwner)
+ }
+ user, emailErr := repo.View.UserByEmail(loginNameInput, request.InstanceID)
+ if emailErr == nil {
+ // if there was a single user with the specified email
+ // load and check the login policy
+ if emailErr = repo.checkLoginPolicyWithResourceOwner(ctx, request, user.ResourceOwner); emailErr != nil {
+ return nil, emailErr
+ }
+ // and in particular if the login with email is possible
+ // if so take the user (and ignore possible phone matches)
+ if !request.LoginPolicy.DisableLoginWithEmail {
+ return user, nil
+ }
+ }
+ user, phoneErr := repo.View.UserByPhone(loginNameInput, request.InstanceID)
+ if phoneErr == nil {
+ // if there was a single user with the specified phone
+ // load and check the login policy
+ if phoneErr = repo.checkLoginPolicyWithResourceOwner(ctx, request, user.ResourceOwner); phoneErr != nil {
+ return nil, phoneErr
+ }
+ // and in particular if the login with phone is possible
+ // if so take the user
+ if !request.LoginPolicy.DisableLoginWithPhone {
+ return user, nil
+ }
+ }
+ // if we get here the user was not found by loginname
+ // and either there was no match for email or phone as well, or they have been both disabled
+ return nil, err
+}
+
+func (repo *AuthRequestRepo) checkLoginNameInputForResourceOwner(request *domain.AuthRequest, loginNameInput string) (*user_view_model.UserView, error) {
+ // always check the loginname first
+ user, err := repo.View.UserByLoginNameAndResourceOwner(loginNameInput, request.RequestedOrgID, request.InstanceID)
+ if err == nil {
+ // and take the user regardless if there would be a user with that email or phone
+ return user, nil
+ }
+ if request.LoginPolicy != nil && !request.LoginPolicy.DisableLoginWithEmail {
+ // if login by email is allowed and there was a single user with the specified email
+ // take that user (and ignore possible phone number matches)
+ user, emailErr := repo.View.UserByEmailAndResourceOwner(loginNameInput, request.RequestedOrgID, request.InstanceID)
+ if emailErr == nil {
+ return user, nil
+ }
+ }
+ if request.LoginPolicy != nil && !request.LoginPolicy.DisableLoginWithPhone {
+ // if login by phone is allowed and there was a single user with the specified phone
+ // take that user
+ user, phoneErr := repo.View.UserByPhoneAndResourceOwner(loginNameInput, request.RequestedOrgID, request.InstanceID)
+ if phoneErr == nil {
+ return user, nil
+ }
+ }
+ // if we get here the user was not found by loginname
+ // and either there was no match for email or phone as well or they have been both disabled
+ return nil, err
+}
+
+func (repo *AuthRequestRepo) checkLoginPolicyWithResourceOwner(ctx context.Context, request *domain.AuthRequest, resourceOwner string) error {
+ loginPolicy, idpProviders, err := repo.getLoginPolicyAndIDPProviders(ctx, resourceOwner)
if err != nil {
return err
}
@@ -758,11 +818,15 @@ func queryLoginPolicyToDomain(policy *query.LoginPolicy) *domain.LoginPolicy {
PasswordlessType: policy.PasswordlessType,
HidePasswordReset: policy.HidePasswordReset,
IgnoreUnknownUsernames: policy.IgnoreUnknownUsernames,
+ AllowDomainDiscovery: policy.AllowDomainDiscovery,
+ DefaultRedirectURI: policy.DefaultRedirectURI,
PasswordCheckLifetime: policy.PasswordCheckLifetime,
ExternalLoginCheckLifetime: policy.ExternalLoginCheckLifetime,
MFAInitSkipLifetime: policy.MFAInitSkipLifetime,
SecondFactorCheckLifetime: policy.SecondFactorCheckLifetime,
MultiFactorCheckLifetime: policy.MultiFactorCheckLifetime,
+ DisableLoginWithEmail: policy.DisableLoginWithEmail,
+ DisableLoginWithPhone: policy.DisableLoginWithPhone,
}
}
diff --git a/internal/auth/repository/eventsourcing/view/user.go b/internal/auth/repository/eventsourcing/view/user.go
index dd56664a9..e9e14a189 100644
--- a/internal/auth/repository/eventsourcing/view/user.go
+++ b/internal/auth/repository/eventsourcing/view/user.go
@@ -52,10 +52,52 @@ func (v *View) UserByLoginNameAndResourceOwner(loginName, resourceOwner, instanc
return v.userByID(instanceID, loginNameQuery, resourceOwnerQuery)
}
+func (v *View) UserByEmail(email, instanceID string) (*model.UserView, error) {
+ emailQuery, err := query.NewUserVerifiedEmailSearchQuery(email, query.TextEquals)
+ if err != nil {
+ return nil, err
+ }
+ return v.userByID(instanceID, emailQuery)
+}
+
+func (v *View) UserByEmailAndResourceOwner(email, resourceOwner, instanceID string) (*model.UserView, error) {
+ emailQuery, err := query.NewUserVerifiedEmailSearchQuery(email, query.TextEquals)
+ if err != nil {
+ return nil, err
+ }
+ resourceOwnerQuery, err := query.NewUserResourceOwnerSearchQuery(resourceOwner, query.TextEquals)
+ if err != nil {
+ return nil, err
+ }
+
+ return v.userByID(instanceID, emailQuery, resourceOwnerQuery)
+}
+
+func (v *View) UserByPhone(phone, instanceID string) (*model.UserView, error) {
+ phoneQuery, err := query.NewUserVerifiedPhoneSearchQuery(phone, query.TextEquals)
+ if err != nil {
+ return nil, err
+ }
+ return v.userByID(instanceID, phoneQuery)
+}
+
+func (v *View) UserByPhoneAndResourceOwner(phone, resourceOwner, instanceID string) (*model.UserView, error) {
+ phoneQuery, err := query.NewUserVerifiedPhoneSearchQuery(phone, query.TextEquals)
+ if err != nil {
+ return nil, err
+ }
+ resourceOwnerQuery, err := query.NewUserResourceOwnerSearchQuery(resourceOwner, query.TextEquals)
+ if err != nil {
+ return nil, err
+ }
+
+ return v.userByID(instanceID, phoneQuery, resourceOwnerQuery)
+}
+
func (v *View) userByID(instanceID string, queries ...query.SearchQuery) (*model.UserView, error) {
ctx := authz.WithInstanceID(context.Background(), instanceID)
- queriedUser, err := v.query.GetUser(ctx, true, queries...)
+ queriedUser, err := v.query.GetNotifyUser(ctx, true, queries...)
if err != nil {
return nil, err
}
diff --git a/internal/command/command.go b/internal/command/command.go
index 9ca70163f..f68bc6efa 100644
--- a/internal/command/command.go
+++ b/internal/command/command.go
@@ -1,11 +1,13 @@
package command
import (
+ "context"
"net/http"
"time"
"github.com/zitadel/zitadel/internal/api/authz"
api_http "github.com/zitadel/zitadel/internal/api/http"
+ "github.com/zitadel/zitadel/internal/command/preparation"
sd "github.com/zitadel/zitadel/internal/config/systemdefaults"
"github.com/zitadel/zitadel/internal/crypto"
"github.com/zitadel/zitadel/internal/domain"
@@ -132,3 +134,28 @@ func AppendAndReduce(object interface {
object.AppendEvents(events...)
return object.Reduce()
}
+
+func queryAndReduce(ctx context.Context, filter preparation.FilterToQueryReducer, wm eventstore.QueryReducer) error {
+ events, err := filter(ctx, wm.Query())
+ if err != nil {
+ return err
+ }
+ if len(events) == 0 {
+ return nil
+ }
+ wm.AppendEvents(events...)
+ return wm.Reduce()
+}
+
+type existsWriteModel interface {
+ Exists() bool
+ eventstore.QueryReducer
+}
+
+func exists(ctx context.Context, filter preparation.FilterToQueryReducer, wm existsWriteModel) (bool, error) {
+ err := queryAndReduce(ctx, filter, wm)
+ if err != nil {
+ return false, err
+ }
+ return wm.Exists(), nil
+}
diff --git a/internal/command/idp_config_model.go b/internal/command/idp_config_model.go
index 8d37ab275..74654c244 100644
--- a/internal/command/idp_config_model.go
+++ b/internal/command/idp_config_model.go
@@ -62,3 +62,7 @@ func (rm *IDPConfigWriteModel) reduceConfigChangedEvent(e *idpconfig.IDPConfigCh
func (rm *IDPConfigWriteModel) reduceConfigStateChanged(configID string, state domain.IDPConfigState) {
rm.State = state
}
+
+func (rm *IDPConfigWriteModel) Exists() bool {
+ return rm.State.Exists()
+}
diff --git a/internal/command/instance.go b/internal/command/instance.go
index 7d9878785..2c9283c60 100644
--- a/internal/command/instance.go
+++ b/internal/command/instance.go
@@ -72,6 +72,8 @@ type InstanceSetup struct {
HidePasswordReset bool
IgnoreUnknownUsername bool
AllowDomainDiscovery bool
+ DisableLoginWithEmail bool
+ DisableLoginWithPhone bool
PasswordlessType domain.PasswordlessType
DefaultRedirectURI string
PasswordCheckLifetime time.Duration
@@ -219,6 +221,8 @@ func (c *Commands) SetUpInstance(ctx context.Context, setup *InstanceSetup) (str
setup.LoginPolicy.HidePasswordReset,
setup.LoginPolicy.IgnoreUnknownUsername,
setup.LoginPolicy.AllowDomainDiscovery,
+ setup.LoginPolicy.DisableLoginWithEmail,
+ setup.LoginPolicy.DisableLoginWithPhone,
setup.LoginPolicy.PasswordlessType,
setup.LoginPolicy.DefaultRedirectURI,
setup.LoginPolicy.PasswordCheckLifetime,
diff --git a/internal/command/instance_policy_login.go b/internal/command/instance_policy_login.go
index 34008536a..395c10723 100644
--- a/internal/command/instance_policy_login.go
+++ b/internal/command/instance_policy_login.go
@@ -15,56 +15,17 @@ import (
"github.com/zitadel/zitadel/internal/telemetry/tracing"
)
-func (c *Commands) ChangeDefaultLoginPolicy(ctx context.Context, policy *domain.LoginPolicy) (*domain.LoginPolicy, error) {
- existingPolicy := NewInstanceLoginPolicyWriteModel(ctx)
- instanceAgg := InstanceAggregateFromWriteModel(&existingPolicy.LoginPolicyWriteModel.WriteModel)
- event, err := c.changeDefaultLoginPolicy(ctx, instanceAgg, existingPolicy, policy)
+func (c *Commands) ChangeDefaultLoginPolicy(ctx context.Context, policy *ChangeLoginPolicy) (*domain.ObjectDetails, error) {
+ instanceAgg := instance.NewAggregate(authz.GetInstance(ctx).InstanceID())
+ cmds, err := preparation.PrepareCommands(ctx, c.eventstore.Filter, prepareChangeDefaultLoginPolicy(instanceAgg, policy))
if err != nil {
return nil, err
}
- pushedEvents, err := c.eventstore.Push(ctx, event)
+ pushedEvents, err := c.eventstore.Push(ctx, cmds...)
if err != nil {
return nil, err
}
- err = AppendAndReduce(existingPolicy, pushedEvents...)
- if err != nil {
- return nil, err
- }
- return writeModelToLoginPolicy(&existingPolicy.LoginPolicyWriteModel), nil
-}
-
-func (c *Commands) changeDefaultLoginPolicy(ctx context.Context, instanceAgg *eventstore.Aggregate, existingPolicy *InstanceLoginPolicyWriteModel, policy *domain.LoginPolicy) (eventstore.Command, error) {
- if ok := domain.ValidateDefaultRedirectURI(policy.DefaultRedirectURI); !ok {
- return nil, caos_errs.ThrowInvalidArgument(nil, "IAM-SFdqd", "Errors.IAM.LoginPolicy.RedirectURIInvalid")
- }
- err := c.defaultLoginPolicyWriteModelByID(ctx, existingPolicy)
- if err != nil {
- return nil, err
- }
- if existingPolicy.State == domain.PolicyStateUnspecified || existingPolicy.State == domain.PolicyStateRemoved {
- return nil, caos_errs.ThrowNotFound(nil, "INSTANCE-M0sif", "Errors.IAM.LoginPolicy.NotFound")
- }
- changedEvent, hasChanged := existingPolicy.NewChangedEvent(ctx,
- instanceAgg,
- policy.AllowUsernamePassword,
- policy.AllowRegister,
- policy.AllowExternalIDP,
- policy.ForceMFA,
- policy.HidePasswordReset,
- policy.IgnoreUnknownUsernames,
- policy.AllowDomainDiscovery,
- policy.PasswordlessType,
- policy.DefaultRedirectURI,
- policy.PasswordCheckLifetime,
- policy.ExternalLoginCheckLifetime,
- policy.MFAInitSkipLifetime,
- policy.SecondFactorCheckLifetime,
- policy.MultiFactorCheckLifetime,
- )
- if !hasChanged {
- return nil, caos_errs.ThrowPreconditionFailed(nil, "INSTANCE-5M9vdd", "Errors.IAM.LoginPolicy.NotChanged")
- }
- return changedEvent, nil
+ return pushedEventsToObjectDetails(pushedEvents), nil
}
func (c *Commands) AddIDPProviderToDefaultLoginPolicy(ctx context.Context, idpProvider *domain.IDPProvider) (*domain.IDPProvider, error) {
@@ -255,6 +216,44 @@ func (c *Commands) getDefaultLoginPolicy(ctx context.Context) (*domain.LoginPoli
return policy, nil
}
+func prepareChangeDefaultLoginPolicy(a *instance.Aggregate, policy *ChangeLoginPolicy) preparation.Validation {
+ return func() (preparation.CreateCommands, error) {
+ if ok := domain.ValidateDefaultRedirectURI(policy.DefaultRedirectURI); !ok {
+ return nil, caos_errs.ThrowInvalidArgument(nil, "IAM-SFdqd", "Errors.IAM.LoginPolicy.RedirectURIInvalid")
+ }
+ return func(ctx context.Context, filter preparation.FilterToQueryReducer) ([]eventstore.Command, error) {
+ wm := NewInstanceLoginPolicyWriteModel(ctx)
+ if err := queryAndReduce(ctx, filter, wm); err != nil {
+ return nil, err
+ }
+ if !wm.State.Exists() {
+ return nil, caos_errs.ThrowNotFound(nil, "INSTANCE-M0sif", "Errors.IAM.LoginPolicy.NotFound")
+ }
+ changedEvent, hasChanged := wm.NewChangedEvent(ctx, &a.Aggregate,
+ policy.AllowUsernamePassword,
+ policy.AllowRegister,
+ policy.AllowExternalIDP,
+ policy.ForceMFA,
+ policy.HidePasswordReset,
+ policy.IgnoreUnknownUsernames,
+ policy.AllowDomainDiscovery,
+ policy.DisableLoginWithEmail,
+ policy.DisableLoginWithPhone,
+ policy.PasswordlessType,
+ policy.DefaultRedirectURI,
+ policy.PasswordCheckLifetime,
+ policy.ExternalLoginCheckLifetime,
+ policy.MFAInitSkipLifetime,
+ policy.SecondFactorCheckLifetime,
+ policy.MultiFactorCheckLifetime)
+ if !hasChanged {
+ return nil, caos_errs.ThrowPreconditionFailed(nil, "INSTANCE-5M9vdd", "Errors.IAM.LoginPolicy.NotChanged")
+ }
+ return []eventstore.Command{changedEvent}, nil
+ }, nil
+ }
+}
+
func prepareAddDefaultLoginPolicy(
a *instance.Aggregate,
allowUsernamePassword bool,
@@ -264,6 +263,8 @@ func prepareAddDefaultLoginPolicy(
hidePasswordReset bool,
ignoreUnknownUsernames bool,
allowDomainDiscovery bool,
+ disableLoginWithEmail bool,
+ disableLoginWithPhone bool,
passwordlessType domain.PasswordlessType,
defaultRedirectURI string,
passwordCheckLifetime time.Duration,
@@ -295,6 +296,8 @@ func prepareAddDefaultLoginPolicy(
hidePasswordReset,
ignoreUnknownUsernames,
allowDomainDiscovery,
+ disableLoginWithEmail,
+ disableLoginWithPhone,
passwordlessType,
defaultRedirectURI,
passwordCheckLifetime,
diff --git a/internal/command/instance_policy_login_model.go b/internal/command/instance_policy_login_model.go
index 972265b26..3f04616aa 100644
--- a/internal/command/instance_policy_login_model.go
+++ b/internal/command/instance_policy_login_model.go
@@ -67,7 +67,9 @@ func (wm *InstanceLoginPolicyWriteModel) NewChangedEvent(
forceMFA,
hidePasswordReset,
ignoreUnknownUsernames,
- allowDomainDiscovery bool,
+ allowDomainDiscovery,
+ disableLoginWithEmail,
+ disableLoginWithPhone bool,
passwordlessType domain.PasswordlessType,
defaultRedirectURI string,
passwordCheckLifetime,
@@ -120,6 +122,12 @@ func (wm *InstanceLoginPolicyWriteModel) NewChangedEvent(
if wm.MultiFactorCheckLifetime != multiFactorCheckLifetime {
changes = append(changes, policy.ChangeMultiFactorCheckLifetime(multiFactorCheckLifetime))
}
+ if wm.DisableLoginWithEmail != disableLoginWithEmail {
+ changes = append(changes, policy.ChangeDisableLoginWithEmail(disableLoginWithEmail))
+ }
+ if wm.DisableLoginWithPhone != disableLoginWithPhone {
+ changes = append(changes, policy.ChangeDisableLoginWithPhone(disableLoginWithPhone))
+ }
if len(changes) == 0 {
return nil, false
}
diff --git a/internal/command/instance_policy_login_test.go b/internal/command/instance_policy_login_test.go
index 3e1518ec9..639fc4a65 100644
--- a/internal/command/instance_policy_login_test.go
+++ b/internal/command/instance_policy_login_test.go
@@ -24,10 +24,10 @@ func TestCommandSide_ChangeDefaultLoginPolicy(t *testing.T) {
}
type args struct {
ctx context.Context
- policy *domain.LoginPolicy
+ policy *ChangeLoginPolicy
}
type res struct {
- want *domain.LoginPolicy
+ want *domain.ObjectDetails
err func(error) bool
}
tests := []struct {
@@ -46,7 +46,7 @@ func TestCommandSide_ChangeDefaultLoginPolicy(t *testing.T) {
},
args: args{
ctx: context.Background(),
- policy: &domain.LoginPolicy{
+ policy: &ChangeLoginPolicy{
AllowRegister: true,
AllowExternalIDP: true,
},
@@ -71,6 +71,8 @@ func TestCommandSide_ChangeDefaultLoginPolicy(t *testing.T) {
true,
true,
true,
+ true,
+ true,
domain.PasswordlessTypeAllowed,
"https://example.com/redirect",
time.Hour*1,
@@ -85,7 +87,7 @@ func TestCommandSide_ChangeDefaultLoginPolicy(t *testing.T) {
},
args: args{
ctx: context.Background(),
- policy: &domain.LoginPolicy{
+ policy: &ChangeLoginPolicy{
AllowRegister: true,
AllowUsernamePassword: true,
AllowExternalIDP: true,
@@ -93,6 +95,8 @@ func TestCommandSide_ChangeDefaultLoginPolicy(t *testing.T) {
HidePasswordReset: true,
IgnoreUnknownUsernames: true,
AllowDomainDiscovery: true,
+ DisableLoginWithEmail: true,
+ DisableLoginWithPhone: true,
PasswordlessType: domain.PasswordlessTypeAllowed,
DefaultRedirectURI: "https://example.com/redirect",
PasswordCheckLifetime: time.Hour * 1,
@@ -123,6 +127,8 @@ func TestCommandSide_ChangeDefaultLoginPolicy(t *testing.T) {
true,
true,
true,
+ true,
+ true,
domain.PasswordlessTypeAllowed,
"https://example.com/redirect",
time.Hour*1,
@@ -145,6 +151,8 @@ func TestCommandSide_ChangeDefaultLoginPolicy(t *testing.T) {
false,
false,
false,
+ false,
+ false,
domain.PasswordlessTypeNotAllowed,
"",
time.Hour*10,
@@ -159,7 +167,7 @@ func TestCommandSide_ChangeDefaultLoginPolicy(t *testing.T) {
},
args: args{
ctx: authz.WithInstanceID(context.Background(), "INSTANCE"),
- policy: &domain.LoginPolicy{
+ policy: &ChangeLoginPolicy{
AllowRegister: false,
AllowUsernamePassword: false,
AllowExternalIDP: false,
@@ -167,6 +175,8 @@ func TestCommandSide_ChangeDefaultLoginPolicy(t *testing.T) {
HidePasswordReset: false,
IgnoreUnknownUsernames: false,
AllowDomainDiscovery: false,
+ DisableLoginWithEmail: false,
+ DisableLoginWithPhone: false,
PasswordlessType: domain.PasswordlessTypeNotAllowed,
DefaultRedirectURI: "",
PasswordCheckLifetime: time.Hour * 10,
@@ -177,26 +187,8 @@ func TestCommandSide_ChangeDefaultLoginPolicy(t *testing.T) {
},
},
res: res{
- want: &domain.LoginPolicy{
- ObjectRoot: models.ObjectRoot{
- InstanceID: "INSTANCE",
- AggregateID: "INSTANCE",
- ResourceOwner: "INSTANCE",
- },
- AllowRegister: false,
- AllowUsernamePassword: false,
- AllowExternalIDP: false,
- ForceMFA: false,
- HidePasswordReset: false,
- IgnoreUnknownUsernames: false,
- AllowDomainDiscovery: false,
- PasswordlessType: domain.PasswordlessTypeNotAllowed,
- DefaultRedirectURI: "",
- PasswordCheckLifetime: time.Hour * 10,
- ExternalLoginCheckLifetime: time.Hour * 20,
- MFAInitSkipLifetime: time.Hour * 30,
- SecondFactorCheckLifetime: time.Hour * 40,
- MultiFactorCheckLifetime: time.Hour * 50,
+ want: &domain.ObjectDetails{
+ ResourceOwner: "INSTANCE",
},
},
},
@@ -287,6 +279,8 @@ func TestCommandSide_AddIDPProviderDefaultLoginPolicy(t *testing.T) {
true,
true,
true,
+ true,
+ true,
domain.PasswordlessTypeAllowed,
"",
time.Hour*1,
@@ -326,6 +320,8 @@ func TestCommandSide_AddIDPProviderDefaultLoginPolicy(t *testing.T) {
true,
true,
true,
+ true,
+ true,
domain.PasswordlessTypeAllowed,
"",
time.Hour*1,
@@ -385,6 +381,8 @@ func TestCommandSide_AddIDPProviderDefaultLoginPolicy(t *testing.T) {
true,
true,
true,
+ true,
+ true,
domain.PasswordlessTypeAllowed,
"",
time.Hour*1,
@@ -526,6 +524,8 @@ func TestCommandSide_RemoveIDPProviderDefaultLoginPolicy(t *testing.T) {
true,
true,
true,
+ true,
+ true,
domain.PasswordlessTypeAllowed,
"",
time.Hour*1,
@@ -565,6 +565,8 @@ func TestCommandSide_RemoveIDPProviderDefaultLoginPolicy(t *testing.T) {
true,
true,
true,
+ true,
+ true,
domain.PasswordlessTypeAllowed,
"",
time.Hour*1,
@@ -617,6 +619,8 @@ func TestCommandSide_RemoveIDPProviderDefaultLoginPolicy(t *testing.T) {
true,
true,
true,
+ true,
+ true,
domain.PasswordlessTypeAllowed,
"",
time.Hour*1,
@@ -674,6 +678,8 @@ func TestCommandSide_RemoveIDPProviderDefaultLoginPolicy(t *testing.T) {
true,
true,
true,
+ true,
+ true,
domain.PasswordlessTypeAllowed,
"",
time.Hour*1,
@@ -739,6 +745,8 @@ func TestCommandSide_RemoveIDPProviderDefaultLoginPolicy(t *testing.T) {
true,
true,
true,
+ true,
+ true,
domain.PasswordlessTypeAllowed,
"",
time.Hour*1,
@@ -1293,7 +1301,8 @@ func TestCommandSide_RemoveMultiFactorDefaultLoginPolicy(t *testing.T) {
}
}
-func newDefaultLoginPolicyChangedEvent(ctx context.Context, allowRegister, allowUsernamePassword, allowExternalIDP, forceMFA, hidePasswordReset, ignoreUnknownUsernames, allowDomainDiscovery bool,
+func newDefaultLoginPolicyChangedEvent(ctx context.Context, allowRegister, allowUsernamePassword, allowExternalIDP, forceMFA,
+ hidePasswordReset, ignoreUnknownUsernames, allowDomainDiscovery, disableLoginWithEmail, disableLoginWithPhone bool,
passwordlessType domain.PasswordlessType,
redirectURI string,
passwordLifetime, externalLoginLifetime, mfaInitSkipLifetime, secondFactorLifetime, multiFactorLifetime time.Duration) *instance.LoginPolicyChangedEvent {
@@ -1307,6 +1316,8 @@ func newDefaultLoginPolicyChangedEvent(ctx context.Context, allowRegister, allow
policy.ChangeHidePasswordReset(hidePasswordReset),
policy.ChangeIgnoreUnknownUsernames(ignoreUnknownUsernames),
policy.ChangeAllowDomainDiscovery(allowDomainDiscovery),
+ policy.ChangeDisableLoginWithEmail(disableLoginWithEmail),
+ policy.ChangeDisableLoginWithPhone(disableLoginWithPhone),
policy.ChangePasswordlessType(passwordlessType),
policy.ChangeDefaultRedirectURI(redirectURI),
policy.ChangePasswordCheckLifetime(passwordLifetime),
diff --git a/internal/command/org_policy_login.go b/internal/command/org_policy_login.go
index e85d6f2a2..bee73e079 100644
--- a/internal/command/org_policy_login.go
+++ b/internal/command/org_policy_login.go
@@ -2,9 +2,12 @@ package command
import (
"context"
+ "time"
"github.com/zitadel/logging"
+ "github.com/zitadel/zitadel/internal/api/authz"
+ "github.com/zitadel/zitadel/internal/command/preparation"
"github.com/zitadel/zitadel/internal/domain"
caos_errs "github.com/zitadel/zitadel/internal/errors"
"github.com/zitadel/zitadel/internal/eventstore"
@@ -12,74 +15,63 @@ import (
"github.com/zitadel/zitadel/internal/telemetry/tracing"
)
-func (c *Commands) AddLoginPolicy(ctx context.Context, resourceOwner string, policy *domain.LoginPolicy) (*domain.LoginPolicy, error) {
- if resourceOwner == "" {
- return nil, caos_errs.ThrowInvalidArgument(nil, "Org-Fn8ds", "Errors.ResourceOwnerMissing")
- }
- if ok := domain.ValidateDefaultRedirectURI(policy.DefaultRedirectURI); !ok {
- return nil, caos_errs.ThrowInvalidArgument(nil, "Org-WSfdq", "Errors.Org.LoginPolicy.RedirectURIInvalid")
- }
- addedPolicy := NewOrgLoginPolicyWriteModel(resourceOwner)
- err := c.eventstore.FilterToQueryReducer(ctx, addedPolicy)
+type AddLoginPolicy struct {
+ AllowUsernamePassword bool
+ AllowRegister bool
+ AllowExternalIDP bool
+ IDPProviders []*AddLoginPolicyIDP
+ ForceMFA bool
+ SecondFactors []domain.SecondFactorType
+ MultiFactors []domain.MultiFactorType
+ PasswordlessType domain.PasswordlessType
+ HidePasswordReset bool
+ IgnoreUnknownUsernames bool
+ AllowDomainDiscovery bool
+ DefaultRedirectURI string
+ PasswordCheckLifetime time.Duration
+ ExternalLoginCheckLifetime time.Duration
+ MFAInitSkipLifetime time.Duration
+ SecondFactorCheckLifetime time.Duration
+ MultiFactorCheckLifetime time.Duration
+ DisableLoginWithEmail bool
+ DisableLoginWithPhone bool
+}
+
+type AddLoginPolicyIDP struct {
+ ConfigID string
+ Type domain.IdentityProviderType
+}
+
+type ChangeLoginPolicy struct {
+ AllowUsernamePassword bool
+ AllowRegister bool
+ AllowExternalIDP bool
+ ForceMFA bool
+ PasswordlessType domain.PasswordlessType
+ HidePasswordReset bool
+ IgnoreUnknownUsernames bool
+ AllowDomainDiscovery bool
+ DefaultRedirectURI string
+ PasswordCheckLifetime time.Duration
+ ExternalLoginCheckLifetime time.Duration
+ MFAInitSkipLifetime time.Duration
+ SecondFactorCheckLifetime time.Duration
+ MultiFactorCheckLifetime time.Duration
+ DisableLoginWithEmail bool
+ DisableLoginWithPhone bool
+}
+
+func (c *Commands) AddLoginPolicy(ctx context.Context, resourceOwner string, policy *AddLoginPolicy) (*domain.ObjectDetails, error) {
+ orgAgg := org.NewAggregate(resourceOwner)
+ cmds, err := preparation.PrepareCommands(ctx, c.eventstore.Filter, prepareAddLoginPolicy(orgAgg, policy))
if err != nil {
return nil, err
}
- if addedPolicy.State == domain.PolicyStateActive {
- return nil, caos_errs.ThrowAlreadyExists(nil, "Org-Dgfb2", "Errors.Org.LoginPolicy.AlreadyExists")
- }
-
- orgAgg := OrgAggregateFromWriteModel(&addedPolicy.WriteModel)
- cmds := []eventstore.Command{
- org.NewLoginPolicyAddedEvent(
- ctx,
- orgAgg,
- policy.AllowUsernamePassword,
- policy.AllowRegister,
- policy.AllowExternalIDP,
- policy.ForceMFA,
- policy.HidePasswordReset,
- policy.IgnoreUnknownUsernames,
- policy.AllowDomainDiscovery,
- policy.PasswordlessType,
- policy.DefaultRedirectURI,
- policy.PasswordCheckLifetime,
- policy.ExternalLoginCheckLifetime,
- policy.MFAInitSkipLifetime,
- policy.SecondFactorCheckLifetime,
- policy.MultiFactorCheckLifetime),
- }
- for _, factor := range policy.SecondFactors {
- if !factor.Valid() {
- return nil, caos_errs.ThrowInvalidArgument(nil, "Org-SFeea", "Errors.Org.LoginPolicy.MFA.Unspecified")
- }
- cmds = append(cmds, org.NewLoginPolicySecondFactorAddedEvent(ctx, orgAgg, factor))
- }
- for _, factor := range policy.MultiFactors {
- if !factor.Valid() {
- return nil, caos_errs.ThrowInvalidArgument(nil, "Org-WSfrg", "Errors.Org.LoginPolicy.MFA.Unspecified")
- }
- cmds = append(cmds, org.NewLoginPolicyMultiFactorAddedEvent(ctx, orgAgg, factor))
- }
- for _, provider := range policy.IDPProviders {
- if provider.Type == domain.IdentityProviderTypeOrg {
- _, err = c.getOrgIDPConfigByID(ctx, provider.IDPConfigID, resourceOwner)
- } else {
- _, err = c.getInstanceIDPConfigByID(ctx, provider.IDPConfigID)
- }
- if err != nil {
- return nil, caos_errs.ThrowPreconditionFailed(err, "Org-FEd32", "Errors.IDPConfig.NotExisting")
- }
- cmds = append(cmds, org.NewIdentityProviderAddedEvent(ctx, orgAgg, provider.IDPConfigID, provider.Type))
- }
pushedEvents, err := c.eventstore.Push(ctx, cmds...)
if err != nil {
return nil, err
}
- err = AppendAndReduce(addedPolicy, pushedEvents...)
- if err != nil {
- return nil, err
- }
- return writeModelToLoginPolicy(&addedPolicy.LoginPolicyWriteModel), nil
+ return pushedEventsToObjectDetails(pushedEvents), nil
}
func (c *Commands) orgLoginPolicyWriteModelByID(ctx context.Context, orgID string) (*OrgLoginPolicyWriteModel, error) {
@@ -102,54 +94,17 @@ func (c *Commands) getOrgLoginPolicy(ctx context.Context, orgID string) (*domain
return c.getDefaultLoginPolicy(ctx)
}
-func (c *Commands) ChangeLoginPolicy(ctx context.Context, resourceOwner string, policy *domain.LoginPolicy) (*domain.LoginPolicy, error) {
- if resourceOwner == "" {
- return nil, caos_errs.ThrowInvalidArgument(nil, "Org-Mf9sf", "Errors.ResourceOwnerMissing")
- }
- if ok := domain.ValidateDefaultRedirectURI(policy.DefaultRedirectURI); !ok {
- return nil, caos_errs.ThrowInvalidArgument(nil, "Org-Sfd21", "Errors.Org.LoginPolicy.RedirectURIInvalid")
- }
- existingPolicy := NewOrgLoginPolicyWriteModel(resourceOwner)
- err := c.eventstore.FilterToQueryReducer(ctx, existingPolicy)
+func (c *Commands) ChangeLoginPolicy(ctx context.Context, resourceOwner string, policy *ChangeLoginPolicy) (*domain.ObjectDetails, error) {
+ orgAgg := org.NewAggregate(resourceOwner)
+ cmds, err := preparation.PrepareCommands(ctx, c.eventstore.Filter, prepareChangeLoginPolicy(orgAgg, policy))
if err != nil {
return nil, err
}
- if existingPolicy.State == domain.PolicyStateUnspecified || existingPolicy.State == domain.PolicyStateRemoved {
- return nil, caos_errs.ThrowNotFound(nil, "Org-M0sif", "Errors.Org.LoginPolicy.NotFound")
- }
-
- orgAgg := OrgAggregateFromWriteModel(&existingPolicy.LoginPolicyWriteModel.WriteModel)
- changedEvent, hasChanged := existingPolicy.NewChangedEvent(
- ctx,
- orgAgg,
- policy.AllowUsernamePassword,
- policy.AllowRegister,
- policy.AllowExternalIDP,
- policy.ForceMFA,
- policy.HidePasswordReset,
- policy.IgnoreUnknownUsernames,
- policy.AllowDomainDiscovery,
- policy.PasswordlessType,
- policy.DefaultRedirectURI,
- policy.PasswordCheckLifetime,
- policy.ExternalLoginCheckLifetime,
- policy.MFAInitSkipLifetime,
- policy.SecondFactorCheckLifetime,
- policy.MultiFactorCheckLifetime)
-
- if !hasChanged {
- return nil, caos_errs.ThrowPreconditionFailed(nil, "Org-5M9vdd", "Errors.Org.LoginPolicy.NotChanged")
- }
-
- pushedEvents, err := c.eventstore.Push(ctx, changedEvent)
+ pushedEvents, err := c.eventstore.Push(ctx, cmds...)
if err != nil {
return nil, err
}
- err = AppendAndReduce(existingPolicy, pushedEvents...)
- if err != nil {
- return nil, err
- }
- return writeModelToLoginPolicy(&existingPolicy.LoginPolicyWriteModel), nil
+ return pushedEventsToObjectDetails(pushedEvents), nil
}
func (c *Commands) RemoveLoginPolicy(ctx context.Context, orgID string) (*domain.ObjectDetails, error) {
@@ -437,3 +392,106 @@ func (c *Commands) orgLoginPolicyAuthFactorsWriteModel(ctx context.Context, orgI
}
return writeModel, nil
}
+
+func prepareAddLoginPolicy(a *org.Aggregate, policy *AddLoginPolicy) preparation.Validation {
+ return func() (preparation.CreateCommands, error) {
+ if ok := domain.ValidateDefaultRedirectURI(policy.DefaultRedirectURI); !ok {
+ return nil, caos_errs.ThrowInvalidArgument(nil, "Org-WSfdq", "Errors.Org.LoginPolicy.RedirectURIInvalid")
+ }
+ for _, factor := range policy.SecondFactors {
+ if !factor.Valid() {
+ return nil, caos_errs.ThrowInvalidArgument(nil, "Org-SFeea", "Errors.Org.LoginPolicy.MFA.Unspecified")
+ }
+ }
+ for _, factor := range policy.MultiFactors {
+ if !factor.Valid() {
+ return nil, caos_errs.ThrowInvalidArgument(nil, "Org-WSfrg", "Errors.Org.LoginPolicy.MFA.Unspecified")
+ }
+ }
+ return func(ctx context.Context, filter preparation.FilterToQueryReducer) ([]eventstore.Command, error) {
+ if exists, err := exists(ctx, filter, NewOrgLoginPolicyWriteModel(a.ID)); exists || err != nil {
+ return nil, caos_errs.ThrowAlreadyExists(nil, "Org-Dgfb2", "Errors.Org.LoginPolicy.AlreadyExists")
+ }
+ for _, idp := range policy.IDPProviders {
+ exists, err := idpExists(ctx, filter, idp)
+ if !exists || err != nil {
+ return nil, caos_errs.ThrowPreconditionFailed(err, "Org-FEd32", "Errors.IDPConfig.NotExisting")
+ }
+ }
+ cmds := make([]eventstore.Command, 0, len(policy.SecondFactors)+len(policy.MultiFactors)+len(policy.IDPProviders)+1)
+ cmds = append(cmds, org.NewLoginPolicyAddedEvent(ctx, &a.Aggregate,
+ policy.AllowUsernamePassword,
+ policy.AllowRegister,
+ policy.AllowExternalIDP,
+ policy.ForceMFA,
+ policy.HidePasswordReset,
+ policy.IgnoreUnknownUsernames,
+ policy.AllowDomainDiscovery,
+ policy.DisableLoginWithEmail,
+ policy.DisableLoginWithPhone,
+ policy.PasswordlessType,
+ policy.DefaultRedirectURI,
+ policy.PasswordCheckLifetime,
+ policy.ExternalLoginCheckLifetime,
+ policy.MFAInitSkipLifetime,
+ policy.SecondFactorCheckLifetime,
+ policy.MultiFactorCheckLifetime,
+ ))
+ for _, factor := range policy.SecondFactors {
+ cmds = append(cmds, org.NewLoginPolicySecondFactorAddedEvent(ctx, &a.Aggregate, factor))
+ }
+ for _, factor := range policy.MultiFactors {
+ cmds = append(cmds, org.NewLoginPolicyMultiFactorAddedEvent(ctx, &a.Aggregate, factor))
+ }
+ for _, idp := range policy.IDPProviders {
+ cmds = append(cmds, org.NewIdentityProviderAddedEvent(ctx, &a.Aggregate, idp.ConfigID, idp.Type))
+ }
+ return cmds, nil
+ }, nil
+ }
+}
+
+func prepareChangeLoginPolicy(a *org.Aggregate, policy *ChangeLoginPolicy) preparation.Validation {
+ return func() (preparation.CreateCommands, error) {
+ if ok := domain.ValidateDefaultRedirectURI(policy.DefaultRedirectURI); !ok {
+ return nil, caos_errs.ThrowInvalidArgument(nil, "Org-Sfd21", "Errors.Org.LoginPolicy.RedirectURIInvalid")
+ }
+ return func(ctx context.Context, filter preparation.FilterToQueryReducer) ([]eventstore.Command, error) {
+ wm := NewOrgLoginPolicyWriteModel(a.ID)
+ if err := queryAndReduce(ctx, filter, wm); err != nil {
+ return nil, err
+ }
+ if !wm.State.Exists() {
+ return nil, caos_errs.ThrowNotFound(nil, "Org-M0sif", "Errors.Org.LoginPolicy.NotFound")
+ }
+ changedEvent, hasChanged := wm.NewChangedEvent(ctx, &a.Aggregate,
+ policy.AllowUsernamePassword,
+ policy.AllowRegister,
+ policy.AllowExternalIDP,
+ policy.ForceMFA,
+ policy.HidePasswordReset,
+ policy.IgnoreUnknownUsernames,
+ policy.AllowDomainDiscovery,
+ policy.DisableLoginWithEmail,
+ policy.DisableLoginWithPhone,
+ policy.PasswordlessType,
+ policy.DefaultRedirectURI,
+ policy.PasswordCheckLifetime,
+ policy.ExternalLoginCheckLifetime,
+ policy.MFAInitSkipLifetime,
+ policy.SecondFactorCheckLifetime,
+ policy.MultiFactorCheckLifetime)
+ if !hasChanged {
+ return nil, caos_errs.ThrowPreconditionFailed(nil, "Org-5M9vdd", "Errors.Org.LoginPolicy.NotChanged")
+ }
+ return []eventstore.Command{changedEvent}, nil
+ }, nil
+ }
+}
+
+func idpExists(ctx context.Context, filter preparation.FilterToQueryReducer, idp *AddLoginPolicyIDP) (bool, error) {
+ if idp.Type == domain.IdentityProviderTypeSystem {
+ return exists(ctx, filter, NewInstanceIDPConfigWriteModel(ctx, idp.ConfigID))
+ }
+ return exists(ctx, filter, NewOrgIDPConfigWriteModel(idp.ConfigID, authz.GetCtxData(ctx).ResourceOwner))
+}
diff --git a/internal/command/org_policy_login_model.go b/internal/command/org_policy_login_model.go
index 4eaccbae5..1f546ea99 100644
--- a/internal/command/org_policy_login_model.go
+++ b/internal/command/org_policy_login_model.go
@@ -69,7 +69,9 @@ func (wm *OrgLoginPolicyWriteModel) NewChangedEvent(
forceMFA,
hidePasswordReset,
ignoreUnknownUsernames,
- allowDomainDiscovery bool,
+ allowDomainDiscovery,
+ disableLoginWithEmail,
+ disableLoginWithPhone bool,
passwordlessType domain.PasswordlessType,
defaultRedirectURI string,
passwordCheckLifetime,
@@ -122,6 +124,12 @@ func (wm *OrgLoginPolicyWriteModel) NewChangedEvent(
if wm.DefaultRedirectURI != defaultRedirectURI {
changes = append(changes, policy.ChangeDefaultRedirectURI(defaultRedirectURI))
}
+ if wm.DisableLoginWithEmail != disableLoginWithEmail {
+ changes = append(changes, policy.ChangeDisableLoginWithEmail(disableLoginWithEmail))
+ }
+ if wm.DisableLoginWithPhone != disableLoginWithPhone {
+ changes = append(changes, policy.ChangeDisableLoginWithPhone(disableLoginWithPhone))
+ }
if len(changes) == 0 {
return nil, false
}
diff --git a/internal/command/org_policy_login_test.go b/internal/command/org_policy_login_test.go
index 9dfaeb0c4..e4a3c0a2f 100644
--- a/internal/command/org_policy_login_test.go
+++ b/internal/command/org_policy_login_test.go
@@ -33,10 +33,10 @@ func TestCommandSide_AddLoginPolicy(t *testing.T) {
type args struct {
ctx context.Context
orgID string
- policy *domain.LoginPolicy
+ policy *AddLoginPolicy
}
type res struct {
- want *domain.LoginPolicy
+ want *domain.ObjectDetails
err func(error) bool
}
tests := []struct {
@@ -45,25 +45,6 @@ func TestCommandSide_AddLoginPolicy(t *testing.T) {
args args
res res
}{
- {
- name: "org id missing, invalid argument error",
- fields: fields{
- eventstore: eventstoreExpect(
- t,
- ),
- },
- args: args{
- ctx: context.Background(),
- policy: &domain.LoginPolicy{
- AllowRegister: true,
- AllowUsernamePassword: true,
- PasswordlessType: domain.PasswordlessTypeAllowed,
- },
- },
- res: res{
- err: caos_errs.IsErrorInvalidArgument,
- },
- },
{
name: "loginpolicy already existing, already exists error",
fields: fields{
@@ -80,6 +61,8 @@ func TestCommandSide_AddLoginPolicy(t *testing.T) {
true,
true,
true,
+ false,
+ false,
domain.PasswordlessTypeAllowed,
"https://example.com/redirect",
time.Hour*1,
@@ -95,7 +78,7 @@ func TestCommandSide_AddLoginPolicy(t *testing.T) {
args: args{
ctx: context.Background(),
orgID: "org1",
- policy: &domain.LoginPolicy{
+ policy: &AddLoginPolicy{
AllowRegister: true,
AllowUsernamePassword: true,
AllowExternalIDP: true,
@@ -133,6 +116,8 @@ func TestCommandSide_AddLoginPolicy(t *testing.T) {
true,
true,
true,
+ true,
+ true,
domain.PasswordlessTypeAllowed,
"https://example.com/redirect",
time.Hour*1,
@@ -149,7 +134,7 @@ func TestCommandSide_AddLoginPolicy(t *testing.T) {
args: args{
ctx: context.Background(),
orgID: "org1",
- policy: &domain.LoginPolicy{
+ policy: &AddLoginPolicy{
AllowRegister: true,
AllowUsernamePassword: true,
AllowExternalIDP: true,
@@ -157,6 +142,8 @@ func TestCommandSide_AddLoginPolicy(t *testing.T) {
HidePasswordReset: true,
IgnoreUnknownUsernames: true,
AllowDomainDiscovery: true,
+ DisableLoginWithEmail: true,
+ DisableLoginWithPhone: true,
PasswordlessType: domain.PasswordlessTypeAllowed,
DefaultRedirectURI: "https://example.com/redirect",
PasswordCheckLifetime: time.Hour * 1,
@@ -167,25 +154,8 @@ func TestCommandSide_AddLoginPolicy(t *testing.T) {
},
},
res: res{
- want: &domain.LoginPolicy{
- ObjectRoot: models.ObjectRoot{
- AggregateID: "org1",
- ResourceOwner: "org1",
- },
- AllowRegister: true,
- AllowUsernamePassword: true,
- AllowExternalIDP: true,
- ForceMFA: true,
- HidePasswordReset: true,
- IgnoreUnknownUsernames: true,
- AllowDomainDiscovery: true,
- PasswordlessType: domain.PasswordlessTypeAllowed,
- DefaultRedirectURI: "https://example.com/redirect",
- PasswordCheckLifetime: time.Hour * 1,
- ExternalLoginCheckLifetime: time.Hour * 2,
- MFAInitSkipLifetime: time.Hour * 3,
- SecondFactorCheckLifetime: time.Hour * 4,
- MultiFactorCheckLifetime: time.Hour * 5,
+ want: &domain.ObjectDetails{
+ ResourceOwner: "org1",
},
},
},
@@ -194,13 +164,12 @@ func TestCommandSide_AddLoginPolicy(t *testing.T) {
fields: fields{
eventstore: eventstoreExpect(
t,
- expectFilter(),
),
},
args: args{
ctx: context.Background(),
orgID: "org1",
- policy: &domain.LoginPolicy{
+ policy: &AddLoginPolicy{
AllowRegister: true,
AllowUsernamePassword: true,
AllowExternalIDP: true,
@@ -208,6 +177,8 @@ func TestCommandSide_AddLoginPolicy(t *testing.T) {
HidePasswordReset: true,
IgnoreUnknownUsernames: true,
AllowDomainDiscovery: true,
+ DisableLoginWithEmail: true,
+ DisableLoginWithPhone: true,
PasswordlessType: domain.PasswordlessTypeAllowed,
DefaultRedirectURI: "https://example.com/redirect",
PasswordCheckLifetime: time.Hour * 1,
@@ -240,6 +211,8 @@ func TestCommandSide_AddLoginPolicy(t *testing.T) {
true,
true,
true,
+ true,
+ true,
domain.PasswordlessTypeAllowed,
"https://example.com/redirect",
time.Hour*1,
@@ -268,7 +241,7 @@ func TestCommandSide_AddLoginPolicy(t *testing.T) {
args: args{
ctx: context.Background(),
orgID: "org1",
- policy: &domain.LoginPolicy{
+ policy: &AddLoginPolicy{
AllowRegister: true,
AllowUsernamePassword: true,
AllowExternalIDP: true,
@@ -276,6 +249,8 @@ func TestCommandSide_AddLoginPolicy(t *testing.T) {
HidePasswordReset: true,
IgnoreUnknownUsernames: true,
AllowDomainDiscovery: true,
+ DisableLoginWithEmail: true,
+ DisableLoginWithPhone: true,
PasswordlessType: domain.PasswordlessTypeAllowed,
DefaultRedirectURI: "https://example.com/redirect",
PasswordCheckLifetime: time.Hour * 1,
@@ -288,25 +263,8 @@ func TestCommandSide_AddLoginPolicy(t *testing.T) {
},
},
res: res{
- want: &domain.LoginPolicy{
- ObjectRoot: models.ObjectRoot{
- AggregateID: "org1",
- ResourceOwner: "org1",
- },
- AllowRegister: true,
- AllowUsernamePassword: true,
- AllowExternalIDP: true,
- ForceMFA: true,
- HidePasswordReset: true,
- IgnoreUnknownUsernames: true,
- AllowDomainDiscovery: true,
- PasswordlessType: domain.PasswordlessTypeAllowed,
- DefaultRedirectURI: "https://example.com/redirect",
- PasswordCheckLifetime: time.Hour * 1,
- ExternalLoginCheckLifetime: time.Hour * 2,
- MFAInitSkipLifetime: time.Hour * 3,
- SecondFactorCheckLifetime: time.Hour * 4,
- MultiFactorCheckLifetime: time.Hour * 5,
+ want: &domain.ObjectDetails{
+ ResourceOwner: "org1",
},
},
},
@@ -322,7 +280,7 @@ func TestCommandSide_AddLoginPolicy(t *testing.T) {
args: args{
ctx: context.Background(),
orgID: "org1",
- policy: &domain.LoginPolicy{
+ policy: &AddLoginPolicy{
AllowRegister: true,
AllowUsernamePassword: true,
AllowExternalIDP: true,
@@ -330,6 +288,8 @@ func TestCommandSide_AddLoginPolicy(t *testing.T) {
HidePasswordReset: true,
IgnoreUnknownUsernames: true,
AllowDomainDiscovery: true,
+ DisableLoginWithEmail: true,
+ DisableLoginWithPhone: true,
PasswordlessType: domain.PasswordlessTypeAllowed,
DefaultRedirectURI: "https://example.com/redirect",
PasswordCheckLifetime: time.Hour * 1,
@@ -337,10 +297,10 @@ func TestCommandSide_AddLoginPolicy(t *testing.T) {
MFAInitSkipLifetime: time.Hour * 3,
SecondFactorCheckLifetime: time.Hour * 4,
MultiFactorCheckLifetime: time.Hour * 5,
- IDPProviders: []*domain.IDPProvider{
+ IDPProviders: []*AddLoginPolicyIDP{
{
- Type: domain.IdentityProviderTypeSystem,
- IDPConfigID: "invalid",
+ Type: domain.IdentityProviderTypeSystem,
+ ConfigID: "invalid",
},
},
},
@@ -379,6 +339,8 @@ func TestCommandSide_AddLoginPolicy(t *testing.T) {
true,
true,
true,
+ true,
+ true,
domain.PasswordlessTypeAllowed,
"https://example.com/redirect",
time.Hour*1,
@@ -402,7 +364,7 @@ func TestCommandSide_AddLoginPolicy(t *testing.T) {
args: args{
ctx: context.Background(),
orgID: "org1",
- policy: &domain.LoginPolicy{
+ policy: &AddLoginPolicy{
AllowRegister: true,
AllowUsernamePassword: true,
AllowExternalIDP: true,
@@ -410,6 +372,8 @@ func TestCommandSide_AddLoginPolicy(t *testing.T) {
HidePasswordReset: true,
IgnoreUnknownUsernames: true,
AllowDomainDiscovery: true,
+ DisableLoginWithEmail: true,
+ DisableLoginWithPhone: true,
PasswordlessType: domain.PasswordlessTypeAllowed,
DefaultRedirectURI: "https://example.com/redirect",
PasswordCheckLifetime: time.Hour * 1,
@@ -417,34 +381,17 @@ func TestCommandSide_AddLoginPolicy(t *testing.T) {
MFAInitSkipLifetime: time.Hour * 3,
SecondFactorCheckLifetime: time.Hour * 4,
MultiFactorCheckLifetime: time.Hour * 5,
- IDPProviders: []*domain.IDPProvider{
+ IDPProviders: []*AddLoginPolicyIDP{
{
- Type: domain.IdentityProviderTypeSystem,
- IDPConfigID: "config1",
+ Type: domain.IdentityProviderTypeSystem,
+ ConfigID: "config1",
},
},
},
},
res: res{
- want: &domain.LoginPolicy{
- ObjectRoot: models.ObjectRoot{
- AggregateID: "org1",
- ResourceOwner: "org1",
- },
- AllowRegister: true,
- AllowUsernamePassword: true,
- AllowExternalIDP: true,
- ForceMFA: true,
- HidePasswordReset: true,
- IgnoreUnknownUsernames: true,
- AllowDomainDiscovery: true,
- PasswordlessType: domain.PasswordlessTypeAllowed,
- DefaultRedirectURI: "https://example.com/redirect",
- PasswordCheckLifetime: time.Hour * 1,
- ExternalLoginCheckLifetime: time.Hour * 2,
- MFAInitSkipLifetime: time.Hour * 3,
- SecondFactorCheckLifetime: time.Hour * 4,
- MultiFactorCheckLifetime: time.Hour * 5,
+ want: &domain.ObjectDetails{
+ ResourceOwner: "org1",
},
},
},
@@ -475,10 +422,10 @@ func TestCommandSide_ChangeLoginPolicy(t *testing.T) {
type args struct {
ctx context.Context
orgID string
- policy *domain.LoginPolicy
+ policy *ChangeLoginPolicy
}
type res struct {
- want *domain.LoginPolicy
+ want *domain.ObjectDetails
err func(error) bool
}
tests := []struct {
@@ -487,30 +434,6 @@ func TestCommandSide_ChangeLoginPolicy(t *testing.T) {
args args
res res
}{
- {
- name: "org id missing, invalid argument error",
- fields: fields{
- eventstore: eventstoreExpect(
- t,
- ),
- },
- args: args{
- ctx: context.Background(),
- policy: &domain.LoginPolicy{
- AllowRegister: true,
- AllowUsernamePassword: true,
- AllowExternalIDP: true,
- ForceMFA: true,
- IgnoreUnknownUsernames: true,
- AllowDomainDiscovery: true,
- PasswordlessType: domain.PasswordlessTypeAllowed,
- DefaultRedirectURI: "https://example.com/redirect",
- },
- },
- res: res{
- err: caos_errs.IsErrorInvalidArgument,
- },
- },
{
name: "loginpolicy not existing, not found error",
fields: fields{
@@ -522,13 +445,15 @@ func TestCommandSide_ChangeLoginPolicy(t *testing.T) {
args: args{
ctx: context.Background(),
orgID: "org1",
- policy: &domain.LoginPolicy{
+ policy: &ChangeLoginPolicy{
AllowRegister: true,
AllowUsernamePassword: true,
AllowExternalIDP: true,
ForceMFA: true,
IgnoreUnknownUsernames: true,
AllowDomainDiscovery: true,
+ DisableLoginWithEmail: true,
+ DisableLoginWithPhone: true,
PasswordlessType: domain.PasswordlessTypeAllowed,
DefaultRedirectURI: "https://example.com/redirect",
},
@@ -553,6 +478,8 @@ func TestCommandSide_ChangeLoginPolicy(t *testing.T) {
true,
true,
true,
+ true,
+ true,
domain.PasswordlessTypeAllowed,
"https://example.com/redirect",
time.Hour*1,
@@ -568,7 +495,7 @@ func TestCommandSide_ChangeLoginPolicy(t *testing.T) {
args: args{
ctx: context.Background(),
orgID: "org1",
- policy: &domain.LoginPolicy{
+ policy: &ChangeLoginPolicy{
AllowRegister: true,
AllowUsernamePassword: true,
AllowExternalIDP: true,
@@ -576,6 +503,8 @@ func TestCommandSide_ChangeLoginPolicy(t *testing.T) {
HidePasswordReset: true,
IgnoreUnknownUsernames: true,
AllowDomainDiscovery: true,
+ DisableLoginWithEmail: true,
+ DisableLoginWithPhone: true,
PasswordlessType: domain.PasswordlessTypeAllowed,
DefaultRedirectURI: "https://example.com/redirect",
PasswordCheckLifetime: time.Hour * 1,
@@ -605,6 +534,8 @@ func TestCommandSide_ChangeLoginPolicy(t *testing.T) {
true,
true,
true,
+ true,
+ true,
domain.PasswordlessTypeAllowed,
"https://example.com/redirect",
time.Hour*1,
@@ -627,6 +558,8 @@ func TestCommandSide_ChangeLoginPolicy(t *testing.T) {
false,
false,
false,
+ false,
+ false,
domain.PasswordlessTypeNotAllowed,
"",
&duration10,
@@ -643,13 +576,15 @@ func TestCommandSide_ChangeLoginPolicy(t *testing.T) {
args: args{
ctx: context.Background(),
orgID: "org1",
- policy: &domain.LoginPolicy{
+ policy: &ChangeLoginPolicy{
AllowRegister: false,
AllowUsernamePassword: false,
AllowExternalIDP: false,
ForceMFA: false,
IgnoreUnknownUsernames: false,
AllowDomainDiscovery: false,
+ DisableLoginWithEmail: false,
+ DisableLoginWithPhone: false,
PasswordlessType: domain.PasswordlessTypeNotAllowed,
DefaultRedirectURI: "",
PasswordCheckLifetime: time.Hour * 10,
@@ -660,25 +595,8 @@ func TestCommandSide_ChangeLoginPolicy(t *testing.T) {
},
},
res: res{
- want: &domain.LoginPolicy{
- ObjectRoot: models.ObjectRoot{
- AggregateID: "org1",
- ResourceOwner: "org1",
- },
- AllowRegister: false,
- AllowUsernamePassword: false,
- AllowExternalIDP: false,
- ForceMFA: false,
- HidePasswordReset: false,
- IgnoreUnknownUsernames: false,
- AllowDomainDiscovery: false,
- PasswordlessType: domain.PasswordlessTypeNotAllowed,
- DefaultRedirectURI: "",
- PasswordCheckLifetime: time.Hour * 10,
- ExternalLoginCheckLifetime: time.Hour * 20,
- MFAInitSkipLifetime: time.Hour * 30,
- SecondFactorCheckLifetime: time.Hour * 40,
- MultiFactorCheckLifetime: time.Hour * 50,
+ want: &domain.ObjectDetails{
+ ResourceOwner: "org1",
},
},
},
@@ -766,6 +684,8 @@ func TestCommandSide_RemoveLoginPolicy(t *testing.T) {
true,
true,
true,
+ true,
+ true,
domain.PasswordlessTypeAllowed,
"",
time.Hour*1,
@@ -907,6 +827,8 @@ func TestCommandSide_AddIDPProviderLoginPolicy(t *testing.T) {
true,
true,
true,
+ true,
+ true,
domain.PasswordlessTypeAllowed,
"",
time.Hour*1,
@@ -949,6 +871,8 @@ func TestCommandSide_AddIDPProviderLoginPolicy(t *testing.T) {
true,
true,
true,
+ true,
+ true,
domain.PasswordlessTypeAllowed,
"",
time.Hour*1,
@@ -1011,6 +935,8 @@ func TestCommandSide_AddIDPProviderLoginPolicy(t *testing.T) {
true,
true,
true,
+ true,
+ true,
domain.PasswordlessTypeAllowed,
"",
time.Hour*1,
@@ -1176,6 +1102,8 @@ func TestCommandSide_RemoveIDPProviderLoginPolicy(t *testing.T) {
true,
true,
true,
+ true,
+ true,
domain.PasswordlessTypeAllowed,
"",
time.Hour*1,
@@ -1218,6 +1146,8 @@ func TestCommandSide_RemoveIDPProviderLoginPolicy(t *testing.T) {
true,
true,
true,
+ true,
+ true,
domain.PasswordlessTypeAllowed,
"",
time.Hour*1,
@@ -1272,6 +1202,8 @@ func TestCommandSide_RemoveIDPProviderLoginPolicy(t *testing.T) {
true,
true,
true,
+ true,
+ true,
domain.PasswordlessTypeAllowed,
"",
time.Hour*1,
@@ -1333,6 +1265,8 @@ func TestCommandSide_RemoveIDPProviderLoginPolicy(t *testing.T) {
true,
true,
true,
+ true,
+ true,
domain.PasswordlessTypeAllowed,
"",
time.Hour*1,
@@ -1402,6 +1336,8 @@ func TestCommandSide_RemoveIDPProviderLoginPolicy(t *testing.T) {
true,
true,
true,
+ true,
+ true,
domain.PasswordlessTypeAllowed,
"",
time.Hour*1,
@@ -2020,7 +1956,8 @@ func TestCommandSide_RemoveMultiFactorLoginPolicy(t *testing.T) {
}
}
-func newLoginPolicyChangedEvent(ctx context.Context, orgID string, usernamePassword, register, externalIDP, mfa, passwordReset, ignoreUnknownUsernames, allowDomainDiscovery bool,
+func newLoginPolicyChangedEvent(ctx context.Context, orgID string,
+ usernamePassword, register, externalIDP, mfa, passwordReset, ignoreUnknownUsernames, allowDomainDiscovery, disableLoginWithEmail, disableLoginWithPhone bool,
passwordlessType domain.PasswordlessType,
redirectURI string,
passwordLifetime, externalLoginLifetime, mfaInitSkipLifetime, secondFactorLifetime, multiFactorLifetime *time.Duration) *org.LoginPolicyChangedEvent {
@@ -2034,6 +1971,8 @@ func newLoginPolicyChangedEvent(ctx context.Context, orgID string, usernamePassw
policy.ChangeAllowDomainDiscovery(allowDomainDiscovery),
policy.ChangePasswordlessType(passwordlessType),
policy.ChangeDefaultRedirectURI(redirectURI),
+ policy.ChangeDisableLoginWithEmail(disableLoginWithEmail),
+ policy.ChangeDisableLoginWithPhone(disableLoginWithPhone),
}
if passwordLifetime != nil {
changes = append(changes, policy.ChangePasswordCheckLifetime(*passwordLifetime))
diff --git a/internal/command/policy_login_model.go b/internal/command/policy_login_model.go
index 1c49fc6ab..50ece0f2f 100644
--- a/internal/command/policy_login_model.go
+++ b/internal/command/policy_login_model.go
@@ -18,6 +18,8 @@ type LoginPolicyWriteModel struct {
HidePasswordReset bool
IgnoreUnknownUsernames bool
AllowDomainDiscovery bool
+ DisableLoginWithEmail bool
+ DisableLoginWithPhone bool
PasswordlessType domain.PasswordlessType
DefaultRedirectURI string
PasswordCheckLifetime time.Duration
@@ -40,6 +42,8 @@ func (wm *LoginPolicyWriteModel) Reduce() error {
wm.HidePasswordReset = e.HidePasswordReset
wm.IgnoreUnknownUsernames = e.IgnoreUnknownUsernames
wm.AllowDomainDiscovery = e.AllowDomainDiscovery
+ wm.DisableLoginWithEmail = e.DisableLoginWithEmail
+ wm.DisableLoginWithPhone = e.DisableLoginWithPhone
wm.DefaultRedirectURI = e.DefaultRedirectURI
wm.PasswordCheckLifetime = e.PasswordCheckLifetime
wm.ExternalLoginCheckLifetime = e.ExternalLoginCheckLifetime
@@ -90,9 +94,19 @@ func (wm *LoginPolicyWriteModel) Reduce() error {
if e.MultiFactorCheckLifetime != nil {
wm.MultiFactorCheckLifetime = *e.MultiFactorCheckLifetime
}
+ if e.DisableLoginWithEmail != nil {
+ wm.DisableLoginWithEmail = *e.DisableLoginWithEmail
+ }
+ if e.DisableLoginWithPhone != nil {
+ wm.DisableLoginWithPhone = *e.DisableLoginWithPhone
+ }
case *policy.LoginPolicyRemovedEvent:
wm.State = domain.PolicyStateRemoved
}
}
return wm.WriteModel.Reduce()
}
+
+func (wm *LoginPolicyWriteModel) Exists() bool {
+ return wm.State.Exists()
+}
diff --git a/internal/command/user_human_password_test.go b/internal/command/user_human_password_test.go
index 3162aeedc..883959f40 100644
--- a/internal/command/user_human_password_test.go
+++ b/internal/command/user_human_password_test.go
@@ -1158,6 +1158,8 @@ func TestCommandSide_CheckPassword(t *testing.T) {
false,
false,
false,
+ false,
+ false,
domain.PasswordlessTypeNotAllowed,
"",
time.Hour*1,
@@ -1196,6 +1198,8 @@ func TestCommandSide_CheckPassword(t *testing.T) {
false,
false,
false,
+ false,
+ false,
domain.PasswordlessTypeNotAllowed,
"",
time.Hour*1,
@@ -1235,6 +1239,8 @@ func TestCommandSide_CheckPassword(t *testing.T) {
false,
false,
false,
+ false,
+ false,
domain.PasswordlessTypeNotAllowed,
"",
time.Hour*1,
@@ -1290,6 +1296,8 @@ func TestCommandSide_CheckPassword(t *testing.T) {
false,
false,
false,
+ false,
+ false,
domain.PasswordlessTypeNotAllowed,
"",
time.Hour*1,
@@ -1379,6 +1387,8 @@ func TestCommandSide_CheckPassword(t *testing.T) {
false,
false,
false,
+ false,
+ false,
domain.PasswordlessTypeNotAllowed,
"",
time.Hour*1,
@@ -1475,6 +1485,8 @@ func TestCommandSide_CheckPassword(t *testing.T) {
false,
false,
false,
+ false,
+ false,
domain.PasswordlessTypeNotAllowed,
"",
time.Hour*1,
diff --git a/internal/command/user_human_test.go b/internal/command/user_human_test.go
index 2558e5945..c19beaac0 100644
--- a/internal/command/user_human_test.go
+++ b/internal/command/user_human_test.go
@@ -1680,6 +1680,8 @@ func TestCommandSide_RegisterHuman(t *testing.T) {
false,
false,
false,
+ false,
+ false,
domain.PasswordlessTypeNotAllowed,
"",
time.Hour*1,
@@ -1747,6 +1749,8 @@ func TestCommandSide_RegisterHuman(t *testing.T) {
false,
false,
false,
+ false,
+ false,
domain.PasswordlessTypeNotAllowed,
"",
time.Hour*1,
@@ -1814,6 +1818,8 @@ func TestCommandSide_RegisterHuman(t *testing.T) {
false,
false,
false,
+ false,
+ false,
domain.PasswordlessTypeNotAllowed,
"",
time.Hour*1,
@@ -1898,6 +1904,8 @@ func TestCommandSide_RegisterHuman(t *testing.T) {
false,
false,
false,
+ false,
+ false,
domain.PasswordlessTypeNotAllowed,
"",
time.Hour*1,
@@ -2040,6 +2048,8 @@ func TestCommandSide_RegisterHuman(t *testing.T) {
false,
false,
false,
+ false,
+ false,
domain.PasswordlessTypeNotAllowed,
"",
time.Hour*1,
@@ -2150,6 +2160,8 @@ func TestCommandSide_RegisterHuman(t *testing.T) {
false,
false,
false,
+ false,
+ false,
domain.PasswordlessTypeNotAllowed,
"",
time.Hour*1,
@@ -2254,6 +2266,8 @@ func TestCommandSide_RegisterHuman(t *testing.T) {
false,
false,
false,
+ false,
+ false,
domain.PasswordlessTypeNotAllowed,
"",
time.Hour*1,
@@ -2380,6 +2394,8 @@ func TestCommandSide_RegisterHuman(t *testing.T) {
false,
false,
false,
+ false,
+ false,
domain.PasswordlessTypeNotAllowed,
"",
time.Hour*1,
diff --git a/internal/domain/idp_config.go b/internal/domain/idp_config.go
index 86dde0d18..762d0da5d 100644
--- a/internal/domain/idp_config.go
+++ b/internal/domain/idp_config.go
@@ -101,7 +101,7 @@ func (s IDPConfigState) Valid() bool {
}
func (s IDPConfigState) Exists() bool {
- return s != IDPConfigStateUnspecified || s == IDPConfigStateRemoved
+ return s != IDPConfigStateUnspecified && s != IDPConfigStateRemoved
}
type IDPConfigStylingType int32
diff --git a/internal/domain/policy_login.go b/internal/domain/policy_login.go
index b265d8709..823a51220 100644
--- a/internal/domain/policy_login.go
+++ b/internal/domain/policy_login.go
@@ -28,6 +28,8 @@ type LoginPolicy struct {
MFAInitSkipLifetime time.Duration
SecondFactorCheckLifetime time.Duration
MultiFactorCheckLifetime time.Duration
+ DisableLoginWithEmail bool
+ DisableLoginWithPhone bool
}
func ValidateDefaultRedirectURI(rawURL string) bool {
diff --git a/internal/eventstore/handler/crdb/statement.go b/internal/eventstore/handler/crdb/statement.go
index 1549289bc..8601630cd 100644
--- a/internal/eventstore/handler/crdb/statement.go
+++ b/internal/eventstore/handler/crdb/statement.go
@@ -123,7 +123,7 @@ func getUpdateCols(cols, conflictTarget []string) (updateCols, updateVals []stri
func NewUpdateStatement(event eventstore.Event, values []handler.Column, conditions []handler.Condition, opts ...execOption) *handler.Statement {
cols, params, args := columnsToQuery(values)
- wheres, whereArgs := conditionsToWhere(conditions, len(params))
+ wheres, whereArgs := conditionsToWhere(conditions, len(args))
args = append(args, whereArgs...)
config := execConfig{
@@ -278,6 +278,13 @@ func NewArrayIntersectCol(column string, value interface{}) handler.Column {
}
}
+func NewCopyCol(column, from string) handler.Column {
+ return handler.Column{
+ Name: column,
+ Value: handler.NewCol(from, nil),
+ }
+}
+
// NewCopyStatement creates a new upsert statement which updates a column from an existing row
// cols represent the columns which are objective to change.
// if the value of a col is empty the data will be copied from the selected row
@@ -359,15 +366,22 @@ func columnsToQuery(cols []handler.Column) (names []string, parameters []string,
names = make([]string, len(cols))
values = make([]interface{}, len(cols))
parameters = make([]string, len(cols))
+ var parameterIndex int
for i, col := range cols {
names[i] = col.Name
- values[i] = col.Value
- parameters[i] = "$" + strconv.Itoa(i+1)
+ if c, ok := col.Value.(handler.Column); ok {
+ parameters[i] = c.Name
+ continue
+ } else {
+ values[parameterIndex] = col.Value
+ }
+ parameters[i] = "$" + strconv.Itoa(parameterIndex+1)
if col.ParameterOpt != nil {
parameters[i] = col.ParameterOpt(parameters[i])
}
+ parameterIndex++
}
- return names, parameters, values
+ return names, parameters, values[:parameterIndex]
}
func conditionsToWhere(cols []handler.Condition, paramOffset int) (wheres []string, values []interface{}) {
diff --git a/internal/eventstore/handler/crdb/statement_test.go b/internal/eventstore/handler/crdb/statement_test.go
index efc270493..fd9f451d9 100644
--- a/internal/eventstore/handler/crdb/statement_test.go
+++ b/internal/eventstore/handler/crdb/statement_test.go
@@ -1352,6 +1352,32 @@ func Test_columnsToQuery(t *testing.T) {
values: []interface{}{1, 3.14},
},
},
+ {
+ name: "with copy column",
+ args: args{
+ cols: []handler.Column{
+ {
+ Name: "col1",
+ Value: 1,
+ },
+ {
+ Name: "col2",
+ Value: handler.Column{
+ Name: "col1",
+ },
+ },
+ {
+ Name: "col3",
+ Value: "something",
+ },
+ },
+ },
+ want: want{
+ names: []string{"col1", "col2", "col3"},
+ params: []string{"$1", "col1", "$2"},
+ values: []interface{}{1, "something"},
+ },
+ },
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
diff --git a/internal/notification/projection.go b/internal/notification/projection.go
index 78fbfb3f0..9f0aefe5a 100644
--- a/internal/notification/projection.go
+++ b/internal/notification/projection.go
@@ -169,7 +169,7 @@ func (p *notificationsProjection) reduceInitCodeAdded(event eventstore.Event) (*
return nil, err
}
- notifyUser, err := p.queries.GeNotifyUser(ctx, true, e.Aggregate().ID)
+ notifyUser, err := p.queries.GetNotifyUserByID(ctx, true, e.Aggregate().ID)
if err != nil {
return nil, err
}
@@ -232,7 +232,7 @@ func (p *notificationsProjection) reduceEmailCodeAdded(event eventstore.Event) (
return nil, err
}
- notifyUser, err := p.queries.GeNotifyUser(ctx, true, e.Aggregate().ID)
+ notifyUser, err := p.queries.GetNotifyUserByID(ctx, true, e.Aggregate().ID)
if err != nil {
return nil, err
}
@@ -295,7 +295,7 @@ func (p *notificationsProjection) reducePasswordCodeAdded(event eventstore.Event
return nil, err
}
- notifyUser, err := p.queries.GeNotifyUser(ctx, true, e.Aggregate().ID)
+ notifyUser, err := p.queries.GetNotifyUserByID(ctx, true, e.Aggregate().ID)
if err != nil {
return nil, err
}
@@ -366,7 +366,7 @@ func (p *notificationsProjection) reduceDomainClaimed(event eventstore.Event) (*
return nil, err
}
- notifyUser, err := p.queries.GeNotifyUser(ctx, true, e.Aggregate().ID)
+ notifyUser, err := p.queries.GetNotifyUserByID(ctx, true, e.Aggregate().ID)
if err != nil {
return nil, err
}
@@ -427,7 +427,7 @@ func (p *notificationsProjection) reducePasswordlessCodeRequested(event eventsto
return nil, err
}
- notifyUser, err := p.queries.GeNotifyUser(ctx, true, e.Aggregate().ID)
+ notifyUser, err := p.queries.GetNotifyUserByID(ctx, true, e.Aggregate().ID)
if err != nil {
return nil, err
}
@@ -485,7 +485,7 @@ func (p *notificationsProjection) reducePhoneCodeAdded(event eventstore.Event) (
return nil, err
}
- notifyUser, err := p.queries.GeNotifyUser(ctx, true, e.Aggregate().ID)
+ notifyUser, err := p.queries.GetNotifyUserByID(ctx, true, e.Aggregate().ID)
if err != nil {
return nil, err
}
diff --git a/internal/query/iam_member_test.go b/internal/query/iam_member_test.go
index e4755bb2a..52877242c 100644
--- a/internal/query/iam_member_test.go
+++ b/internal/query/iam_member_test.go
@@ -20,18 +20,18 @@ var (
", members.user_id" +
", members.roles" +
", projections.login_names.login_name" +
- ", projections.users3_humans.email" +
- ", projections.users3_humans.first_name" +
- ", projections.users3_humans.last_name" +
- ", projections.users3_humans.display_name" +
- ", projections.users3_machines.name" +
- ", projections.users3_humans.avatar_key" +
+ ", projections.users4_humans.email" +
+ ", projections.users4_humans.first_name" +
+ ", projections.users4_humans.last_name" +
+ ", projections.users4_humans.display_name" +
+ ", projections.users4_machines.name" +
+ ", projections.users4_humans.avatar_key" +
", COUNT(*) OVER () " +
"FROM projections.instance_members2 AS members " +
- "LEFT JOIN projections.users3_humans " +
- "ON members.user_id = projections.users3_humans.user_id " +
- "LEFT JOIN projections.users3_machines " +
- "ON members.user_id = projections.users3_machines.user_id " +
+ "LEFT JOIN projections.users4_humans " +
+ "ON members.user_id = projections.users4_humans.user_id " +
+ "LEFT JOIN projections.users4_machines " +
+ "ON members.user_id = projections.users4_machines.user_id " +
"LEFT JOIN projections.login_names " +
"ON members.user_id = projections.login_names.user_id " +
"WHERE projections.login_names.is_primary = $1")
diff --git a/internal/query/login_policy.go b/internal/query/login_policy.go
index bd7326a3b..d25117e8d 100644
--- a/internal/query/login_policy.go
+++ b/internal/query/login_policy.go
@@ -31,6 +31,8 @@ type LoginPolicy struct {
HidePasswordReset bool
IgnoreUnknownUsernames bool
AllowDomainDiscovery bool
+ DisableLoginWithEmail bool
+ DisableLoginWithPhone bool
DefaultRedirectURI string
PasswordCheckLifetime time.Duration
ExternalLoginCheckLifetime time.Duration
@@ -118,6 +120,14 @@ var (
name: projection.AllowDomainDiscovery,
table: loginPolicyTable,
}
+ LoginPolicyColumnDisableLoginWithEmail = Column{
+ name: projection.DisableLoginWithEmail,
+ table: loginPolicyTable,
+ }
+ LoginPolicyColumnDisableLoginWithPhone = Column{
+ name: projection.DisableLoginWithPhone,
+ table: loginPolicyTable,
+ }
LoginPolicyColumnDefaultRedirectURI = Column{
name: projection.DefaultRedirectURI,
table: loginPolicyTable,
@@ -311,6 +321,8 @@ func prepareLoginPolicyQuery() (sq.SelectBuilder, func(*sql.Rows) (*LoginPolicy,
LoginPolicyColumnHidePasswordReset.identifier(),
LoginPolicyColumnIgnoreUnknownUsernames.identifier(),
LoginPolicyColumnAllowDomainDiscovery.identifier(),
+ LoginPolicyColumnDisableLoginWithEmail.identifier(),
+ LoginPolicyColumnDisableLoginWithPhone.identifier(),
LoginPolicyColumnDefaultRedirectURI.identifier(),
LoginPolicyColumnPasswordCheckLifetime.identifier(),
LoginPolicyColumnExternalLoginCheckLifetime.identifier(),
@@ -350,6 +362,8 @@ func prepareLoginPolicyQuery() (sq.SelectBuilder, func(*sql.Rows) (*LoginPolicy,
&p.HidePasswordReset,
&p.IgnoreUnknownUsernames,
&p.AllowDomainDiscovery,
+ &p.DisableLoginWithEmail,
+ &p.DisableLoginWithPhone,
&defaultRedirectURI,
&p.PasswordCheckLifetime,
&p.ExternalLoginCheckLifetime,
diff --git a/internal/query/login_policy_test.go b/internal/query/login_policy_test.go
index 221e4024f..c5b05ed03 100644
--- a/internal/query/login_policy_test.go
+++ b/internal/query/login_policy_test.go
@@ -30,33 +30,35 @@ func Test_LoginPolicyPrepares(t *testing.T) {
prepare: prepareLoginPolicyQuery,
want: want{
sqlExpectations: mockQueries(
- regexp.QuoteMeta(`SELECT projections.login_policies2.aggregate_id,`+
- ` projections.login_policies2.creation_date,`+
- ` projections.login_policies2.change_date,`+
- ` projections.login_policies2.sequence,`+
- ` projections.login_policies2.allow_register,`+
- ` projections.login_policies2.allow_username_password,`+
- ` projections.login_policies2.allow_external_idps,`+
- ` projections.login_policies2.force_mfa,`+
- ` projections.login_policies2.second_factors,`+
- ` projections.login_policies2.multi_factors,`+
- ` projections.login_policies2.passwordless_type,`+
- ` projections.login_policies2.is_default,`+
- ` projections.login_policies2.hide_password_reset,`+
- ` projections.login_policies2.ignore_unknown_usernames,`+
- ` projections.login_policies2.allow_domain_discovery,`+
- ` projections.login_policies2.default_redirect_uri,`+
- ` projections.login_policies2.password_check_lifetime,`+
- ` projections.login_policies2.external_login_check_lifetime,`+
- ` projections.login_policies2.mfa_init_skip_lifetime,`+
- ` projections.login_policies2.second_factor_check_lifetime,`+
- ` projections.login_policies2.multi_factor_check_lifetime,`+
+ regexp.QuoteMeta(`SELECT projections.login_policies3.aggregate_id,`+
+ ` projections.login_policies3.creation_date,`+
+ ` projections.login_policies3.change_date,`+
+ ` projections.login_policies3.sequence,`+
+ ` projections.login_policies3.allow_register,`+
+ ` projections.login_policies3.allow_username_password,`+
+ ` projections.login_policies3.allow_external_idps,`+
+ ` projections.login_policies3.force_mfa,`+
+ ` projections.login_policies3.second_factors,`+
+ ` projections.login_policies3.multi_factors,`+
+ ` projections.login_policies3.passwordless_type,`+
+ ` projections.login_policies3.is_default,`+
+ ` projections.login_policies3.hide_password_reset,`+
+ ` projections.login_policies3.ignore_unknown_usernames,`+
+ ` projections.login_policies3.allow_domain_discovery,`+
+ ` projections.login_policies3.disable_login_with_email,`+
+ ` projections.login_policies3.disable_login_with_phone,`+
+ ` projections.login_policies3.default_redirect_uri,`+
+ ` projections.login_policies3.password_check_lifetime,`+
+ ` projections.login_policies3.external_login_check_lifetime,`+
+ ` projections.login_policies3.mfa_init_skip_lifetime,`+
+ ` projections.login_policies3.second_factor_check_lifetime,`+
+ ` projections.login_policies3.multi_factor_check_lifetime,`+
` projections.idp_login_policy_links3.idp_id,`+
` projections.idps2.name,`+
` projections.idps2.type`+
- ` FROM projections.login_policies2`+
+ ` FROM projections.login_policies3`+
` LEFT JOIN projections.idp_login_policy_links3 ON `+
- ` projections.login_policies2.aggregate_id = projections.idp_login_policy_links3.aggregate_id`+
+ ` projections.login_policies3.aggregate_id = projections.idp_login_policy_links3.aggregate_id`+
` LEFT JOIN projections.idps2 ON`+
` projections.idp_login_policy_links3.idp_id = projections.idps2.id`),
nil,
@@ -76,33 +78,35 @@ func Test_LoginPolicyPrepares(t *testing.T) {
prepare: prepareLoginPolicyQuery,
want: want{
sqlExpectations: mockQuery(
- regexp.QuoteMeta(`SELECT projections.login_policies2.aggregate_id,`+
- ` projections.login_policies2.creation_date,`+
- ` projections.login_policies2.change_date,`+
- ` projections.login_policies2.sequence,`+
- ` projections.login_policies2.allow_register,`+
- ` projections.login_policies2.allow_username_password,`+
- ` projections.login_policies2.allow_external_idps,`+
- ` projections.login_policies2.force_mfa,`+
- ` projections.login_policies2.second_factors,`+
- ` projections.login_policies2.multi_factors,`+
- ` projections.login_policies2.passwordless_type,`+
- ` projections.login_policies2.is_default,`+
- ` projections.login_policies2.hide_password_reset,`+
- ` projections.login_policies2.ignore_unknown_usernames,`+
- ` projections.login_policies2.allow_domain_discovery,`+
- ` projections.login_policies2.default_redirect_uri,`+
- ` projections.login_policies2.password_check_lifetime,`+
- ` projections.login_policies2.external_login_check_lifetime,`+
- ` projections.login_policies2.mfa_init_skip_lifetime,`+
- ` projections.login_policies2.second_factor_check_lifetime,`+
- ` projections.login_policies2.multi_factor_check_lifetime,`+
+ regexp.QuoteMeta(`SELECT projections.login_policies3.aggregate_id,`+
+ ` projections.login_policies3.creation_date,`+
+ ` projections.login_policies3.change_date,`+
+ ` projections.login_policies3.sequence,`+
+ ` projections.login_policies3.allow_register,`+
+ ` projections.login_policies3.allow_username_password,`+
+ ` projections.login_policies3.allow_external_idps,`+
+ ` projections.login_policies3.force_mfa,`+
+ ` projections.login_policies3.second_factors,`+
+ ` projections.login_policies3.multi_factors,`+
+ ` projections.login_policies3.passwordless_type,`+
+ ` projections.login_policies3.is_default,`+
+ ` projections.login_policies3.hide_password_reset,`+
+ ` projections.login_policies3.ignore_unknown_usernames,`+
+ ` projections.login_policies3.allow_domain_discovery,`+
+ ` projections.login_policies3.disable_login_with_email,`+
+ ` projections.login_policies3.disable_login_with_phone,`+
+ ` projections.login_policies3.default_redirect_uri,`+
+ ` projections.login_policies3.password_check_lifetime,`+
+ ` projections.login_policies3.external_login_check_lifetime,`+
+ ` projections.login_policies3.mfa_init_skip_lifetime,`+
+ ` projections.login_policies3.second_factor_check_lifetime,`+
+ ` projections.login_policies3.multi_factor_check_lifetime,`+
` projections.idp_login_policy_links3.idp_id,`+
` projections.idps2.name,`+
` projections.idps2.type`+
- ` FROM projections.login_policies2`+
+ ` FROM projections.login_policies3`+
` LEFT JOIN projections.idp_login_policy_links3 ON `+
- ` projections.login_policies2.aggregate_id = projections.idp_login_policy_links3.aggregate_id`+
+ ` projections.login_policies3.aggregate_id = projections.idp_login_policy_links3.aggregate_id`+
` LEFT JOIN projections.idps2 ON`+
` projections.idp_login_policy_links3.idp_id = projections.idps2.id`),
[]string{
@@ -121,6 +125,8 @@ func Test_LoginPolicyPrepares(t *testing.T) {
"hide_password_reset",
"ignore_unknown_usernames",
"allow_domain_discovery",
+ "disable_login_with_email",
+ "disable_login_with_phone",
"default_redirect_uri",
"password_check_lifetime",
"external_login_check_lifetime",
@@ -147,6 +153,8 @@ func Test_LoginPolicyPrepares(t *testing.T) {
true,
true,
true,
+ true,
+ true,
"https://example.com/redirect",
time.Hour * 2,
time.Hour * 2,
@@ -175,6 +183,8 @@ func Test_LoginPolicyPrepares(t *testing.T) {
HidePasswordReset: true,
IgnoreUnknownUsernames: true,
AllowDomainDiscovery: true,
+ DisableLoginWithEmail: true,
+ DisableLoginWithPhone: true,
DefaultRedirectURI: "https://example.com/redirect",
PasswordCheckLifetime: time.Hour * 2,
ExternalLoginCheckLifetime: time.Hour * 2,
@@ -195,33 +205,35 @@ func Test_LoginPolicyPrepares(t *testing.T) {
prepare: prepareLoginPolicyQuery,
want: want{
sqlExpectations: mockQueryErr(
- regexp.QuoteMeta(`SELECT projections.login_policies2.aggregate_id,`+
- ` projections.login_policies2.creation_date,`+
- ` projections.login_policies2.change_date,`+
- ` projections.login_policies2.sequence,`+
- ` projections.login_policies2.allow_register,`+
- ` projections.login_policies2.allow_username_password,`+
- ` projections.login_policies2.allow_external_idps,`+
- ` projections.login_policies2.force_mfa,`+
- ` projections.login_policies2.second_factors,`+
- ` projections.login_policies2.multi_factors,`+
- ` projections.login_policies2.passwordless_type,`+
- ` projections.login_policies2.is_default,`+
- ` projections.login_policies2.hide_password_reset,`+
- ` projections.login_policies2.ignore_unknown_usernames,`+
- ` projections.login_policies2.allow_domain_discovery,`+
- ` projections.login_policies2.default_redirect_uri,`+
- ` projections.login_policies2.password_check_lifetime,`+
- ` projections.login_policies2.external_login_check_lifetime,`+
- ` projections.login_policies2.mfa_init_skip_lifetime,`+
- ` projections.login_policies2.second_factor_check_lifetime,`+
- ` projections.login_policies2.multi_factor_check_lifetime,`+
+ regexp.QuoteMeta(`SELECT projections.login_policies3.aggregate_id,`+
+ ` projections.login_policies3.creation_date,`+
+ ` projections.login_policies3.change_date,`+
+ ` projections.login_policies3.sequence,`+
+ ` projections.login_policies3.allow_register,`+
+ ` projections.login_policies3.allow_username_password,`+
+ ` projections.login_policies3.allow_external_idps,`+
+ ` projections.login_policies3.force_mfa,`+
+ ` projections.login_policies3.second_factors,`+
+ ` projections.login_policies3.multi_factors,`+
+ ` projections.login_policies3.passwordless_type,`+
+ ` projections.login_policies3.is_default,`+
+ ` projections.login_policies3.hide_password_reset,`+
+ ` projections.login_policies3.ignore_unknown_usernames,`+
+ ` projections.login_policies3.allow_domain_discovery,`+
+ ` projections.login_policies3.disable_login_with_email,`+
+ ` projections.login_policies3.disable_login_with_phone,`+
+ ` projections.login_policies3.default_redirect_uri,`+
+ ` projections.login_policies3.password_check_lifetime,`+
+ ` projections.login_policies3.external_login_check_lifetime,`+
+ ` projections.login_policies3.mfa_init_skip_lifetime,`+
+ ` projections.login_policies3.second_factor_check_lifetime,`+
+ ` projections.login_policies3.multi_factor_check_lifetime,`+
` projections.idp_login_policy_links3.idp_id,`+
` projections.idps2.name,`+
` projections.idps2.type`+
- ` FROM projections.login_policies2`+
+ ` FROM projections.login_policies3`+
` LEFT JOIN projections.idp_login_policy_links3 ON `+
- ` projections.login_policies2.aggregate_id = projections.idp_login_policy_links3.aggregate_id`+
+ ` projections.login_policies3.aggregate_id = projections.idp_login_policy_links3.aggregate_id`+
` LEFT JOIN projections.idps2 ON`+
` projections.idp_login_policy_links3.idp_id = projections.idps2.id`),
sql.ErrConnDone,
@@ -240,8 +252,8 @@ func Test_LoginPolicyPrepares(t *testing.T) {
prepare: prepareLoginPolicy2FAsQuery,
want: want{
sqlExpectations: mockQuery(
- regexp.QuoteMeta(`SELECT projections.login_policies2.second_factors`+
- ` FROM projections.login_policies2`),
+ regexp.QuoteMeta(`SELECT projections.login_policies3.second_factors`+
+ ` FROM projections.login_policies3`),
[]string{
"second_factors",
},
@@ -261,8 +273,8 @@ func Test_LoginPolicyPrepares(t *testing.T) {
prepare: prepareLoginPolicy2FAsQuery,
want: want{
sqlExpectations: mockQuery(
- regexp.QuoteMeta(`SELECT projections.login_policies2.second_factors`+
- ` FROM projections.login_policies2`),
+ regexp.QuoteMeta(`SELECT projections.login_policies3.second_factors`+
+ ` FROM projections.login_policies3`),
[]string{
"second_factors",
},
@@ -283,8 +295,8 @@ func Test_LoginPolicyPrepares(t *testing.T) {
prepare: prepareLoginPolicy2FAsQuery,
want: want{
sqlExpectations: mockQuery(
- regexp.QuoteMeta(`SELECT projections.login_policies2.second_factors`+
- ` FROM projections.login_policies2`),
+ regexp.QuoteMeta(`SELECT projections.login_policies3.second_factors`+
+ ` FROM projections.login_policies3`),
[]string{
"second_factors",
},
@@ -300,8 +312,8 @@ func Test_LoginPolicyPrepares(t *testing.T) {
prepare: prepareLoginPolicy2FAsQuery,
want: want{
sqlExpectations: mockQueryErr(
- regexp.QuoteMeta(`SELECT projections.login_policies2.second_factors`+
- ` FROM projections.login_policies2`),
+ regexp.QuoteMeta(`SELECT projections.login_policies3.second_factors`+
+ ` FROM projections.login_policies3`),
sql.ErrConnDone,
),
err: func(err error) (error, bool) {
@@ -318,8 +330,8 @@ func Test_LoginPolicyPrepares(t *testing.T) {
prepare: prepareLoginPolicyMFAsQuery,
want: want{
sqlExpectations: mockQuery(
- regexp.QuoteMeta(`SELECT projections.login_policies2.multi_factors`+
- ` FROM projections.login_policies2`),
+ regexp.QuoteMeta(`SELECT projections.login_policies3.multi_factors`+
+ ` FROM projections.login_policies3`),
[]string{
"multi_factors",
},
@@ -339,8 +351,8 @@ func Test_LoginPolicyPrepares(t *testing.T) {
prepare: prepareLoginPolicyMFAsQuery,
want: want{
sqlExpectations: mockQuery(
- regexp.QuoteMeta(`SELECT projections.login_policies2.multi_factors`+
- ` FROM projections.login_policies2`),
+ regexp.QuoteMeta(`SELECT projections.login_policies3.multi_factors`+
+ ` FROM projections.login_policies3`),
[]string{
"multi_factors",
},
@@ -361,8 +373,8 @@ func Test_LoginPolicyPrepares(t *testing.T) {
prepare: prepareLoginPolicyMFAsQuery,
want: want{
sqlExpectations: mockQuery(
- regexp.QuoteMeta(`SELECT projections.login_policies2.multi_factors`+
- ` FROM projections.login_policies2`),
+ regexp.QuoteMeta(`SELECT projections.login_policies3.multi_factors`+
+ ` FROM projections.login_policies3`),
[]string{
"multi_factors",
},
@@ -378,8 +390,8 @@ func Test_LoginPolicyPrepares(t *testing.T) {
prepare: prepareLoginPolicyMFAsQuery,
want: want{
sqlExpectations: mockQueryErr(
- regexp.QuoteMeta(`SELECT projections.login_policies2.multi_factors`+
- ` FROM projections.login_policies2`),
+ regexp.QuoteMeta(`SELECT projections.login_policies3.multi_factors`+
+ ` FROM projections.login_policies3`),
sql.ErrConnDone,
),
err: func(err error) (error, bool) {
diff --git a/internal/query/org_member_test.go b/internal/query/org_member_test.go
index 185ed451c..c0e683da5 100644
--- a/internal/query/org_member_test.go
+++ b/internal/query/org_member_test.go
@@ -20,18 +20,18 @@ var (
", members.user_id" +
", members.roles" +
", projections.login_names.login_name" +
- ", projections.users3_humans.email" +
- ", projections.users3_humans.first_name" +
- ", projections.users3_humans.last_name" +
- ", projections.users3_humans.display_name" +
- ", projections.users3_machines.name" +
- ", projections.users3_humans.avatar_key" +
+ ", projections.users4_humans.email" +
+ ", projections.users4_humans.first_name" +
+ ", projections.users4_humans.last_name" +
+ ", projections.users4_humans.display_name" +
+ ", projections.users4_machines.name" +
+ ", projections.users4_humans.avatar_key" +
", COUNT(*) OVER () " +
"FROM projections.org_members2 AS members " +
- "LEFT JOIN projections.users3_humans " +
- "ON members.user_id = projections.users3_humans.user_id " +
- "LEFT JOIN projections.users3_machines " +
- "ON members.user_id = projections.users3_machines.user_id " +
+ "LEFT JOIN projections.users4_humans " +
+ "ON members.user_id = projections.users4_humans.user_id " +
+ "LEFT JOIN projections.users4_machines " +
+ "ON members.user_id = projections.users4_machines.user_id " +
"LEFT JOIN projections.login_names " +
"ON members.user_id = projections.login_names.user_id " +
"WHERE projections.login_names.is_primary = $1")
diff --git a/internal/query/project_grant_member_test.go b/internal/query/project_grant_member_test.go
index 3ca6783cc..40ec90bf0 100644
--- a/internal/query/project_grant_member_test.go
+++ b/internal/query/project_grant_member_test.go
@@ -20,18 +20,18 @@ var (
", members.user_id" +
", members.roles" +
", projections.login_names.login_name" +
- ", projections.users3_humans.email" +
- ", projections.users3_humans.first_name" +
- ", projections.users3_humans.last_name" +
- ", projections.users3_humans.display_name" +
- ", projections.users3_machines.name" +
- ", projections.users3_humans.avatar_key" +
+ ", projections.users4_humans.email" +
+ ", projections.users4_humans.first_name" +
+ ", projections.users4_humans.last_name" +
+ ", projections.users4_humans.display_name" +
+ ", projections.users4_machines.name" +
+ ", projections.users4_humans.avatar_key" +
", COUNT(*) OVER () " +
"FROM projections.project_grant_members2 AS members " +
- "LEFT JOIN projections.users3_humans " +
- "ON members.user_id = projections.users3_humans.user_id " +
- "LEFT JOIN projections.users3_machines " +
- "ON members.user_id = projections.users3_machines.user_id " +
+ "LEFT JOIN projections.users4_humans " +
+ "ON members.user_id = projections.users4_humans.user_id " +
+ "LEFT JOIN projections.users4_machines " +
+ "ON members.user_id = projections.users4_machines.user_id " +
"LEFT JOIN projections.login_names " +
"ON members.user_id = projections.login_names.user_id " +
"LEFT JOIN projections.project_grants2 " +
diff --git a/internal/query/project_member_test.go b/internal/query/project_member_test.go
index 610b976b0..c89485727 100644
--- a/internal/query/project_member_test.go
+++ b/internal/query/project_member_test.go
@@ -20,18 +20,18 @@ var (
", members.user_id" +
", members.roles" +
", projections.login_names.login_name" +
- ", projections.users3_humans.email" +
- ", projections.users3_humans.first_name" +
- ", projections.users3_humans.last_name" +
- ", projections.users3_humans.display_name" +
- ", projections.users3_machines.name" +
- ", projections.users3_humans.avatar_key" +
+ ", projections.users4_humans.email" +
+ ", projections.users4_humans.first_name" +
+ ", projections.users4_humans.last_name" +
+ ", projections.users4_humans.display_name" +
+ ", projections.users4_machines.name" +
+ ", projections.users4_humans.avatar_key" +
", COUNT(*) OVER () " +
"FROM projections.project_members2 AS members " +
- "LEFT JOIN projections.users3_humans " +
- "ON members.user_id = projections.users3_humans.user_id " +
- "LEFT JOIN projections.users3_machines " +
- "ON members.user_id = projections.users3_machines.user_id " +
+ "LEFT JOIN projections.users4_humans " +
+ "ON members.user_id = projections.users4_humans.user_id " +
+ "LEFT JOIN projections.users4_machines " +
+ "ON members.user_id = projections.users4_machines.user_id " +
"LEFT JOIN projections.login_names " +
"ON members.user_id = projections.login_names.user_id " +
"WHERE projections.login_names.is_primary = $1")
diff --git a/internal/query/projection/login_policy.go b/internal/query/projection/login_policy.go
index 0900d9026..9ba12ec80 100644
--- a/internal/query/projection/login_policy.go
+++ b/internal/query/projection/login_policy.go
@@ -13,7 +13,7 @@ import (
)
const (
- LoginPolicyTable = "projections.login_policies2"
+ LoginPolicyTable = "projections.login_policies3"
LoginPolicyIDCol = "aggregate_id"
LoginPolicyInstanceIDCol = "instance_id"
@@ -31,6 +31,8 @@ const (
LoginPolicyHidePWResetCol = "hide_password_reset"
IgnoreUnknownUsernames = "ignore_unknown_usernames"
AllowDomainDiscovery = "allow_domain_discovery"
+ DisableLoginWithEmail = "disable_login_with_email"
+ DisableLoginWithPhone = "disable_login_with_phone"
DefaultRedirectURI = "default_redirect_uri"
PasswordCheckLifetimeCol = "password_check_lifetime"
ExternalLoginCheckLifetimeCol = "external_login_check_lifetime"
@@ -65,6 +67,8 @@ func newLoginPolicyProjection(ctx context.Context, config crdb.StatementHandlerC
crdb.NewColumn(LoginPolicyHidePWResetCol, crdb.ColumnTypeBool),
crdb.NewColumn(IgnoreUnknownUsernames, crdb.ColumnTypeBool),
crdb.NewColumn(AllowDomainDiscovery, crdb.ColumnTypeBool),
+ crdb.NewColumn(DisableLoginWithEmail, crdb.ColumnTypeBool),
+ crdb.NewColumn(DisableLoginWithPhone, crdb.ColumnTypeBool),
crdb.NewColumn(DefaultRedirectURI, crdb.ColumnTypeText, crdb.Nullable()),
crdb.NewColumn(PasswordCheckLifetimeCol, crdb.ColumnTypeInt64),
crdb.NewColumn(ExternalLoginCheckLifetimeCol, crdb.ColumnTypeInt64),
@@ -175,6 +179,8 @@ func (p *loginPolicyProjection) reduceLoginPolicyAdded(event eventstore.Event) (
handler.NewCol(LoginPolicyHidePWResetCol, policyEvent.HidePasswordReset),
handler.NewCol(IgnoreUnknownUsernames, policyEvent.IgnoreUnknownUsernames),
handler.NewCol(AllowDomainDiscovery, policyEvent.AllowDomainDiscovery),
+ handler.NewCol(DisableLoginWithEmail, policyEvent.DisableLoginWithEmail),
+ handler.NewCol(DisableLoginWithPhone, policyEvent.DisableLoginWithPhone),
handler.NewCol(DefaultRedirectURI, policyEvent.DefaultRedirectURI),
handler.NewCol(PasswordCheckLifetimeCol, policyEvent.PasswordCheckLifetime),
handler.NewCol(ExternalLoginCheckLifetimeCol, policyEvent.ExternalLoginCheckLifetime),
@@ -223,6 +229,12 @@ func (p *loginPolicyProjection) reduceLoginPolicyChanged(event eventstore.Event)
if policyEvent.AllowDomainDiscovery != nil {
cols = append(cols, handler.NewCol(AllowDomainDiscovery, *policyEvent.AllowDomainDiscovery))
}
+ if policyEvent.DisableLoginWithEmail != nil {
+ cols = append(cols, handler.NewCol(DisableLoginWithEmail, *policyEvent.DisableLoginWithEmail))
+ }
+ if policyEvent.DisableLoginWithPhone != nil {
+ cols = append(cols, handler.NewCol(DisableLoginWithPhone, *policyEvent.DisableLoginWithPhone))
+ }
if policyEvent.DefaultRedirectURI != nil {
cols = append(cols, handler.NewCol(DefaultRedirectURI, *policyEvent.DefaultRedirectURI))
}
diff --git a/internal/query/projection/login_policy_test.go b/internal/query/projection/login_policy_test.go
index cecec6f2f..ef5f5a33f 100644
--- a/internal/query/projection/login_policy_test.go
+++ b/internal/query/projection/login_policy_test.go
@@ -37,6 +37,8 @@ func TestLoginPolicyProjection_reduces(t *testing.T) {
"hidePasswordReset": true,
"ignoreUnknownUsernames": true,
"allowDomainDiscovery": true,
+ "disableLoginWithEmail": true,
+ "disableLoginWithPhone": true,
"passwordlessType": 1,
"defaultRedirectURI": "https://example.com/redirect",
"passwordCheckLifetime": 10000000,
@@ -56,7 +58,7 @@ func TestLoginPolicyProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
- expectedStmt: "INSERT INTO projections.login_policies2 (aggregate_id, instance_id, creation_date, change_date, sequence, allow_register, allow_username_password, allow_external_idps, force_mfa, passwordless_type, is_default, hide_password_reset, ignore_unknown_usernames, allow_domain_discovery, default_redirect_uri, password_check_lifetime, external_login_check_lifetime, mfa_init_skip_lifetime, second_factor_check_lifetime, multi_factor_check_lifetime) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20)",
+ expectedStmt: "INSERT INTO projections.login_policies3 (aggregate_id, instance_id, creation_date, change_date, sequence, allow_register, allow_username_password, allow_external_idps, force_mfa, passwordless_type, is_default, hide_password_reset, ignore_unknown_usernames, allow_domain_discovery, disable_login_with_email, disable_login_with_phone, default_redirect_uri, password_check_lifetime, external_login_check_lifetime, mfa_init_skip_lifetime, second_factor_check_lifetime, multi_factor_check_lifetime) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21, $22)",
expectedArgs: []interface{}{
"agg-id",
"instance-id",
@@ -72,6 +74,8 @@ func TestLoginPolicyProjection_reduces(t *testing.T) {
true,
true,
true,
+ true,
+ true,
"https://example.com/redirect",
time.Millisecond * 10,
time.Millisecond * 10,
@@ -99,6 +103,8 @@ func TestLoginPolicyProjection_reduces(t *testing.T) {
"hidePasswordReset": true,
"ignoreUnknownUsernames": true,
"allowDomainDiscovery": true,
+ "disableLoginWithEmail": true,
+ "disableLoginWithPhone": true,
"passwordlessType": 1,
"defaultRedirectURI": "https://example.com/redirect",
"passwordCheckLifetime": 10000000,
@@ -117,7 +123,7 @@ func TestLoginPolicyProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
- expectedStmt: "UPDATE projections.login_policies2 SET (change_date, sequence, allow_register, allow_username_password, allow_external_idps, force_mfa, passwordless_type, hide_password_reset, ignore_unknown_usernames, allow_domain_discovery, default_redirect_uri, password_check_lifetime, external_login_check_lifetime, mfa_init_skip_lifetime, second_factor_check_lifetime, multi_factor_check_lifetime) = ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16) WHERE (aggregate_id = $17)",
+ expectedStmt: "UPDATE projections.login_policies3 SET (change_date, sequence, allow_register, allow_username_password, allow_external_idps, force_mfa, passwordless_type, hide_password_reset, ignore_unknown_usernames, allow_domain_discovery, disable_login_with_email, disable_login_with_phone, default_redirect_uri, password_check_lifetime, external_login_check_lifetime, mfa_init_skip_lifetime, second_factor_check_lifetime, multi_factor_check_lifetime) = ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18) WHERE (aggregate_id = $19)",
expectedArgs: []interface{}{
anyArg{},
uint64(15),
@@ -129,6 +135,8 @@ func TestLoginPolicyProjection_reduces(t *testing.T) {
true,
true,
true,
+ true,
+ true,
"https://example.com/redirect",
time.Millisecond * 10,
time.Millisecond * 10,
@@ -162,7 +170,7 @@ func TestLoginPolicyProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
- expectedStmt: "UPDATE projections.login_policies2 SET (change_date, sequence, multi_factors) = ($1, $2, array_append(multi_factors, $3)) WHERE (aggregate_id = $4)",
+ expectedStmt: "UPDATE projections.login_policies3 SET (change_date, sequence, multi_factors) = ($1, $2, array_append(multi_factors, $3)) WHERE (aggregate_id = $4)",
expectedArgs: []interface{}{
anyArg{},
uint64(15),
@@ -194,7 +202,7 @@ func TestLoginPolicyProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
- expectedStmt: "UPDATE projections.login_policies2 SET (change_date, sequence, multi_factors) = ($1, $2, array_remove(multi_factors, $3)) WHERE (aggregate_id = $4)",
+ expectedStmt: "UPDATE projections.login_policies3 SET (change_date, sequence, multi_factors) = ($1, $2, array_remove(multi_factors, $3)) WHERE (aggregate_id = $4)",
expectedArgs: []interface{}{
anyArg{},
uint64(15),
@@ -224,7 +232,7 @@ func TestLoginPolicyProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
- expectedStmt: "DELETE FROM projections.login_policies2 WHERE (aggregate_id = $1)",
+ expectedStmt: "DELETE FROM projections.login_policies3 WHERE (aggregate_id = $1)",
expectedArgs: []interface{}{
"agg-id",
},
@@ -253,7 +261,7 @@ func TestLoginPolicyProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
- expectedStmt: "UPDATE projections.login_policies2 SET (change_date, sequence, second_factors) = ($1, $2, array_append(second_factors, $3)) WHERE (aggregate_id = $4)",
+ expectedStmt: "UPDATE projections.login_policies3 SET (change_date, sequence, second_factors) = ($1, $2, array_append(second_factors, $3)) WHERE (aggregate_id = $4)",
expectedArgs: []interface{}{
anyArg{},
uint64(15),
@@ -285,7 +293,7 @@ func TestLoginPolicyProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
- expectedStmt: "UPDATE projections.login_policies2 SET (change_date, sequence, second_factors) = ($1, $2, array_remove(second_factors, $3)) WHERE (aggregate_id = $4)",
+ expectedStmt: "UPDATE projections.login_policies3 SET (change_date, sequence, second_factors) = ($1, $2, array_remove(second_factors, $3)) WHERE (aggregate_id = $4)",
expectedArgs: []interface{}{
anyArg{},
uint64(15),
@@ -312,6 +320,8 @@ func TestLoginPolicyProjection_reduces(t *testing.T) {
"hidePasswordReset": true,
"ignoreUnknownUsernames": true,
"allowDomainDiscovery": true,
+ "disableLoginWithEmail": true,
+ "disableLoginWithPhone": true,
"passwordlessType": 1,
"defaultRedirectURI": "https://example.com/redirect",
"passwordCheckLifetime": 10000000,
@@ -330,7 +340,7 @@ func TestLoginPolicyProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
- expectedStmt: "INSERT INTO projections.login_policies2 (aggregate_id, instance_id, creation_date, change_date, sequence, allow_register, allow_username_password, allow_external_idps, force_mfa, passwordless_type, is_default, hide_password_reset, ignore_unknown_usernames, allow_domain_discovery, default_redirect_uri, password_check_lifetime, external_login_check_lifetime, mfa_init_skip_lifetime, second_factor_check_lifetime, multi_factor_check_lifetime) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20)",
+ expectedStmt: "INSERT INTO projections.login_policies3 (aggregate_id, instance_id, creation_date, change_date, sequence, allow_register, allow_username_password, allow_external_idps, force_mfa, passwordless_type, is_default, hide_password_reset, ignore_unknown_usernames, allow_domain_discovery, disable_login_with_email, disable_login_with_phone, default_redirect_uri, password_check_lifetime, external_login_check_lifetime, mfa_init_skip_lifetime, second_factor_check_lifetime, multi_factor_check_lifetime) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21, $22)",
expectedArgs: []interface{}{
"agg-id",
"instance-id",
@@ -346,6 +356,8 @@ func TestLoginPolicyProjection_reduces(t *testing.T) {
true,
true,
true,
+ true,
+ true,
"https://example.com/redirect",
time.Millisecond * 10,
time.Millisecond * 10,
@@ -373,6 +385,8 @@ func TestLoginPolicyProjection_reduces(t *testing.T) {
"hidePasswordReset": true,
"ignoreUnknownUsernames": true,
"allowDomainDiscovery": true,
+ "disableLoginWithEmail": true,
+ "disableLoginWithPhone": true,
"passwordlessType": 1,
"defaultRedirectURI": "https://example.com/redirect"
}`),
@@ -386,7 +400,7 @@ func TestLoginPolicyProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
- expectedStmt: "UPDATE projections.login_policies2 SET (change_date, sequence, allow_register, allow_username_password, allow_external_idps, force_mfa, passwordless_type, hide_password_reset, ignore_unknown_usernames, allow_domain_discovery, default_redirect_uri) = ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11) WHERE (aggregate_id = $12)",
+ expectedStmt: "UPDATE projections.login_policies3 SET (change_date, sequence, allow_register, allow_username_password, allow_external_idps, force_mfa, passwordless_type, hide_password_reset, ignore_unknown_usernames, allow_domain_discovery, disable_login_with_email, disable_login_with_phone, default_redirect_uri) = ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13) WHERE (aggregate_id = $14)",
expectedArgs: []interface{}{
anyArg{},
uint64(15),
@@ -398,6 +412,8 @@ func TestLoginPolicyProjection_reduces(t *testing.T) {
true,
true,
true,
+ true,
+ true,
"https://example.com/redirect",
"agg-id",
},
@@ -426,7 +442,7 @@ func TestLoginPolicyProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
- expectedStmt: "UPDATE projections.login_policies2 SET (change_date, sequence, multi_factors) = ($1, $2, array_append(multi_factors, $3)) WHERE (aggregate_id = $4)",
+ expectedStmt: "UPDATE projections.login_policies3 SET (change_date, sequence, multi_factors) = ($1, $2, array_append(multi_factors, $3)) WHERE (aggregate_id = $4)",
expectedArgs: []interface{}{
anyArg{},
uint64(15),
@@ -458,7 +474,7 @@ func TestLoginPolicyProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
- expectedStmt: "UPDATE projections.login_policies2 SET (change_date, sequence, multi_factors) = ($1, $2, array_remove(multi_factors, $3)) WHERE (aggregate_id = $4)",
+ expectedStmt: "UPDATE projections.login_policies3 SET (change_date, sequence, multi_factors) = ($1, $2, array_remove(multi_factors, $3)) WHERE (aggregate_id = $4)",
expectedArgs: []interface{}{
anyArg{},
uint64(15),
@@ -490,7 +506,7 @@ func TestLoginPolicyProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
- expectedStmt: "UPDATE projections.login_policies2 SET (change_date, sequence, second_factors) = ($1, $2, array_append(second_factors, $3)) WHERE (aggregate_id = $4)",
+ expectedStmt: "UPDATE projections.login_policies3 SET (change_date, sequence, second_factors) = ($1, $2, array_append(second_factors, $3)) WHERE (aggregate_id = $4)",
expectedArgs: []interface{}{
anyArg{},
uint64(15),
@@ -522,7 +538,7 @@ func TestLoginPolicyProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
- expectedStmt: "UPDATE projections.login_policies2 SET (change_date, sequence, second_factors) = ($1, $2, array_remove(second_factors, $3)) WHERE (aggregate_id = $4)",
+ expectedStmt: "UPDATE projections.login_policies3 SET (change_date, sequence, second_factors) = ($1, $2, array_remove(second_factors, $3)) WHERE (aggregate_id = $4)",
expectedArgs: []interface{}{
anyArg{},
uint64(15),
diff --git a/internal/query/projection/user.go b/internal/query/projection/user.go
index 9d1c72c61..6f646d46a 100644
--- a/internal/query/projection/user.go
+++ b/internal/query/projection/user.go
@@ -17,7 +17,7 @@ type userProjection struct {
}
const (
- UserTable = "projections.users3"
+ UserTable = "projections.users4"
UserHumanTable = UserTable + "_" + UserHumanSuffix
UserMachineTable = UserTable + "_" + UserMachineSuffix
UserNotifyTable = UserTable + "_" + UserNotifySuffix
@@ -88,9 +88,9 @@ func newUserProjection(ctx context.Context, config crdb.StatementHandlerConfig)
crdb.NewColumn(UserTypeCol, crdb.ColumnTypeEnum),
},
crdb.NewPrimaryKey(UserIDCol, UserInstanceIDCol),
- crdb.WithIndex(crdb.NewIndex("username_idx", []string{UserUsernameCol})),
- crdb.WithIndex(crdb.NewIndex("user_ro_idx", []string{UserResourceOwnerCol})),
- crdb.WithConstraint(crdb.NewConstraint("user_id_unique", []string{UserIDCol})),
+ crdb.WithIndex(crdb.NewIndex("username_idx4", []string{UserUsernameCol})),
+ crdb.WithIndex(crdb.NewIndex("user_ro_idx4", []string{UserResourceOwnerCol})),
+ crdb.WithConstraint(crdb.NewConstraint("user_id_unique4", []string{UserIDCol})),
),
crdb.NewSuffixedTable([]*crdb.Column{
crdb.NewColumn(HumanUserIDCol, crdb.ColumnTypeText),
@@ -109,7 +109,7 @@ func newUserProjection(ctx context.Context, config crdb.StatementHandlerConfig)
},
crdb.NewPrimaryKey(HumanUserIDCol, HumanUserInstanceIDCol),
UserHumanSuffix,
- crdb.WithForeignKey(crdb.NewForeignKeyOfPublicKeys("fk_human_ref_user")),
+ crdb.WithForeignKey(crdb.NewForeignKeyOfPublicKeys("fk_human_ref_user4")),
),
crdb.NewSuffixedTable([]*crdb.Column{
crdb.NewColumn(MachineUserIDCol, crdb.ColumnTypeText),
@@ -119,7 +119,7 @@ func newUserProjection(ctx context.Context, config crdb.StatementHandlerConfig)
},
crdb.NewPrimaryKey(MachineUserIDCol, MachineUserInstanceIDCol),
UserMachineSuffix,
- crdb.WithForeignKey(crdb.NewForeignKeyOfPublicKeys("fk_machine_ref_user")),
+ crdb.WithForeignKey(crdb.NewForeignKeyOfPublicKeys("fk_machine_ref_user4")),
),
crdb.NewSuffixedTable([]*crdb.Column{
crdb.NewColumn(NotifyUserIDCol, crdb.ColumnTypeText),
@@ -132,7 +132,7 @@ func newUserProjection(ctx context.Context, config crdb.StatementHandlerConfig)
},
crdb.NewPrimaryKey(NotifyUserIDCol, NotifyInstanceIDCol),
UserNotifySuffix,
- crdb.WithForeignKey(crdb.NewForeignKeyOfPublicKeys("fk_notify_ref_user")),
+ crdb.WithForeignKey(crdb.NewForeignKeyOfPublicKeys("fk_notify_ref_user4")),
),
)
p.StatementHandler = crdb.NewStatementHandler(ctx, config)
@@ -708,20 +708,9 @@ func (p *userProjection) reduceHumanPhoneVerified(event eventstore.Event) (*hand
},
crdb.WithTableSuffix(UserHumanSuffix),
),
- crdb.AddCopyStatement(
+ crdb.AddUpdateStatement(
[]handler.Column{
- handler.NewCol(NotifyUserIDCol, nil),
- handler.NewCol(NotifyInstanceIDCol, nil),
- },
- []handler.Column{
- handler.NewCol(NotifyUserIDCol, nil),
- handler.NewCol(NotifyInstanceIDCol, nil),
- handler.NewCol(NotifyLastPhoneCol, nil),
- },
- []handler.Column{
- handler.NewCol(NotifyUserIDCol, nil),
- handler.NewCol(NotifyInstanceIDCol, nil),
- handler.NewCol(NotifyVerifiedPhoneCol, nil),
+ crdb.NewCopyCol(NotifyVerifiedPhoneCol, NotifyLastPhoneCol),
},
[]handler.Condition{
handler.NewCond(NotifyUserIDCol, e.Aggregate().ID),
@@ -802,20 +791,9 @@ func (p *userProjection) reduceHumanEmailVerified(event eventstore.Event) (*hand
},
crdb.WithTableSuffix(UserHumanSuffix),
),
- crdb.AddCopyStatement(
+ crdb.AddUpdateStatement(
[]handler.Column{
- handler.NewCol(NotifyUserIDCol, nil),
- handler.NewCol(NotifyInstanceIDCol, nil),
- },
- []handler.Column{
- handler.NewCol(NotifyUserIDCol, nil),
- handler.NewCol(NotifyInstanceIDCol, nil),
- handler.NewCol(NotifyLastEmailCol, nil),
- },
- []handler.Column{
- handler.NewCol(NotifyUserIDCol, nil),
- handler.NewCol(NotifyInstanceIDCol, nil),
- handler.NewCol(NotifyVerifiedEmailCol, nil),
+ crdb.NewCopyCol(NotifyVerifiedEmailCol, NotifyLastEmailCol),
},
[]handler.Condition{
handler.NewCond(NotifyUserIDCol, e.Aggregate().ID),
diff --git a/internal/query/projection/user_test.go b/internal/query/projection/user_test.go
index e7846a258..54cebee31 100644
--- a/internal/query/projection/user_test.go
+++ b/internal/query/projection/user_test.go
@@ -50,7 +50,7 @@ func TestUserProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
- expectedStmt: "INSERT INTO projections.users3 (id, creation_date, change_date, resource_owner, instance_id, state, sequence, username, type) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)",
+ expectedStmt: "INSERT INTO projections.users4 (id, creation_date, change_date, resource_owner, instance_id, state, sequence, username, type) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)",
expectedArgs: []interface{}{
"agg-id",
anyArg{},
@@ -64,7 +64,7 @@ func TestUserProjection_reduces(t *testing.T) {
},
},
{
- expectedStmt: "INSERT INTO projections.users3_humans (user_id, instance_id, first_name, last_name, nick_name, display_name, preferred_language, gender, email, phone) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)",
+ expectedStmt: "INSERT INTO projections.users4_humans (user_id, instance_id, first_name, last_name, nick_name, display_name, preferred_language, gender, email, phone) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)",
expectedArgs: []interface{}{
"agg-id",
"instance-id",
@@ -79,7 +79,7 @@ func TestUserProjection_reduces(t *testing.T) {
},
},
{
- expectedStmt: "INSERT INTO projections.users3_notifications (user_id, instance_id, last_email, last_phone, password_set) VALUES ($1, $2, $3, $4, $5)",
+ expectedStmt: "INSERT INTO projections.users4_notifications (user_id, instance_id, last_email, last_phone, password_set) VALUES ($1, $2, $3, $4, $5)",
expectedArgs: []interface{}{
"agg-id",
"instance-id",
@@ -120,7 +120,7 @@ func TestUserProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
- expectedStmt: "INSERT INTO projections.users3 (id, creation_date, change_date, resource_owner, instance_id, state, sequence, username, type) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)",
+ expectedStmt: "INSERT INTO projections.users4 (id, creation_date, change_date, resource_owner, instance_id, state, sequence, username, type) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)",
expectedArgs: []interface{}{
"agg-id",
anyArg{},
@@ -134,7 +134,7 @@ func TestUserProjection_reduces(t *testing.T) {
},
},
{
- expectedStmt: "INSERT INTO projections.users3_humans (user_id, instance_id, first_name, last_name, nick_name, display_name, preferred_language, gender, email, phone) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)",
+ expectedStmt: "INSERT INTO projections.users4_humans (user_id, instance_id, first_name, last_name, nick_name, display_name, preferred_language, gender, email, phone) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)",
expectedArgs: []interface{}{
"agg-id",
"instance-id",
@@ -149,7 +149,7 @@ func TestUserProjection_reduces(t *testing.T) {
},
},
{
- expectedStmt: "INSERT INTO projections.users3_notifications (user_id, instance_id, last_email, last_phone, password_set) VALUES ($1, $2, $3, $4, $5)",
+ expectedStmt: "INSERT INTO projections.users4_notifications (user_id, instance_id, last_email, last_phone, password_set) VALUES ($1, $2, $3, $4, $5)",
expectedArgs: []interface{}{
"agg-id",
"instance-id",
@@ -185,7 +185,7 @@ func TestUserProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
- expectedStmt: "INSERT INTO projections.users3 (id, creation_date, change_date, resource_owner, instance_id, state, sequence, username, type) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)",
+ expectedStmt: "INSERT INTO projections.users4 (id, creation_date, change_date, resource_owner, instance_id, state, sequence, username, type) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)",
expectedArgs: []interface{}{
"agg-id",
anyArg{},
@@ -199,7 +199,7 @@ func TestUserProjection_reduces(t *testing.T) {
},
},
{
- expectedStmt: "INSERT INTO projections.users3_humans (user_id, instance_id, first_name, last_name, nick_name, display_name, preferred_language, gender, email, phone) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)",
+ expectedStmt: "INSERT INTO projections.users4_humans (user_id, instance_id, first_name, last_name, nick_name, display_name, preferred_language, gender, email, phone) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)",
expectedArgs: []interface{}{
"agg-id",
"instance-id",
@@ -214,7 +214,7 @@ func TestUserProjection_reduces(t *testing.T) {
},
},
{
- expectedStmt: "INSERT INTO projections.users3_notifications (user_id, instance_id, last_email, last_phone, password_set) VALUES ($1, $2, $3, $4, $5)",
+ expectedStmt: "INSERT INTO projections.users4_notifications (user_id, instance_id, last_email, last_phone, password_set) VALUES ($1, $2, $3, $4, $5)",
expectedArgs: []interface{}{
"agg-id",
"instance-id",
@@ -255,7 +255,7 @@ func TestUserProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
- expectedStmt: "INSERT INTO projections.users3 (id, creation_date, change_date, resource_owner, instance_id, state, sequence, username, type) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)",
+ expectedStmt: "INSERT INTO projections.users4 (id, creation_date, change_date, resource_owner, instance_id, state, sequence, username, type) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)",
expectedArgs: []interface{}{
"agg-id",
anyArg{},
@@ -269,7 +269,7 @@ func TestUserProjection_reduces(t *testing.T) {
},
},
{
- expectedStmt: "INSERT INTO projections.users3_humans (user_id, instance_id, first_name, last_name, nick_name, display_name, preferred_language, gender, email, phone) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)",
+ expectedStmt: "INSERT INTO projections.users4_humans (user_id, instance_id, first_name, last_name, nick_name, display_name, preferred_language, gender, email, phone) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)",
expectedArgs: []interface{}{
"agg-id",
"instance-id",
@@ -284,7 +284,7 @@ func TestUserProjection_reduces(t *testing.T) {
},
},
{
- expectedStmt: "INSERT INTO projections.users3_notifications (user_id, instance_id, last_email, last_phone, password_set) VALUES ($1, $2, $3, $4, $5)",
+ expectedStmt: "INSERT INTO projections.users4_notifications (user_id, instance_id, last_email, last_phone, password_set) VALUES ($1, $2, $3, $4, $5)",
expectedArgs: []interface{}{
"agg-id",
"instance-id",
@@ -325,7 +325,7 @@ func TestUserProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
- expectedStmt: "INSERT INTO projections.users3 (id, creation_date, change_date, resource_owner, instance_id, state, sequence, username, type) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)",
+ expectedStmt: "INSERT INTO projections.users4 (id, creation_date, change_date, resource_owner, instance_id, state, sequence, username, type) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)",
expectedArgs: []interface{}{
"agg-id",
anyArg{},
@@ -339,7 +339,7 @@ func TestUserProjection_reduces(t *testing.T) {
},
},
{
- expectedStmt: "INSERT INTO projections.users3_humans (user_id, instance_id, first_name, last_name, nick_name, display_name, preferred_language, gender, email, phone) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)",
+ expectedStmt: "INSERT INTO projections.users4_humans (user_id, instance_id, first_name, last_name, nick_name, display_name, preferred_language, gender, email, phone) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)",
expectedArgs: []interface{}{
"agg-id",
"instance-id",
@@ -354,7 +354,7 @@ func TestUserProjection_reduces(t *testing.T) {
},
},
{
- expectedStmt: "INSERT INTO projections.users3_notifications (user_id, instance_id, last_email, last_phone, password_set) VALUES ($1, $2, $3, $4, $5)",
+ expectedStmt: "INSERT INTO projections.users4_notifications (user_id, instance_id, last_email, last_phone, password_set) VALUES ($1, $2, $3, $4, $5)",
expectedArgs: []interface{}{
"agg-id",
"instance-id",
@@ -390,7 +390,7 @@ func TestUserProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
- expectedStmt: "INSERT INTO projections.users3 (id, creation_date, change_date, resource_owner, instance_id, state, sequence, username, type) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)",
+ expectedStmt: "INSERT INTO projections.users4 (id, creation_date, change_date, resource_owner, instance_id, state, sequence, username, type) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)",
expectedArgs: []interface{}{
"agg-id",
anyArg{},
@@ -404,7 +404,7 @@ func TestUserProjection_reduces(t *testing.T) {
},
},
{
- expectedStmt: "INSERT INTO projections.users3_humans (user_id, instance_id, first_name, last_name, nick_name, display_name, preferred_language, gender, email, phone) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)",
+ expectedStmt: "INSERT INTO projections.users4_humans (user_id, instance_id, first_name, last_name, nick_name, display_name, preferred_language, gender, email, phone) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)",
expectedArgs: []interface{}{
"agg-id",
"instance-id",
@@ -419,7 +419,7 @@ func TestUserProjection_reduces(t *testing.T) {
},
},
{
- expectedStmt: "INSERT INTO projections.users3_notifications (user_id, instance_id, last_email, last_phone, password_set) VALUES ($1, $2, $3, $4, $5)",
+ expectedStmt: "INSERT INTO projections.users4_notifications (user_id, instance_id, last_email, last_phone, password_set) VALUES ($1, $2, $3, $4, $5)",
expectedArgs: []interface{}{
"agg-id",
"instance-id",
@@ -450,7 +450,7 @@ func TestUserProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
- expectedStmt: "UPDATE projections.users3 SET state = $1 WHERE (id = $2) AND (instance_id = $3)",
+ expectedStmt: "UPDATE projections.users4 SET state = $1 WHERE (id = $2) AND (instance_id = $3)",
expectedArgs: []interface{}{
domain.UserStateInitial,
"agg-id",
@@ -479,7 +479,7 @@ func TestUserProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
- expectedStmt: "UPDATE projections.users3 SET state = $1 WHERE (id = $2) AND (instance_id = $3)",
+ expectedStmt: "UPDATE projections.users4 SET state = $1 WHERE (id = $2) AND (instance_id = $3)",
expectedArgs: []interface{}{
domain.UserStateInitial,
"agg-id",
@@ -508,7 +508,7 @@ func TestUserProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
- expectedStmt: "UPDATE projections.users3 SET state = $1 WHERE (id = $2) AND (instance_id = $3)",
+ expectedStmt: "UPDATE projections.users4 SET state = $1 WHERE (id = $2) AND (instance_id = $3)",
expectedArgs: []interface{}{
domain.UserStateActive,
"agg-id",
@@ -537,7 +537,7 @@ func TestUserProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
- expectedStmt: "UPDATE projections.users3 SET state = $1 WHERE (id = $2) AND (instance_id = $3)",
+ expectedStmt: "UPDATE projections.users4 SET state = $1 WHERE (id = $2) AND (instance_id = $3)",
expectedArgs: []interface{}{
domain.UserStateActive,
"agg-id",
@@ -566,7 +566,7 @@ func TestUserProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
- expectedStmt: "UPDATE projections.users3 SET (change_date, state, sequence) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)",
+ expectedStmt: "UPDATE projections.users4 SET (change_date, state, sequence) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)",
expectedArgs: []interface{}{
anyArg{},
domain.UserStateLocked,
@@ -597,7 +597,7 @@ func TestUserProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
- expectedStmt: "UPDATE projections.users3 SET (change_date, state, sequence) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)",
+ expectedStmt: "UPDATE projections.users4 SET (change_date, state, sequence) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)",
expectedArgs: []interface{}{
anyArg{},
domain.UserStateActive,
@@ -628,7 +628,7 @@ func TestUserProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
- expectedStmt: "UPDATE projections.users3 SET (change_date, state, sequence) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)",
+ expectedStmt: "UPDATE projections.users4 SET (change_date, state, sequence) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)",
expectedArgs: []interface{}{
anyArg{},
domain.UserStateInactive,
@@ -659,7 +659,7 @@ func TestUserProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
- expectedStmt: "UPDATE projections.users3 SET (change_date, state, sequence) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)",
+ expectedStmt: "UPDATE projections.users4 SET (change_date, state, sequence) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)",
expectedArgs: []interface{}{
anyArg{},
domain.UserStateActive,
@@ -690,7 +690,7 @@ func TestUserProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
- expectedStmt: "DELETE FROM projections.users3 WHERE (id = $1) AND (instance_id = $2)",
+ expectedStmt: "DELETE FROM projections.users4 WHERE (id = $1) AND (instance_id = $2)",
expectedArgs: []interface{}{
"agg-id",
"instance-id",
@@ -720,7 +720,7 @@ func TestUserProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
- expectedStmt: "UPDATE projections.users3 SET (change_date, username, sequence) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)",
+ expectedStmt: "UPDATE projections.users4 SET (change_date, username, sequence) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)",
expectedArgs: []interface{}{
anyArg{},
"username",
@@ -753,7 +753,7 @@ func TestUserProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
- expectedStmt: "UPDATE projections.users3 SET (change_date, username, sequence) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)",
+ expectedStmt: "UPDATE projections.users4 SET (change_date, username, sequence) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)",
expectedArgs: []interface{}{
anyArg{},
"id@temporary.domain",
@@ -791,7 +791,7 @@ func TestUserProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
- expectedStmt: "UPDATE projections.users3 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)",
+ expectedStmt: "UPDATE projections.users4 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)",
expectedArgs: []interface{}{
anyArg{},
uint64(15),
@@ -800,7 +800,7 @@ func TestUserProjection_reduces(t *testing.T) {
},
},
{
- expectedStmt: "UPDATE projections.users3_humans SET (first_name, last_name, nick_name, display_name, preferred_language, gender) = ($1, $2, $3, $4, $5, $6) WHERE (user_id = $7) AND (instance_id = $8)",
+ expectedStmt: "UPDATE projections.users4_humans SET (first_name, last_name, nick_name, display_name, preferred_language, gender) = ($1, $2, $3, $4, $5, $6) WHERE (user_id = $7) AND (instance_id = $8)",
expectedArgs: []interface{}{
"first-name",
"last-name",
@@ -841,7 +841,7 @@ func TestUserProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
- expectedStmt: "UPDATE projections.users3 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)",
+ expectedStmt: "UPDATE projections.users4 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)",
expectedArgs: []interface{}{
anyArg{},
uint64(15),
@@ -850,7 +850,7 @@ func TestUserProjection_reduces(t *testing.T) {
},
},
{
- expectedStmt: "UPDATE projections.users3_humans SET (first_name, last_name, nick_name, display_name, preferred_language, gender) = ($1, $2, $3, $4, $5, $6) WHERE (user_id = $7) AND (instance_id = $8)",
+ expectedStmt: "UPDATE projections.users4_humans SET (first_name, last_name, nick_name, display_name, preferred_language, gender) = ($1, $2, $3, $4, $5, $6) WHERE (user_id = $7) AND (instance_id = $8)",
expectedArgs: []interface{}{
"first-name",
"last-name",
@@ -886,7 +886,7 @@ func TestUserProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
- expectedStmt: "UPDATE projections.users3 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)",
+ expectedStmt: "UPDATE projections.users4 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)",
expectedArgs: []interface{}{
anyArg{},
uint64(15),
@@ -895,7 +895,7 @@ func TestUserProjection_reduces(t *testing.T) {
},
},
{
- expectedStmt: "UPDATE projections.users3_humans SET (phone, is_phone_verified) = ($1, $2) WHERE (user_id = $3) AND (instance_id = $4)",
+ expectedStmt: "UPDATE projections.users4_humans SET (phone, is_phone_verified) = ($1, $2) WHERE (user_id = $3) AND (instance_id = $4)",
expectedArgs: []interface{}{
"+41 00 000 00 00",
false,
@@ -904,7 +904,7 @@ func TestUserProjection_reduces(t *testing.T) {
},
},
{
- expectedStmt: "UPDATE projections.users3_notifications SET last_phone = $1 WHERE (user_id = $2) AND (instance_id = $3)",
+ expectedStmt: "UPDATE projections.users4_notifications SET last_phone = $1 WHERE (user_id = $2) AND (instance_id = $3)",
expectedArgs: []interface{}{
&sql.NullString{String: "+41 00 000 00 00", Valid: true},
"agg-id",
@@ -935,7 +935,7 @@ func TestUserProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
- expectedStmt: "UPDATE projections.users3 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)",
+ expectedStmt: "UPDATE projections.users4 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)",
expectedArgs: []interface{}{
anyArg{},
uint64(15),
@@ -944,7 +944,7 @@ func TestUserProjection_reduces(t *testing.T) {
},
},
{
- expectedStmt: "UPDATE projections.users3_humans SET (phone, is_phone_verified) = ($1, $2) WHERE (user_id = $3) AND (instance_id = $4)",
+ expectedStmt: "UPDATE projections.users4_humans SET (phone, is_phone_verified) = ($1, $2) WHERE (user_id = $3) AND (instance_id = $4)",
expectedArgs: []interface{}{
"+41 00 000 00 00",
false,
@@ -953,7 +953,7 @@ func TestUserProjection_reduces(t *testing.T) {
},
},
{
- expectedStmt: "UPDATE projections.users3_notifications SET last_phone = $1 WHERE (user_id = $2) AND (instance_id = $3)",
+ expectedStmt: "UPDATE projections.users4_notifications SET last_phone = $1 WHERE (user_id = $2) AND (instance_id = $3)",
expectedArgs: []interface{}{
&sql.NullString{String: "+41 00 000 00 00", Valid: true},
"agg-id",
@@ -982,7 +982,7 @@ func TestUserProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
- expectedStmt: "UPDATE projections.users3 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)",
+ expectedStmt: "UPDATE projections.users4 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)",
expectedArgs: []interface{}{
anyArg{},
uint64(15),
@@ -991,7 +991,7 @@ func TestUserProjection_reduces(t *testing.T) {
},
},
{
- expectedStmt: "UPDATE projections.users3_humans SET (phone, is_phone_verified) = ($1, $2) WHERE (user_id = $3) AND (instance_id = $4)",
+ expectedStmt: "UPDATE projections.users4_humans SET (phone, is_phone_verified) = ($1, $2) WHERE (user_id = $3) AND (instance_id = $4)",
expectedArgs: []interface{}{
nil,
nil,
@@ -1000,7 +1000,7 @@ func TestUserProjection_reduces(t *testing.T) {
},
},
{
- expectedStmt: "UPDATE projections.users3_notifications SET (last_phone, verified_phone) = ($1, $2) WHERE (user_id = $3) AND (instance_id = $4)",
+ expectedStmt: "UPDATE projections.users4_notifications SET (last_phone, verified_phone) = ($1, $2) WHERE (user_id = $3) AND (instance_id = $4)",
expectedArgs: []interface{}{
nil,
nil,
@@ -1030,7 +1030,7 @@ func TestUserProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
- expectedStmt: "UPDATE projections.users3 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)",
+ expectedStmt: "UPDATE projections.users4 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)",
expectedArgs: []interface{}{
anyArg{},
uint64(15),
@@ -1039,7 +1039,7 @@ func TestUserProjection_reduces(t *testing.T) {
},
},
{
- expectedStmt: "UPDATE projections.users3_humans SET (phone, is_phone_verified) = ($1, $2) WHERE (user_id = $3) AND (instance_id = $4)",
+ expectedStmt: "UPDATE projections.users4_humans SET (phone, is_phone_verified) = ($1, $2) WHERE (user_id = $3) AND (instance_id = $4)",
expectedArgs: []interface{}{
nil,
nil,
@@ -1048,7 +1048,7 @@ func TestUserProjection_reduces(t *testing.T) {
},
},
{
- expectedStmt: "UPDATE projections.users3_notifications SET (last_phone, verified_phone) = ($1, $2) WHERE (user_id = $3) AND (instance_id = $4)",
+ expectedStmt: "UPDATE projections.users4_notifications SET (last_phone, verified_phone) = ($1, $2) WHERE (user_id = $3) AND (instance_id = $4)",
expectedArgs: []interface{}{
nil,
nil,
@@ -1078,7 +1078,7 @@ func TestUserProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
- expectedStmt: "UPDATE projections.users3 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)",
+ expectedStmt: "UPDATE projections.users4 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)",
expectedArgs: []interface{}{
anyArg{},
uint64(15),
@@ -1087,7 +1087,7 @@ func TestUserProjection_reduces(t *testing.T) {
},
},
{
- expectedStmt: "UPDATE projections.users3_humans SET is_phone_verified = $1 WHERE (user_id = $2) AND (instance_id = $3)",
+ expectedStmt: "UPDATE projections.users4_humans SET is_phone_verified = $1 WHERE (user_id = $2) AND (instance_id = $3)",
expectedArgs: []interface{}{
true,
"agg-id",
@@ -1095,7 +1095,7 @@ func TestUserProjection_reduces(t *testing.T) {
},
},
{
- expectedStmt: "INSERT INTO projections.users3_notifications (user_id, instance_id, verified_phone) SELECT user_id, instance_id, last_phone FROM projections.users3_notifications AS copy_table WHERE copy_table.user_id = $1 AND copy_table.instance_id = $2 ON CONFLICT (user_id, instance_id) DO UPDATE SET (user_id, instance_id, verified_phone) = (EXCLUDED.user_id, EXCLUDED.instance_id, EXCLUDED.last_phone)",
+ expectedStmt: "UPDATE projections.users4_notifications SET verified_phone = last_phone WHERE (user_id = $1) AND (instance_id = $2)",
expectedArgs: []interface{}{
"agg-id",
"instance-id",
@@ -1123,7 +1123,7 @@ func TestUserProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
- expectedStmt: "UPDATE projections.users3 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)",
+ expectedStmt: "UPDATE projections.users4 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)",
expectedArgs: []interface{}{
anyArg{},
uint64(15),
@@ -1132,7 +1132,7 @@ func TestUserProjection_reduces(t *testing.T) {
},
},
{
- expectedStmt: "UPDATE projections.users3_humans SET is_phone_verified = $1 WHERE (user_id = $2) AND (instance_id = $3)",
+ expectedStmt: "UPDATE projections.users4_humans SET is_phone_verified = $1 WHERE (user_id = $2) AND (instance_id = $3)",
expectedArgs: []interface{}{
true,
"agg-id",
@@ -1140,7 +1140,7 @@ func TestUserProjection_reduces(t *testing.T) {
},
},
{
- expectedStmt: "INSERT INTO projections.users3_notifications (user_id, instance_id, verified_phone) SELECT user_id, instance_id, last_phone FROM projections.users3_notifications AS copy_table WHERE copy_table.user_id = $1 AND copy_table.instance_id = $2 ON CONFLICT (user_id, instance_id) DO UPDATE SET (user_id, instance_id, verified_phone) = (EXCLUDED.user_id, EXCLUDED.instance_id, EXCLUDED.last_phone)",
+ expectedStmt: "UPDATE projections.users4_notifications SET verified_phone = last_phone WHERE (user_id = $1) AND (instance_id = $2)",
expectedArgs: []interface{}{
"agg-id",
"instance-id",
@@ -1170,7 +1170,7 @@ func TestUserProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
- expectedStmt: "UPDATE projections.users3 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)",
+ expectedStmt: "UPDATE projections.users4 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)",
expectedArgs: []interface{}{
anyArg{},
uint64(15),
@@ -1179,7 +1179,7 @@ func TestUserProjection_reduces(t *testing.T) {
},
},
{
- expectedStmt: "UPDATE projections.users3_humans SET (email, is_email_verified) = ($1, $2) WHERE (user_id = $3) AND (instance_id = $4)",
+ expectedStmt: "UPDATE projections.users4_humans SET (email, is_email_verified) = ($1, $2) WHERE (user_id = $3) AND (instance_id = $4)",
expectedArgs: []interface{}{
"email@zitadel.com",
false,
@@ -1188,7 +1188,7 @@ func TestUserProjection_reduces(t *testing.T) {
},
},
{
- expectedStmt: "UPDATE projections.users3_notifications SET last_email = $1 WHERE (user_id = $2) AND (instance_id = $3)",
+ expectedStmt: "UPDATE projections.users4_notifications SET last_email = $1 WHERE (user_id = $2) AND (instance_id = $3)",
expectedArgs: []interface{}{
&sql.NullString{String: "email@zitadel.com", Valid: true},
"agg-id",
@@ -1219,7 +1219,7 @@ func TestUserProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
- expectedStmt: "UPDATE projections.users3 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)",
+ expectedStmt: "UPDATE projections.users4 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)",
expectedArgs: []interface{}{
anyArg{},
uint64(15),
@@ -1228,7 +1228,7 @@ func TestUserProjection_reduces(t *testing.T) {
},
},
{
- expectedStmt: "UPDATE projections.users3_humans SET (email, is_email_verified) = ($1, $2) WHERE (user_id = $3) AND (instance_id = $4)",
+ expectedStmt: "UPDATE projections.users4_humans SET (email, is_email_verified) = ($1, $2) WHERE (user_id = $3) AND (instance_id = $4)",
expectedArgs: []interface{}{
"email@zitadel.com",
false,
@@ -1237,7 +1237,7 @@ func TestUserProjection_reduces(t *testing.T) {
},
},
{
- expectedStmt: "UPDATE projections.users3_notifications SET last_email = $1 WHERE (user_id = $2) AND (instance_id = $3)",
+ expectedStmt: "UPDATE projections.users4_notifications SET last_email = $1 WHERE (user_id = $2) AND (instance_id = $3)",
expectedArgs: []interface{}{
&sql.NullString{String: "email@zitadel.com", Valid: true},
"agg-id",
@@ -1266,7 +1266,7 @@ func TestUserProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
- expectedStmt: "UPDATE projections.users3 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)",
+ expectedStmt: "UPDATE projections.users4 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)",
expectedArgs: []interface{}{
anyArg{},
uint64(15),
@@ -1275,7 +1275,7 @@ func TestUserProjection_reduces(t *testing.T) {
},
},
{
- expectedStmt: "UPDATE projections.users3_humans SET is_email_verified = $1 WHERE (user_id = $2) AND (instance_id = $3)",
+ expectedStmt: "UPDATE projections.users4_humans SET is_email_verified = $1 WHERE (user_id = $2) AND (instance_id = $3)",
expectedArgs: []interface{}{
true,
"agg-id",
@@ -1283,7 +1283,7 @@ func TestUserProjection_reduces(t *testing.T) {
},
},
{
- expectedStmt: "INSERT INTO projections.users3_notifications (user_id, instance_id, verified_email) SELECT user_id, instance_id, last_email FROM projections.users3_notifications AS copy_table WHERE copy_table.user_id = $1 AND copy_table.instance_id = $2 ON CONFLICT (user_id, instance_id) DO UPDATE SET (user_id, instance_id, verified_email) = (EXCLUDED.user_id, EXCLUDED.instance_id, EXCLUDED.last_email)",
+ expectedStmt: "UPDATE projections.users4_notifications SET verified_email = last_email WHERE (user_id = $1) AND (instance_id = $2)",
expectedArgs: []interface{}{
"agg-id",
"instance-id",
@@ -1311,7 +1311,7 @@ func TestUserProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
- expectedStmt: "UPDATE projections.users3 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)",
+ expectedStmt: "UPDATE projections.users4 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)",
expectedArgs: []interface{}{
anyArg{},
uint64(15),
@@ -1320,7 +1320,7 @@ func TestUserProjection_reduces(t *testing.T) {
},
},
{
- expectedStmt: "UPDATE projections.users3_humans SET is_email_verified = $1 WHERE (user_id = $2) AND (instance_id = $3)",
+ expectedStmt: "UPDATE projections.users4_humans SET is_email_verified = $1 WHERE (user_id = $2) AND (instance_id = $3)",
expectedArgs: []interface{}{
true,
"agg-id",
@@ -1328,7 +1328,7 @@ func TestUserProjection_reduces(t *testing.T) {
},
},
{
- expectedStmt: "INSERT INTO projections.users3_notifications (user_id, instance_id, verified_email) SELECT user_id, instance_id, last_email FROM projections.users3_notifications AS copy_table WHERE copy_table.user_id = $1 AND copy_table.instance_id = $2 ON CONFLICT (user_id, instance_id) DO UPDATE SET (user_id, instance_id, verified_email) = (EXCLUDED.user_id, EXCLUDED.instance_id, EXCLUDED.last_email)",
+ expectedStmt: "UPDATE projections.users4_notifications SET verified_email = last_email WHERE (user_id = $1) AND (instance_id = $2)",
expectedArgs: []interface{}{
"agg-id",
"instance-id",
@@ -1358,7 +1358,7 @@ func TestUserProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
- expectedStmt: "UPDATE projections.users3 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)",
+ expectedStmt: "UPDATE projections.users4 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)",
expectedArgs: []interface{}{
anyArg{},
uint64(15),
@@ -1367,7 +1367,7 @@ func TestUserProjection_reduces(t *testing.T) {
},
},
{
- expectedStmt: "UPDATE projections.users3_humans SET avatar_key = $1 WHERE (user_id = $2) AND (instance_id = $3)",
+ expectedStmt: "UPDATE projections.users4_humans SET avatar_key = $1 WHERE (user_id = $2) AND (instance_id = $3)",
expectedArgs: []interface{}{
"users/agg-id/avatar",
"agg-id",
@@ -1396,7 +1396,7 @@ func TestUserProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
- expectedStmt: "UPDATE projections.users3 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)",
+ expectedStmt: "UPDATE projections.users4 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)",
expectedArgs: []interface{}{
anyArg{},
uint64(15),
@@ -1405,7 +1405,7 @@ func TestUserProjection_reduces(t *testing.T) {
},
},
{
- expectedStmt: "UPDATE projections.users3_humans SET avatar_key = $1 WHERE (user_id = $2) AND (instance_id = $3)",
+ expectedStmt: "UPDATE projections.users4_humans SET avatar_key = $1 WHERE (user_id = $2) AND (instance_id = $3)",
expectedArgs: []interface{}{
nil,
"agg-id",
@@ -1437,7 +1437,7 @@ func TestUserProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
- expectedStmt: "INSERT INTO projections.users3 (id, creation_date, change_date, resource_owner, instance_id, state, sequence, username, type) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)",
+ expectedStmt: "INSERT INTO projections.users4 (id, creation_date, change_date, resource_owner, instance_id, state, sequence, username, type) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)",
expectedArgs: []interface{}{
"agg-id",
anyArg{},
@@ -1451,7 +1451,7 @@ func TestUserProjection_reduces(t *testing.T) {
},
},
{
- expectedStmt: "INSERT INTO projections.users3_machines (user_id, instance_id, name, description) VALUES ($1, $2, $3, $4)",
+ expectedStmt: "INSERT INTO projections.users4_machines (user_id, instance_id, name, description) VALUES ($1, $2, $3, $4)",
expectedArgs: []interface{}{
"agg-id",
"instance-id",
@@ -1485,7 +1485,7 @@ func TestUserProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
- expectedStmt: "INSERT INTO projections.users3 (id, creation_date, change_date, resource_owner, instance_id, state, sequence, username, type) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)",
+ expectedStmt: "INSERT INTO projections.users4 (id, creation_date, change_date, resource_owner, instance_id, state, sequence, username, type) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)",
expectedArgs: []interface{}{
"agg-id",
anyArg{},
@@ -1499,7 +1499,7 @@ func TestUserProjection_reduces(t *testing.T) {
},
},
{
- expectedStmt: "INSERT INTO projections.users3_machines (user_id, instance_id, name, description) VALUES ($1, $2, $3, $4)",
+ expectedStmt: "INSERT INTO projections.users4_machines (user_id, instance_id, name, description) VALUES ($1, $2, $3, $4)",
expectedArgs: []interface{}{
"agg-id",
"instance-id",
@@ -1532,7 +1532,7 @@ func TestUserProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
- expectedStmt: "UPDATE projections.users3 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)",
+ expectedStmt: "UPDATE projections.users4 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)",
expectedArgs: []interface{}{
anyArg{},
uint64(15),
@@ -1541,7 +1541,7 @@ func TestUserProjection_reduces(t *testing.T) {
},
},
{
- expectedStmt: "UPDATE projections.users3_machines SET (name, description) = ($1, $2) WHERE (user_id = $3) AND (instance_id = $4)",
+ expectedStmt: "UPDATE projections.users4_machines SET (name, description) = ($1, $2) WHERE (user_id = $3) AND (instance_id = $4)",
expectedArgs: []interface{}{
"machine-name",
"description",
@@ -1573,7 +1573,7 @@ func TestUserProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
- expectedStmt: "UPDATE projections.users3 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)",
+ expectedStmt: "UPDATE projections.users4 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)",
expectedArgs: []interface{}{
anyArg{},
uint64(15),
@@ -1582,7 +1582,7 @@ func TestUserProjection_reduces(t *testing.T) {
},
},
{
- expectedStmt: "UPDATE projections.users3_machines SET name = $1 WHERE (user_id = $2) AND (instance_id = $3)",
+ expectedStmt: "UPDATE projections.users4_machines SET name = $1 WHERE (user_id = $2) AND (instance_id = $3)",
expectedArgs: []interface{}{
"machine-name",
"agg-id",
@@ -1613,7 +1613,7 @@ func TestUserProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
- expectedStmt: "UPDATE projections.users3 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)",
+ expectedStmt: "UPDATE projections.users4 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)",
expectedArgs: []interface{}{
anyArg{},
uint64(15),
@@ -1622,7 +1622,7 @@ func TestUserProjection_reduces(t *testing.T) {
},
},
{
- expectedStmt: "UPDATE projections.users3_machines SET description = $1 WHERE (user_id = $2) AND (instance_id = $3)",
+ expectedStmt: "UPDATE projections.users4_machines SET description = $1 WHERE (user_id = $2) AND (instance_id = $3)",
expectedArgs: []interface{}{
"description",
"agg-id",
diff --git a/internal/query/user.go b/internal/query/user.go
index d001a6625..f75bab56e 100644
--- a/internal/query/user.go
+++ b/internal/query/user.go
@@ -388,7 +388,7 @@ func (q *Queries) GetHumanPhone(ctx context.Context, userID string, queries ...S
return scan(row)
}
-func (q *Queries) GeNotifyUser(ctx context.Context, shouldTriggered bool, userID string, queries ...SearchQuery) (*NotifyUser, error) {
+func (q *Queries) GetNotifyUserByID(ctx context.Context, shouldTriggered bool, userID string, queries ...SearchQuery) (*NotifyUser, error) {
if shouldTriggered {
projection.UserProjection.Trigger(ctx)
projection.LoginNameProjection.Trigger(ctx)
@@ -411,6 +411,28 @@ func (q *Queries) GeNotifyUser(ctx context.Context, shouldTriggered bool, userID
return scan(row)
}
+func (q *Queries) GetNotifyUser(ctx context.Context, shouldTriggered bool, queries ...SearchQuery) (*NotifyUser, error) {
+ if shouldTriggered {
+ projection.UserProjection.Trigger(ctx)
+ projection.LoginNameProjection.Trigger(ctx)
+ }
+
+ instanceID := authz.GetInstance(ctx).InstanceID()
+ query, scan := prepareNotifyUserQuery(instanceID)
+ for _, q := range queries {
+ query = q.toQuery(query)
+ }
+ stmt, args, err := query.Where(sq.Eq{
+ UserInstanceIDCol.identifier(): instanceID,
+ }).ToSql()
+ if err != nil {
+ return nil, errors.ThrowInternal(err, "QUERY-Err3g", "Errors.Query.SQLStatment")
+ }
+
+ row := q.client.QueryRowContext(ctx, stmt, args...)
+ return scan(row)
+}
+
func (q *Queries) SearchUsers(ctx context.Context, queries *UserSearchQueries) (*Users, error) {
query, scan := prepareUsersQuery()
stmt, args, err := queries.toQuery(query).
@@ -492,27 +514,39 @@ func NewUserResourceOwnerSearchQuery(value string, comparison TextComparison) (S
}
func NewUserUsernameSearchQuery(value string, comparison TextComparison) (SearchQuery, error) {
- return NewTextQuery(Column(UserUsernameCol), value, comparison)
+ return NewTextQuery(UserUsernameCol, value, comparison)
}
func NewUserFirstNameSearchQuery(value string, comparison TextComparison) (SearchQuery, error) {
- return NewTextQuery(Column(HumanFirstNameCol), value, comparison)
+ return NewTextQuery(HumanFirstNameCol, value, comparison)
}
func NewUserLastNameSearchQuery(value string, comparison TextComparison) (SearchQuery, error) {
- return NewTextQuery(Column(HumanLastNameCol), value, comparison)
+ return NewTextQuery(HumanLastNameCol, value, comparison)
}
func NewUserNickNameSearchQuery(value string, comparison TextComparison) (SearchQuery, error) {
- return NewTextQuery(Column(HumanNickNameCol), value, comparison)
+ return NewTextQuery(HumanNickNameCol, value, comparison)
}
func NewUserDisplayNameSearchQuery(value string, comparison TextComparison) (SearchQuery, error) {
- return NewTextQuery(Column(HumanDisplayNameCol), value, comparison)
+ return NewTextQuery(HumanDisplayNameCol, value, comparison)
}
func NewUserEmailSearchQuery(value string, comparison TextComparison) (SearchQuery, error) {
- return NewTextQuery(Column(HumanEmailCol), value, comparison)
+ return NewTextQuery(HumanEmailCol, value, comparison)
+}
+
+func NewUserPhoneSearchQuery(value string, comparison TextComparison) (SearchQuery, error) {
+ return NewTextQuery(HumanPhoneCol, value, comparison)
+}
+
+func NewUserVerifiedEmailSearchQuery(value string, comparison TextComparison) (SearchQuery, error) {
+ return NewTextQuery(NotifyVerifiedEmailCol, value, comparison)
+}
+
+func NewUserVerifiedPhoneSearchQuery(value string, comparison TextComparison) (SearchQuery, error) {
+ return NewTextQuery(NotifyVerifiedPhoneCol, value, comparison)
}
func NewUserStateSearchQuery(value int32) (SearchQuery, error) {
@@ -580,6 +614,7 @@ func prepareUserQuery(instanceID string) (sq.SelectBuilder, func(*sql.Row) (*Use
MachineUserIDCol.identifier(),
MachineNameCol.identifier(),
MachineDescriptionCol.identifier(),
+ countColumn.identifier(),
).
From(userTable.identifier()).
LeftJoin(join(HumanUserIDCol, UserIDCol)).
@@ -589,6 +624,7 @@ func prepareUserQuery(instanceID string) (sq.SelectBuilder, func(*sql.Row) (*Use
PlaceholderFormat(sq.Dollar),
func(row *sql.Row) (*User, error) {
u := new(User)
+ var count int
preferredLoginName := sql.NullString{}
humanID := sql.NullString{}
@@ -634,10 +670,11 @@ func prepareUserQuery(instanceID string) (sq.SelectBuilder, func(*sql.Row) (*Use
&machineID,
&name,
&description,
+ &count,
)
- if err != nil {
- if errs.Is(err, sql.ErrNoRows) {
+ if err != nil || count != 1 {
+ if errs.Is(err, sql.ErrNoRows) || count != 1 {
return nil, errors.ThrowNotFound(err, "QUERY-Dfbg2", "Errors.User.NotFound")
}
return nil, errors.ThrowInternal(err, "QUERY-Bgah2", "Errors.Internal")
@@ -877,6 +914,7 @@ func prepareNotifyUserQuery(instanceID string) (sq.SelectBuilder, func(*sql.Row)
NotifyPhoneCol.identifier(),
NotifyVerifiedPhoneCol.identifier(),
NotifyPasswordSetCol.identifier(),
+ countColumn.identifier(),
).
From(userTable.identifier()).
LeftJoin(join(HumanUserIDCol, UserIDCol)).
@@ -886,6 +924,7 @@ func prepareNotifyUserQuery(instanceID string) (sq.SelectBuilder, func(*sql.Row)
PlaceholderFormat(sq.Dollar),
func(row *sql.Row) (*NotifyUser, error) {
u := new(NotifyUser)
+ var count int
loginNames := database.StringArray{}
preferredLoginName := sql.NullString{}
@@ -930,10 +969,11 @@ func prepareNotifyUserQuery(instanceID string) (sq.SelectBuilder, func(*sql.Row)
¬ifyPhone,
¬ifyVerifiedPhone,
¬ifyPasswordSet,
+ &count,
)
- if err != nil {
- if errs.Is(err, sql.ErrNoRows) {
+ if err != nil || count != 1 {
+ if errs.Is(err, sql.ErrNoRows) || count != 1 {
return nil, errors.ThrowNotFound(err, "QUERY-Dgqd2", "Errors.User.NotFound")
}
return nil, errors.ThrowInternal(err, "QUERY-Dbwsg", "Errors.Internal")
diff --git a/internal/query/user_grant_test.go b/internal/query/user_grant_test.go
index 37f19512c..d06fd0ad6 100644
--- a/internal/query/user_grant_test.go
+++ b/internal/query/user_grant_test.go
@@ -23,14 +23,14 @@ var (
", projections.user_grants2.roles" +
", projections.user_grants2.state" +
", projections.user_grants2.user_id" +
- ", projections.users3.username" +
- ", projections.users3.type" +
- ", projections.users3.resource_owner" +
- ", projections.users3_humans.first_name" +
- ", projections.users3_humans.last_name" +
- ", projections.users3_humans.email" +
- ", projections.users3_humans.display_name" +
- ", projections.users3_humans.avatar_key" +
+ ", projections.users4.username" +
+ ", projections.users4.type" +
+ ", projections.users4.resource_owner" +
+ ", projections.users4_humans.first_name" +
+ ", projections.users4_humans.last_name" +
+ ", projections.users4_humans.email" +
+ ", projections.users4_humans.display_name" +
+ ", projections.users4_humans.avatar_key" +
", projections.login_names.login_name" +
", projections.user_grants2.resource_owner" +
", projections.orgs.name" +
@@ -38,8 +38,8 @@ var (
", projections.user_grants2.project_id" +
", projections.projects2.name" +
" FROM projections.user_grants2" +
- " LEFT JOIN projections.users3 ON projections.user_grants2.user_id = projections.users3.id" +
- " LEFT JOIN projections.users3_humans ON projections.user_grants2.user_id = projections.users3_humans.user_id" +
+ " LEFT JOIN projections.users4 ON projections.user_grants2.user_id = projections.users4.id" +
+ " LEFT JOIN projections.users4_humans ON projections.user_grants2.user_id = projections.users4_humans.user_id" +
" LEFT JOIN projections.orgs ON projections.user_grants2.resource_owner = projections.orgs.id" +
" LEFT JOIN projections.projects2 ON projections.user_grants2.project_id = projections.projects2.id" +
" LEFT JOIN projections.login_names ON projections.user_grants2.user_id = projections.login_names.user_id" +
@@ -77,14 +77,14 @@ var (
", projections.user_grants2.roles" +
", projections.user_grants2.state" +
", projections.user_grants2.user_id" +
- ", projections.users3.username" +
- ", projections.users3.type" +
- ", projections.users3.resource_owner" +
- ", projections.users3_humans.first_name" +
- ", projections.users3_humans.last_name" +
- ", projections.users3_humans.email" +
- ", projections.users3_humans.display_name" +
- ", projections.users3_humans.avatar_key" +
+ ", projections.users4.username" +
+ ", projections.users4.type" +
+ ", projections.users4.resource_owner" +
+ ", projections.users4_humans.first_name" +
+ ", projections.users4_humans.last_name" +
+ ", projections.users4_humans.email" +
+ ", projections.users4_humans.display_name" +
+ ", projections.users4_humans.avatar_key" +
", projections.login_names.login_name" +
", projections.user_grants2.resource_owner" +
", projections.orgs.name" +
@@ -93,8 +93,8 @@ var (
", projections.projects2.name" +
", COUNT(*) OVER ()" +
" FROM projections.user_grants2" +
- " LEFT JOIN projections.users3 ON projections.user_grants2.user_id = projections.users3.id" +
- " LEFT JOIN projections.users3_humans ON projections.user_grants2.user_id = projections.users3_humans.user_id" +
+ " LEFT JOIN projections.users4 ON projections.user_grants2.user_id = projections.users4.id" +
+ " LEFT JOIN projections.users4_humans ON projections.user_grants2.user_id = projections.users4_humans.user_id" +
" LEFT JOIN projections.orgs ON projections.user_grants2.resource_owner = projections.orgs.id" +
" LEFT JOIN projections.projects2 ON projections.user_grants2.project_id = projections.projects2.id" +
" LEFT JOIN projections.login_names ON projections.user_grants2.user_id = projections.login_names.user_id" +
diff --git a/internal/query/user_test.go b/internal/query/user_test.go
index d9c2ac541..109399c83 100644
--- a/internal/query/user_test.go
+++ b/internal/query/user_test.go
@@ -17,43 +17,44 @@ import (
)
var (
- userQuery = `SELECT projections.users3.id,` +
- ` projections.users3.creation_date,` +
- ` projections.users3.change_date,` +
- ` projections.users3.resource_owner,` +
- ` projections.users3.sequence,` +
- ` projections.users3.state,` +
- ` projections.users3.type,` +
- ` projections.users3.username,` +
+ userQuery = `SELECT projections.users4.id,` +
+ ` projections.users4.creation_date,` +
+ ` projections.users4.change_date,` +
+ ` projections.users4.resource_owner,` +
+ ` projections.users4.sequence,` +
+ ` projections.users4.state,` +
+ ` projections.users4.type,` +
+ ` projections.users4.username,` +
` login_names.loginnames,` +
` preferred_login_name.login_name,` +
- ` projections.users3_humans.user_id,` +
- ` projections.users3_humans.first_name,` +
- ` projections.users3_humans.last_name,` +
- ` projections.users3_humans.nick_name,` +
- ` projections.users3_humans.display_name,` +
- ` projections.users3_humans.preferred_language,` +
- ` projections.users3_humans.gender,` +
- ` projections.users3_humans.avatar_key,` +
- ` projections.users3_humans.email,` +
- ` projections.users3_humans.is_email_verified,` +
- ` projections.users3_humans.phone,` +
- ` projections.users3_humans.is_phone_verified,` +
- ` projections.users3_machines.user_id,` +
- ` projections.users3_machines.name,` +
- ` projections.users3_machines.description` +
- ` FROM projections.users3` +
- ` LEFT JOIN projections.users3_humans ON projections.users3.id = projections.users3_humans.user_id` +
- ` LEFT JOIN projections.users3_machines ON projections.users3.id = projections.users3_machines.user_id` +
+ ` projections.users4_humans.user_id,` +
+ ` projections.users4_humans.first_name,` +
+ ` projections.users4_humans.last_name,` +
+ ` projections.users4_humans.nick_name,` +
+ ` projections.users4_humans.display_name,` +
+ ` projections.users4_humans.preferred_language,` +
+ ` projections.users4_humans.gender,` +
+ ` projections.users4_humans.avatar_key,` +
+ ` projections.users4_humans.email,` +
+ ` projections.users4_humans.is_email_verified,` +
+ ` projections.users4_humans.phone,` +
+ ` projections.users4_humans.is_phone_verified,` +
+ ` projections.users4_machines.user_id,` +
+ ` projections.users4_machines.name,` +
+ ` projections.users4_machines.description,` +
+ ` COUNT(*) OVER ()` +
+ ` FROM projections.users4` +
+ ` LEFT JOIN projections.users4_humans ON projections.users4.id = projections.users4_humans.user_id` +
+ ` LEFT JOIN projections.users4_machines ON projections.users4.id = projections.users4_machines.user_id` +
` LEFT JOIN` +
` (SELECT login_names.user_id, ARRAY_AGG(login_names.login_name)::TEXT[] AS loginnames` +
` FROM projections.login_names AS login_names` +
` WHERE login_names.instance_id = $1` +
` GROUP BY login_names.user_id) AS login_names` +
- ` ON login_names.user_id = projections.users3.id` +
+ ` ON login_names.user_id = projections.users4.id` +
` LEFT JOIN` +
` (SELECT preferred_login_name.user_id, preferred_login_name.login_name FROM projections.login_names AS preferred_login_name WHERE preferred_login_name.instance_id = $2 AND preferred_login_name.is_primary = $3) AS preferred_login_name` +
- ` ON preferred_login_name.user_id = projections.users3.id`
+ ` ON preferred_login_name.user_id = projections.users4.id`
userCols = []string{
"id",
"creation_date",
@@ -82,22 +83,23 @@ var (
"user_id",
"name",
"description",
+ "count",
}
- profileQuery = `SELECT projections.users3.id,` +
- ` projections.users3.creation_date,` +
- ` projections.users3.change_date,` +
- ` projections.users3.resource_owner,` +
- ` projections.users3.sequence,` +
- ` projections.users3_humans.user_id,` +
- ` projections.users3_humans.first_name,` +
- ` projections.users3_humans.last_name,` +
- ` projections.users3_humans.nick_name,` +
- ` projections.users3_humans.display_name,` +
- ` projections.users3_humans.preferred_language,` +
- ` projections.users3_humans.gender,` +
- ` projections.users3_humans.avatar_key` +
- ` FROM projections.users3` +
- ` LEFT JOIN projections.users3_humans ON projections.users3.id = projections.users3_humans.user_id`
+ profileQuery = `SELECT projections.users4.id,` +
+ ` projections.users4.creation_date,` +
+ ` projections.users4.change_date,` +
+ ` projections.users4.resource_owner,` +
+ ` projections.users4.sequence,` +
+ ` projections.users4_humans.user_id,` +
+ ` projections.users4_humans.first_name,` +
+ ` projections.users4_humans.last_name,` +
+ ` projections.users4_humans.nick_name,` +
+ ` projections.users4_humans.display_name,` +
+ ` projections.users4_humans.preferred_language,` +
+ ` projections.users4_humans.gender,` +
+ ` projections.users4_humans.avatar_key` +
+ ` FROM projections.users4` +
+ ` LEFT JOIN projections.users4_humans ON projections.users4.id = projections.users4_humans.user_id`
profileCols = []string{
"id",
"creation_date",
@@ -113,16 +115,16 @@ var (
"gender",
"avatar_key",
}
- emailQuery = `SELECT projections.users3.id,` +
- ` projections.users3.creation_date,` +
- ` projections.users3.change_date,` +
- ` projections.users3.resource_owner,` +
- ` projections.users3.sequence,` +
- ` projections.users3_humans.user_id,` +
- ` projections.users3_humans.email,` +
- ` projections.users3_humans.is_email_verified` +
- ` FROM projections.users3` +
- ` LEFT JOIN projections.users3_humans ON projections.users3.id = projections.users3_humans.user_id`
+ emailQuery = `SELECT projections.users4.id,` +
+ ` projections.users4.creation_date,` +
+ ` projections.users4.change_date,` +
+ ` projections.users4.resource_owner,` +
+ ` projections.users4.sequence,` +
+ ` projections.users4_humans.user_id,` +
+ ` projections.users4_humans.email,` +
+ ` projections.users4_humans.is_email_verified` +
+ ` FROM projections.users4` +
+ ` LEFT JOIN projections.users4_humans ON projections.users4.id = projections.users4_humans.user_id`
emailCols = []string{
"id",
"creation_date",
@@ -133,16 +135,16 @@ var (
"email",
"is_email_verified",
}
- phoneQuery = `SELECT projections.users3.id,` +
- ` projections.users3.creation_date,` +
- ` projections.users3.change_date,` +
- ` projections.users3.resource_owner,` +
- ` projections.users3.sequence,` +
- ` projections.users3_humans.user_id,` +
- ` projections.users3_humans.phone,` +
- ` projections.users3_humans.is_phone_verified` +
- ` FROM projections.users3` +
- ` LEFT JOIN projections.users3_humans ON projections.users3.id = projections.users3_humans.user_id`
+ phoneQuery = `SELECT projections.users4.id,` +
+ ` projections.users4.creation_date,` +
+ ` projections.users4.change_date,` +
+ ` projections.users4.resource_owner,` +
+ ` projections.users4.sequence,` +
+ ` projections.users4_humans.user_id,` +
+ ` projections.users4_humans.phone,` +
+ ` projections.users4_humans.is_phone_verified` +
+ ` FROM projections.users4` +
+ ` LEFT JOIN projections.users4_humans ON projections.users4.id = projections.users4_humans.user_id`
phoneCols = []string{
"id",
"creation_date",
@@ -153,14 +155,14 @@ var (
"phone",
"is_phone_verified",
}
- userUniqueQuery = `SELECT projections.users3.id,` +
- ` projections.users3.state,` +
- ` projections.users3.username,` +
- ` projections.users3_humans.user_id,` +
- ` projections.users3_humans.email,` +
- ` projections.users3_humans.is_email_verified` +
- ` FROM projections.users3` +
- ` LEFT JOIN projections.users3_humans ON projections.users3.id = projections.users3_humans.user_id`
+ userUniqueQuery = `SELECT projections.users4.id,` +
+ ` projections.users4.state,` +
+ ` projections.users4.username,` +
+ ` projections.users4_humans.user_id,` +
+ ` projections.users4_humans.email,` +
+ ` projections.users4_humans.is_email_verified` +
+ ` FROM projections.users4` +
+ ` LEFT JOIN projections.users4_humans ON projections.users4.id = projections.users4_humans.user_id`
userUniqueCols = []string{
"id",
"state",
@@ -169,42 +171,43 @@ var (
"email",
"is_email_verified",
}
- notifyUserQuery = `SELECT projections.users3.id,` +
- ` projections.users3.creation_date,` +
- ` projections.users3.change_date,` +
- ` projections.users3.resource_owner,` +
- ` projections.users3.sequence,` +
- ` projections.users3.state,` +
- ` projections.users3.type,` +
- ` projections.users3.username,` +
+ notifyUserQuery = `SELECT projections.users4.id,` +
+ ` projections.users4.creation_date,` +
+ ` projections.users4.change_date,` +
+ ` projections.users4.resource_owner,` +
+ ` projections.users4.sequence,` +
+ ` projections.users4.state,` +
+ ` projections.users4.type,` +
+ ` projections.users4.username,` +
` login_names.loginnames,` +
` preferred_login_name.login_name,` +
- ` projections.users3_humans.user_id,` +
- ` projections.users3_humans.first_name,` +
- ` projections.users3_humans.last_name,` +
- ` projections.users3_humans.nick_name,` +
- ` projections.users3_humans.display_name,` +
- ` projections.users3_humans.preferred_language,` +
- ` projections.users3_humans.gender,` +
- ` projections.users3_humans.avatar_key,` +
- ` projections.users3_notifications.user_id,` +
- ` projections.users3_notifications.last_email,` +
- ` projections.users3_notifications.verified_email,` +
- ` projections.users3_notifications.last_phone,` +
- ` projections.users3_notifications.verified_phone,` +
- ` projections.users3_notifications.password_set` +
- ` FROM projections.users3` +
- ` LEFT JOIN projections.users3_humans ON projections.users3.id = projections.users3_humans.user_id` +
- ` LEFT JOIN projections.users3_notifications ON projections.users3.id = projections.users3_notifications.user_id` +
+ ` projections.users4_humans.user_id,` +
+ ` projections.users4_humans.first_name,` +
+ ` projections.users4_humans.last_name,` +
+ ` projections.users4_humans.nick_name,` +
+ ` projections.users4_humans.display_name,` +
+ ` projections.users4_humans.preferred_language,` +
+ ` projections.users4_humans.gender,` +
+ ` projections.users4_humans.avatar_key,` +
+ ` projections.users4_notifications.user_id,` +
+ ` projections.users4_notifications.last_email,` +
+ ` projections.users4_notifications.verified_email,` +
+ ` projections.users4_notifications.last_phone,` +
+ ` projections.users4_notifications.verified_phone,` +
+ ` projections.users4_notifications.password_set,` +
+ ` COUNT(*) OVER ()` +
+ ` FROM projections.users4` +
+ ` LEFT JOIN projections.users4_humans ON projections.users4.id = projections.users4_humans.user_id` +
+ ` LEFT JOIN projections.users4_notifications ON projections.users4.id = projections.users4_notifications.user_id` +
` LEFT JOIN` +
` (SELECT login_names.user_id, ARRAY_AGG(login_names.login_name) AS loginnames` +
` FROM projections.login_names AS login_names` +
` WHERE login_names.instance_id = $1` +
` GROUP BY login_names.user_id) AS login_names` +
- ` ON login_names.user_id = projections.users3.id` +
+ ` ON login_names.user_id = projections.users4.id` +
` LEFT JOIN` +
` (SELECT preferred_login_name.user_id, preferred_login_name.login_name FROM projections.login_names AS preferred_login_name WHERE preferred_login_name.instance_id = $2 AND preferred_login_name.is_primary = $3) AS preferred_login_name` +
- ` ON preferred_login_name.user_id = projections.users3.id`
+ ` ON preferred_login_name.user_id = projections.users4.id`
notifyUserCols = []string{
"id",
"creation_date",
@@ -232,44 +235,45 @@ var (
"last_phone",
"verified_phone",
"password_set",
+ "count",
}
- usersQuery = `SELECT projections.users3.id,` +
- ` projections.users3.creation_date,` +
- ` projections.users3.change_date,` +
- ` projections.users3.resource_owner,` +
- ` projections.users3.sequence,` +
- ` projections.users3.state,` +
- ` projections.users3.type,` +
- ` projections.users3.username,` +
+ usersQuery = `SELECT projections.users4.id,` +
+ ` projections.users4.creation_date,` +
+ ` projections.users4.change_date,` +
+ ` projections.users4.resource_owner,` +
+ ` projections.users4.sequence,` +
+ ` projections.users4.state,` +
+ ` projections.users4.type,` +
+ ` projections.users4.username,` +
` login_names.loginnames,` +
` preferred_login_name.login_name,` +
- ` projections.users3_humans.user_id,` +
- ` projections.users3_humans.first_name,` +
- ` projections.users3_humans.last_name,` +
- ` projections.users3_humans.nick_name,` +
- ` projections.users3_humans.display_name,` +
- ` projections.users3_humans.preferred_language,` +
- ` projections.users3_humans.gender,` +
- ` projections.users3_humans.avatar_key,` +
- ` projections.users3_humans.email,` +
- ` projections.users3_humans.is_email_verified,` +
- ` projections.users3_humans.phone,` +
- ` projections.users3_humans.is_phone_verified,` +
- ` projections.users3_machines.user_id,` +
- ` projections.users3_machines.name,` +
- ` projections.users3_machines.description,` +
+ ` projections.users4_humans.user_id,` +
+ ` projections.users4_humans.first_name,` +
+ ` projections.users4_humans.last_name,` +
+ ` projections.users4_humans.nick_name,` +
+ ` projections.users4_humans.display_name,` +
+ ` projections.users4_humans.preferred_language,` +
+ ` projections.users4_humans.gender,` +
+ ` projections.users4_humans.avatar_key,` +
+ ` projections.users4_humans.email,` +
+ ` projections.users4_humans.is_email_verified,` +
+ ` projections.users4_humans.phone,` +
+ ` projections.users4_humans.is_phone_verified,` +
+ ` projections.users4_machines.user_id,` +
+ ` projections.users4_machines.name,` +
+ ` projections.users4_machines.description,` +
` COUNT(*) OVER ()` +
- ` FROM projections.users3` +
- ` LEFT JOIN projections.users3_humans ON projections.users3.id = projections.users3_humans.user_id` +
- ` LEFT JOIN projections.users3_machines ON projections.users3.id = projections.users3_machines.user_id` +
+ ` FROM projections.users4` +
+ ` LEFT JOIN projections.users4_humans ON projections.users4.id = projections.users4_humans.user_id` +
+ ` LEFT JOIN projections.users4_machines ON projections.users4.id = projections.users4_machines.user_id` +
` LEFT JOIN` +
` (SELECT login_names.user_id, ARRAY_AGG(login_names.login_name) AS loginnames` +
` FROM projections.login_names AS login_names` +
` GROUP BY login_names.user_id) AS login_names` +
- ` ON login_names.user_id = projections.users3.id` +
+ ` ON login_names.user_id = projections.users4.id` +
` LEFT JOIN` +
` (SELECT preferred_login_name.user_id, preferred_login_name.login_name FROM projections.login_names AS preferred_login_name WHERE preferred_login_name.is_primary = $1) AS preferred_login_name` +
- ` ON preferred_login_name.user_id = projections.users3.id`
+ ` ON preferred_login_name.user_id = projections.users4.id`
usersCols = []string{
"id",
"creation_date",
@@ -370,6 +374,7 @@ func Test_UserPrepares(t *testing.T) {
nil,
nil,
nil,
+ 1,
},
),
},
@@ -436,6 +441,7 @@ func Test_UserPrepares(t *testing.T) {
"id",
"name",
"description",
+ 1,
},
),
},
@@ -879,6 +885,7 @@ func Test_UserPrepares(t *testing.T) {
"lastPhone",
"verifiedPhone",
true,
+ 1,
},
),
},
@@ -942,6 +949,7 @@ func Test_UserPrepares(t *testing.T) {
nil,
nil,
nil,
+ 1,
},
),
err: func(err error) (error, bool) {
diff --git a/internal/repository/instance/policy_login.go b/internal/repository/instance/policy_login.go
index 279ace4e3..fad06fa71 100644
--- a/internal/repository/instance/policy_login.go
+++ b/internal/repository/instance/policy_login.go
@@ -29,7 +29,9 @@ func NewLoginPolicyAddedEvent(
forceMFA,
hidePasswordReset,
ignoreUnknownUsernames,
- allowDomainDiscovery bool,
+ allowDomainDiscovery,
+ disableLoginWithEmail,
+ disableLoginWithPhone bool,
passwordlessType domain.PasswordlessType,
defaultRedirectURI string,
passwordCheckLifetime,
@@ -51,6 +53,8 @@ func NewLoginPolicyAddedEvent(
hidePasswordReset,
ignoreUnknownUsernames,
allowDomainDiscovery,
+ disableLoginWithEmail,
+ disableLoginWithPhone,
passwordlessType,
defaultRedirectURI,
passwordCheckLifetime,
diff --git a/internal/repository/org/policy_login.go b/internal/repository/org/policy_login.go
index 915be8718..449e3e10a 100644
--- a/internal/repository/org/policy_login.go
+++ b/internal/repository/org/policy_login.go
@@ -30,7 +30,9 @@ func NewLoginPolicyAddedEvent(
forceMFA,
hidePasswordReset,
ignoreUnknownUsernames,
- allowDomainDiscovery bool,
+ allowDomainDiscovery,
+ disableLoginWithEmail,
+ disableLoginWithPhone bool,
passwordlessType domain.PasswordlessType,
defaultRedirectURI string,
passwordCheckLifetime,
@@ -52,13 +54,16 @@ func NewLoginPolicyAddedEvent(
hidePasswordReset,
ignoreUnknownUsernames,
allowDomainDiscovery,
+ disableLoginWithEmail,
+ disableLoginWithPhone,
passwordlessType,
defaultRedirectURI,
passwordCheckLifetime,
externalLoginCheckLifetime,
mfaInitSkipLifetime,
secondFactorCheckLifetime,
- multiFactorCheckLifetime),
+ multiFactorCheckLifetime,
+ ),
}
}
diff --git a/internal/repository/policy/login.go b/internal/repository/policy/login.go
index e86472ab8..dfd2d0afd 100644
--- a/internal/repository/policy/login.go
+++ b/internal/repository/policy/login.go
@@ -27,6 +27,8 @@ type LoginPolicyAddedEvent struct {
HidePasswordReset bool `json:"hidePasswordReset,omitempty"`
IgnoreUnknownUsernames bool `json:"ignoreUnknownUsernames,omitempty"`
AllowDomainDiscovery bool `json:"allowDomainDiscovery,omitempty"`
+ DisableLoginWithEmail bool `json:"disableLoginWithEmail,omitempty"`
+ DisableLoginWithPhone bool `json:"disableLoginWithPhone,omitempty"`
PasswordlessType domain.PasswordlessType `json:"passwordlessType,omitempty"`
DefaultRedirectURI string `json:"defaultRedirectURI,omitempty"`
PasswordCheckLifetime time.Duration `json:"passwordCheckLifetime,omitempty"`
@@ -52,7 +54,9 @@ func NewLoginPolicyAddedEvent(
forceMFA,
hidePasswordReset,
ignoreUnknownUsernames,
- allowDomainDiscovery bool,
+ allowDomainDiscovery,
+ disableLoginWithEmail,
+ disableLoginWithPhone bool,
passwordlessType domain.PasswordlessType,
defaultRedirectURI string,
passwordCheckLifetime,
@@ -77,6 +81,8 @@ func NewLoginPolicyAddedEvent(
MFAInitSkipLifetime: mfaInitSkipLifetime,
SecondFactorCheckLifetime: secondFactorCheckLifetime,
MultiFactorCheckLifetime: multiFactorCheckLifetime,
+ DisableLoginWithEmail: disableLoginWithEmail,
+ DisableLoginWithPhone: disableLoginWithPhone,
}
}
@@ -103,6 +109,8 @@ type LoginPolicyChangedEvent struct {
HidePasswordReset *bool `json:"hidePasswordReset,omitempty"`
IgnoreUnknownUsernames *bool `json:"ignoreUnknownUsernames,omitempty"`
AllowDomainDiscovery *bool `json:"allowDomainDiscovery,omitempty"`
+ DisableLoginWithEmail *bool `json:"disableLoginWithEmail,omitempty"`
+ DisableLoginWithPhone *bool `json:"disableLoginWithPhone,omitempty"`
PasswordlessType *domain.PasswordlessType `json:"passwordlessType,omitempty"`
DefaultRedirectURI *string `json:"defaultRedirectURI,omitempty"`
PasswordCheckLifetime *time.Duration `json:"passwordCheckLifetime,omitempty"`
@@ -222,6 +230,18 @@ func ChangeDefaultRedirectURI(defaultRedirectURI string) func(*LoginPolicyChange
}
}
+func ChangeDisableLoginWithEmail(disableLoginWithEmail bool) func(*LoginPolicyChangedEvent) {
+ return func(e *LoginPolicyChangedEvent) {
+ e.DisableLoginWithEmail = &disableLoginWithEmail
+ }
+}
+
+func ChangeDisableLoginWithPhone(DisableLoginWithPhone bool) func(*LoginPolicyChangedEvent) {
+ return func(e *LoginPolicyChangedEvent) {
+ e.DisableLoginWithPhone = &DisableLoginWithPhone
+ }
+}
+
func LoginPolicyChangedEventMapper(event *repository.Event) (eventstore.Event, error) {
e := &LoginPolicyChangedEvent{
BaseEvent: *eventstore.BaseEventFromRepo(event),
diff --git a/proto/zitadel/admin.proto b/proto/zitadel/admin.proto
index 2178f50d5..9585fea10 100644
--- a/proto/zitadel/admin.proto
+++ b/proto/zitadel/admin.proto
@@ -3916,6 +3916,16 @@ message UpdateLoginPolicyRequest {
description: "If set to true, the suffix (@domain.com) of an unknown username input on the login screen will be matched against the org domains and will redirect to the registration of that organisation on success."
}
];
+ bool disable_login_with_email = 15 [
+ (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
+ description: "defines if user can additionally (to the loginname) be identified by their verified email address"
+ }
+ ];
+ bool disable_login_with_phone = 16 [
+ (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
+ description: "defines if user can additionally (to the loginname) be identified by their verified phone number"
+ }
+ ];
}
message UpdateLoginPolicyResponse {
diff --git a/proto/zitadel/management.proto b/proto/zitadel/management.proto
index cbf4021da..ce0f28f7f 100644
--- a/proto/zitadel/management.proto
+++ b/proto/zitadel/management.proto
@@ -4611,6 +4611,16 @@ message AddCustomLoginPolicyRequest {
description: "If set to true, the suffix (@domain.com) of an unknown username input on the login screen will be matched against the org domains and will redirect to the registration of that organisation on success."
}
];
+ bool disable_login_with_email = 18 [
+ (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
+ description: "defines if user can additionally (to the loginname) be identified by their verified email address"
+ }
+ ];
+ bool disable_login_with_phone = 19 [
+ (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
+ description: "defines if user can additionally (to the loginname) be identified by their verified phone number"
+ }
+ ];
}
message AddCustomLoginPolicyResponse {
@@ -4645,6 +4655,16 @@ message UpdateCustomLoginPolicyRequest {
description: "If set to true, the suffix (@domain.com) of an unknown username input on the login screen will be matched against the org domains and will redirect to the registration of that organisation on success."
}
];
+ bool disable_login_with_email = 15 [
+ (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
+ description: "defines if user can additionally (to the loginname) be identified by their verified email address"
+ }
+ ];
+ bool disable_login_with_phone = 16 [
+ (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
+ description: "defines if user can additionally (to the loginname) be identified by their verified phone number"
+ }
+ ];
}
message UpdateCustomLoginPolicyResponse {
diff --git a/proto/zitadel/policy.proto b/proto/zitadel/policy.proto
index 34920eefa..c2d0215ae 100644
--- a/proto/zitadel/policy.proto
+++ b/proto/zitadel/policy.proto
@@ -179,6 +179,16 @@ message LoginPolicy {
description: "If set to true, the suffix (@domain.com) of an unknown username input on the login screen will be matched against the org domains and will redirect to the registration of that organisation on success."
}
];
+ bool disable_login_with_email = 20 [
+ (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
+ description: "defines if user can additionally (to the loginname) be identified by their verified email address"
+ }
+ ];
+ bool disable_login_with_phone = 21 [
+ (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
+ description: "defines if user can additionally (to the loginname) be identified by their verified phone number"
+ }
+ ];
}
enum SecondFactorType {