mirror of
https://github.com/zitadel/zitadel.git
synced 2025-01-05 22:52:46 +00:00
feat(login): additionally use email/phone for authentication (#4563)
* feat: add ability to disable login by email and phone * feat: check login by email and phone * fix: set verified email / phone correctly on notify users * update projection version * fix merge * fix email/phone verified reduce tests * fix user tests * loginname check * cleanup * fix: update user projection version to handle fixed statement
This commit is contained in:
parent
9ae58b62fd
commit
b0b1e94090
@ -329,6 +329,50 @@
|
||||
</mat-checkbox>
|
||||
</div>
|
||||
|
||||
<div class="login-policy-row">
|
||||
<mat-checkbox
|
||||
class="login-policy-toggle"
|
||||
color="primary"
|
||||
ngDefaultControl
|
||||
[(ngModel)]="loginData.disableLoginWithEmail"
|
||||
[disabled]="
|
||||
([
|
||||
serviceType === PolicyComponentServiceType.ADMIN
|
||||
? 'iam.policy.write'
|
||||
: serviceType === PolicyComponentServiceType.MGMT
|
||||
? 'policy.write'
|
||||
: ''
|
||||
]
|
||||
| hasRole
|
||||
| async) === false
|
||||
"
|
||||
>
|
||||
{{ 'POLICY.DATA.DISABLELOGINWITHEMAIL' | translate }}
|
||||
</mat-checkbox>
|
||||
</div>
|
||||
|
||||
<div class="login-policy-row">
|
||||
<mat-checkbox
|
||||
class="login-policy-toggle"
|
||||
color="primary"
|
||||
ngDefaultControl
|
||||
[(ngModel)]="loginData.disableLoginWithPhone"
|
||||
[disabled]="
|
||||
([
|
||||
serviceType === PolicyComponentServiceType.ADMIN
|
||||
? 'iam.policy.write'
|
||||
: serviceType === PolicyComponentServiceType.MGMT
|
||||
? 'policy.write'
|
||||
: ''
|
||||
]
|
||||
| hasRole
|
||||
| async) === false
|
||||
"
|
||||
>
|
||||
{{ 'POLICY.DATA.DISABLELOGINWITHPHONE' | translate }}
|
||||
</mat-checkbox>
|
||||
</div>
|
||||
|
||||
<div class="login-policy-row">
|
||||
<cnsl-form-field class="form-field" label="Access Code" required="true">
|
||||
<cnsl-label>{{ 'POLICY.DATA.DEFAULTREDIRECTURI' | translate }}</cnsl-label>
|
||||
|
@ -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);
|
||||
|
@ -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",
|
||||
|
@ -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",
|
||||
|
@ -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",
|
||||
|
@ -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",
|
||||
|
@ -1172,6 +1172,8 @@
|
||||
"IGNOREUNKNOWNUSERNAMES_DESC": "如果选择该选项,即使未找到用户,登录过程中也会显示密码屏幕。如果用户名或密码错误,密码检查的错误不会透露。",
|
||||
"ALLOWDOMAINDISCOVERY": "允许域名发现",
|
||||
"ALLOWDOMAINDISCOVERY_DESC": "如果选择该选项,在登录屏幕上输入的未知用户名的后缀(@domain.com)将与组织的域名进行匹配,成功后将重定向到组织的注册。",
|
||||
"DISABLELOGINWITHEMAIL": "禁止用电子邮件地址登录",
|
||||
"DISABLELOGINWITHPHONE": "禁止用电话号码登录",
|
||||
"DEFAULTREDIRECTURI": "默认重定向 URI",
|
||||
"DEFAULTREDIRECTURI_DESC": "定义如果在没有应用程序上下文的情况下开始登录(例如来自邮件),用户将被重定向到哪里。",
|
||||
"ERRORMSGPOPUP": "在对话框中显示错误",
|
||||
|
@ -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 | - | |
|
||||
|
||||
|
||||
|
||||
|
@ -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 | - | |
|
||||
|
||||
|
||||
|
||||
|
@ -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 | - | |
|
||||
|
||||
|
||||
|
||||
|
@ -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()})
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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(),
|
||||
|
@ -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
|
||||
|
@ -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(),
|
||||
|
@ -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),
|
||||
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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()
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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),
|
||||
|
@ -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))
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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))
|
||||
|
@ -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()
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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 {
|
||||
|
@ -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{}) {
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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")
|
||||
|
@ -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,
|
||||
|
@ -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) {
|
||||
|
@ -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")
|
||||
|
@ -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 " +
|
||||
|
@ -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")
|
||||
|
@ -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))
|
||||
}
|
||||
|
@ -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),
|
||||
|
@ -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),
|
||||
|
@ -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",
|
||||
|
@ -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")
|
||||
|
@ -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" +
|
||||
|
@ -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) {
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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),
|
||||
|
@ -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 {
|
||||
|
@ -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 {
|
||||
|
@ -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 {
|
||||
|
Loading…
x
Reference in New Issue
Block a user