mirror of
https://github.com/zitadel/zitadel.git
synced 2025-02-28 20:37:23 +00:00
feat: add hide password reset to login policy (#1806)
* feat: add hide password reset to login policy * feat: tests * feat: hide password reset in login * feat: hide password reset to frontend * feat: hide password reset to frontend * feat: hide password reset to frontend * feat: check feature * feat: feature in frontend
This commit is contained in:
parent
3dba12c0d4
commit
8d163163f1
@ -66,6 +66,15 @@
|
||||
</mat-slide-toggle>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<span class="left-desc">{{'FEATURES.DATA.LOGINPOLICYPASSWORDRESET' | translate}}</span>
|
||||
<span class="fill-space"></span>
|
||||
<mat-slide-toggle color="primary" name="hasNumber" ngDefaultControl
|
||||
[(ngModel)]="features.loginPolicyPasswordReset"
|
||||
[disabled]="(['iam.features.write'] | hasRole | async) == false">
|
||||
</mat-slide-toggle>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<span class="left-desc">{{'FEATURES.DATA.LOGINPOLICYREGISTRATION' | translate}}</span>
|
||||
<span class="fill-space"></span>
|
||||
@ -132,4 +141,4 @@
|
||||
type="submit" mat-raised-button>{{ 'ACTIONS.SAVE' | translate
|
||||
}}</button>
|
||||
</div>
|
||||
</app-detail-layout>
|
||||
</app-detail-layout>
|
||||
|
@ -152,6 +152,7 @@ export class FeaturesComponent implements OnDestroy {
|
||||
req.setOrgId(this.org.id);
|
||||
|
||||
req.setLoginPolicyUsernameLogin(this.features.loginPolicyUsernameLogin);
|
||||
req.setLoginPolicyPasswordReset(this.features.loginPolicyPasswordReset);
|
||||
req.setLoginPolicyRegistration(this.features.loginPolicyRegistration);
|
||||
req.setLoginPolicyIdp(this.features.loginPolicyIdp);
|
||||
req.setLoginPolicyFactors(this.features.loginPolicyFactors);
|
||||
@ -170,6 +171,7 @@ export class FeaturesComponent implements OnDestroy {
|
||||
// update Default org iam policy?
|
||||
const dreq = new SetDefaultFeaturesRequest();
|
||||
dreq.setLoginPolicyUsernameLogin(this.features.loginPolicyUsernameLogin);
|
||||
dreq.setLoginPolicyPasswordReset(this.features.loginPolicyPasswordReset);
|
||||
dreq.setLoginPolicyRegistration(this.features.loginPolicyRegistration);
|
||||
dreq.setLoginPolicyIdp(this.features.loginPolicyIdp);
|
||||
dreq.setLoginPolicyFactors(this.features.loginPolicyFactors);
|
||||
|
@ -95,6 +95,26 @@
|
||||
</cnsl-info-section>
|
||||
</ng-template>
|
||||
</div>
|
||||
<div class="row">
|
||||
<mat-slide-toggle class="toggle" color="primary" [disabled]="disabled" ngDefaultControl
|
||||
[(ngModel)]="loginData.hidePasswordReset">
|
||||
{{'POLICY.DATA.HIDEPASSWORDRESET' | translate}}
|
||||
</mat-slide-toggle>
|
||||
|
||||
<ng-container
|
||||
*ngIf="serviceType == PolicyComponentServiceType.MGMT && (['login_policy.password_reset'] | hasFeature | async) == false; else passwordResetInfo">
|
||||
<cnsl-info-section type="WARN">{{'FEATURES.NOTAVAILABLE' | translate: ({value:
|
||||
'login_policy.hide_password_reset'})}}
|
||||
</cnsl-info-section>
|
||||
</ng-container>
|
||||
|
||||
<ng-template #passwordResetInfo>
|
||||
<cnsl-info-section class="info">
|
||||
{{'POLICY.DATA.HIDEPASSWORDRESET_DESC' | translate}}
|
||||
</cnsl-info-section>
|
||||
</ng-template>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
|
||||
<cnsl-form-field class="form-field" label="Access Code" required="true">
|
||||
@ -201,4 +221,4 @@
|
||||
|
||||
<cnsl-links *ngIf="nextLinks" [links]="nextLinks"></cnsl-links>
|
||||
|
||||
</app-detail-layout>
|
||||
</app-detail-layout>
|
||||
|
@ -143,6 +143,7 @@ export class LoginPolicyComponent implements OnDestroy {
|
||||
mgmtreq.setAllowUsernamePassword(this.loginData.allowUsernamePassword);
|
||||
mgmtreq.setForceMfa(this.loginData.forceMfa);
|
||||
mgmtreq.setPasswordlessType(this.loginData.passwordlessType);
|
||||
mgmtreq.setHidePasswordReset(this.loginData.hidePasswordReset);
|
||||
if ((this.loginData as LoginPolicy.AsObject).isDefault) {
|
||||
return (this.service as ManagementService).addCustomLoginPolicy(mgmtreq);
|
||||
} else {
|
||||
@ -155,6 +156,7 @@ export class LoginPolicyComponent implements OnDestroy {
|
||||
adminreq.setAllowUsernamePassword(this.loginData.allowUsernamePassword);
|
||||
adminreq.setForceMfa(this.loginData.forceMfa);
|
||||
adminreq.setPasswordlessType(this.loginData.passwordlessType);
|
||||
adminreq.setHidePasswordReset(this.loginData.hidePasswordReset);
|
||||
|
||||
return (this.service as AdminService).updateLoginPolicy(adminreq);
|
||||
}
|
||||
|
@ -607,6 +607,7 @@
|
||||
"DATA": {
|
||||
"AUDITLOGRETENTION": "Audit Log Retention",
|
||||
"LOGINPOLICYUSERNAMELOGIN": "Login Richtlinie: Login mit Username erlauben - benutzerdefiniert",
|
||||
"LOGINPOLICYPASSWORDRESET": "Login Richtlinie: Passwort vergessen Link nicht anzeigen - benutzerdefiniert",
|
||||
"LOGINPOLICYREGISTRATION": "Login Richtlinie: Registration erlauben - benutzerdefiniert",
|
||||
"LOGINPOLICYIDP": "Login Richtlinie: Identity Providers - benutzerdefiniert",
|
||||
"LOGINPOLICYFACTORS": "Login Richtlinie: Mltifaktoren - benutzerdefiniert",
|
||||
@ -683,7 +684,9 @@
|
||||
"ALLOWEXTERNALIDP_DESC": "Der Login wird für die darunter liegenden Identity Provider erlaubt.",
|
||||
"ALLOWREGISTER_DESC": "Ist die Option gewählt, erscheint im Login ein zusätzlicher Schritt zum Registrieren eines Benutzers.",
|
||||
"FORCEMFA": "Mfa erzwingen",
|
||||
"FORCEMFA_DESC": "Ist die Option gewählt, müssen Benutzer einen zweiten Faktor für den Login verwenden."
|
||||
"FORCEMFA_DESC": "Ist die Option gewählt, müssen Benutzer einen zweiten Faktor für den Login verwenden.",
|
||||
"HIDEPASSWORDRESET": "Passwort vergessen, nicht anzeigen",
|
||||
"FORCEMFA_DESC": "Ist die Option gewählt, ist es nicht möglich im Login das Passwort zurück zusetzen via Passwort vergessen Link."
|
||||
},
|
||||
"RESET": "Richtlinie zurücksetzen",
|
||||
"CREATECUSTOM": "Benutzerdefinierte Richtlinie erstellen",
|
||||
|
@ -607,6 +607,7 @@
|
||||
"DATA": {
|
||||
"AUDITLOGRETENTION": "Audit Log Retention",
|
||||
"LOGINPOLICYUSERNAMELOGIN": "Login Policy: Allow login with Username - custom",
|
||||
"LOGINPOLICYPASSWORDRESET": "Login Policy: Hide reset password link - custom",
|
||||
"LOGINPOLICYREGISTRATION": "Login Policy: Allow self registration - custom",
|
||||
"LOGINPOLICYIDP": "Login Policy: Identity Provider - custom",
|
||||
"LOGINPOLICYFACTORS": "Login Policy: Multifactors - custom",
|
||||
@ -683,7 +684,9 @@
|
||||
"ALLOWEXTERNALIDP_DESC": "The login is allowed for the underlying identity providers",
|
||||
"ALLOWREGISTER_DESC": "If the option is selected, an additional step for registering a user appears in the login.",
|
||||
"FORCEMFA": "Force MFA",
|
||||
"FORCEMFA_DESC": "If the option is selected, users have to configure a second factor for login."
|
||||
"FORCEMFA_DESC": "If the option is selected, users have to configure a second factor for login.",
|
||||
"HIDEPASSWORDRESET": "Hide Password reset",
|
||||
"FORCEMFA_DESC": "If the option is selected, the user can't reset his password in the login process."
|
||||
},
|
||||
"RESET": "Reset Policy",
|
||||
"CREATECUSTOM": "Create Custom Policy",
|
||||
|
@ -1421,6 +1421,7 @@ This is an empty response
|
||||
| password_complexity_policy | bool | - | |
|
||||
| label_policy | bool | - | |
|
||||
| custom_domain | bool | - | |
|
||||
| login_policy_password_reset | bool | - | |
|
||||
|
||||
|
||||
|
||||
@ -1456,6 +1457,7 @@ This is an empty response
|
||||
| password_complexity_policy | bool | - | |
|
||||
| label_policy | bool | - | |
|
||||
| custom_domain | bool | - | |
|
||||
| login_policy_password_reset | bool | - | |
|
||||
|
||||
|
||||
|
||||
@ -1696,6 +1698,7 @@ This is an empty response
|
||||
| allow_external_idp | bool | - | |
|
||||
| force_mfa | bool | - | |
|
||||
| passwordless_type | zitadel.policy.v1.PasswordlessType | - | enum.defined_only: true<br /> |
|
||||
| hide_password_reset | bool | - | |
|
||||
|
||||
|
||||
|
||||
|
@ -1803,6 +1803,7 @@ Change OIDC identity provider configuration of the organisation
|
||||
| allow_external_idp | bool | - | |
|
||||
| force_mfa | bool | - | |
|
||||
| passwordless_type | zitadel.policy.v1.PasswordlessType | - | enum.defined_only: true<br /> |
|
||||
| hide_password_reset | bool | - | |
|
||||
|
||||
|
||||
|
||||
@ -4988,6 +4989,7 @@ This is an empty request
|
||||
| allow_external_idp | bool | - | |
|
||||
| force_mfa | bool | - | |
|
||||
| passwordless_type | zitadel.policy.v1.PasswordlessType | - | enum.defined_only: true<br /> |
|
||||
| hide_password_reset | bool | - | |
|
||||
|
||||
|
||||
|
||||
|
@ -37,6 +37,7 @@ title: zitadel/policy.proto
|
||||
| force_mfa | bool | - | |
|
||||
| passwordless_type | PasswordlessType | - | |
|
||||
| is_default | bool | - | |
|
||||
| hide_password_reset | bool | - | |
|
||||
|
||||
|
||||
|
||||
|
@ -69,6 +69,7 @@ func setDefaultFeaturesRequestToDomain(req *admin_pb.SetDefaultFeaturesRequest)
|
||||
LoginPolicyPasswordless: req.LoginPolicyPasswordless,
|
||||
LoginPolicyRegistration: req.LoginPolicyRegistration,
|
||||
LoginPolicyUsernameLogin: req.LoginPolicyUsernameLogin,
|
||||
LoginPolicyPasswordReset: req.LoginPolicyPasswordReset,
|
||||
PasswordComplexityPolicy: req.PasswordComplexityPolicy,
|
||||
LabelPolicy: req.LabelPolicy,
|
||||
CustomDomain: req.CustomDomain,
|
||||
@ -87,6 +88,7 @@ func setOrgFeaturesRequestToDomain(req *admin_pb.SetOrgFeaturesRequest) *domain.
|
||||
LoginPolicyPasswordless: req.LoginPolicyPasswordless,
|
||||
LoginPolicyRegistration: req.LoginPolicyRegistration,
|
||||
LoginPolicyUsernameLogin: req.LoginPolicyUsernameLogin,
|
||||
LoginPolicyPasswordReset: req.LoginPolicyPasswordReset,
|
||||
PasswordComplexityPolicy: req.PasswordComplexityPolicy,
|
||||
LabelPolicy: req.LabelPolicy,
|
||||
CustomDomain: req.CustomDomain,
|
||||
|
@ -15,6 +15,7 @@ func updateLoginPolicyToDomain(p *admin_pb.UpdateLoginPolicyRequest) *domain.Log
|
||||
AllowExternalIDP: p.AllowExternalIdp,
|
||||
ForceMFA: p.ForceMfa,
|
||||
PasswordlessType: policy_grpc.PasswordlessTypeToDomain(p.PasswordlessType),
|
||||
HidePasswordReset: p.HidePasswordReset,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -21,6 +21,7 @@ func FeaturesFromModel(features *features_model.FeaturesView) *features_pb.Featu
|
||||
LoginPolicyPasswordless: features.LoginPolicyPasswordless,
|
||||
LoginPolicyRegistration: features.LoginPolicyRegistration,
|
||||
LoginPolicyUsernameLogin: features.LoginPolicyUsernameLogin,
|
||||
LoginPolicyPasswordReset: features.LoginPolicyPasswordReset,
|
||||
PasswordComplexityPolicy: features.PasswordComplexityPolicy,
|
||||
LabelPolicy: features.LabelPolicy,
|
||||
CustomDomain: features.CustomDomain,
|
||||
|
@ -15,6 +15,7 @@ func addLoginPolicyToDomain(p *mgmt_pb.AddCustomLoginPolicyRequest) *domain.Logi
|
||||
AllowExternalIDP: p.AllowExternalIdp,
|
||||
ForceMFA: p.ForceMfa,
|
||||
PasswordlessType: policy_grpc.PasswordlessTypeToDomain(p.PasswordlessType),
|
||||
HidePasswordReset: p.HidePasswordReset,
|
||||
}
|
||||
}
|
||||
|
||||
@ -25,6 +26,7 @@ func updateLoginPolicyToDomain(p *mgmt_pb.UpdateCustomLoginPolicyRequest) *domai
|
||||
AllowExternalIDP: p.AllowExternalIdp,
|
||||
ForceMFA: p.ForceMfa,
|
||||
PasswordlessType: policy_grpc.PasswordlessTypeToDomain(p.PasswordlessType),
|
||||
HidePasswordReset: p.HidePasswordReset,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -14,6 +14,7 @@ func ModelLoginPolicyToPb(policy *model.LoginPolicyView) *policy_pb.LoginPolicy
|
||||
AllowExternalIdp: policy.AllowExternalIDP,
|
||||
ForceMfa: policy.ForceMFA,
|
||||
PasswordlessType: ModelPasswordlessTypeToPb(policy.PasswordlessType),
|
||||
HidePasswordReset: policy.HidePasswordReset,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -163,6 +163,10 @@ func checkLoginPolicyFeatures(features *features_view_model.FeaturesView, requir
|
||||
if !features.LoginPolicyUsernameLogin {
|
||||
return MissingFeatureErr(requiredFeature)
|
||||
}
|
||||
case domain.FeatureLoginPolicyPasswordReset:
|
||||
if !features.LoginPolicyPasswordReset {
|
||||
return MissingFeatureErr(requiredFeature)
|
||||
}
|
||||
default:
|
||||
if !features.LoginPolicyFactors && !features.LoginPolicyIDP && !features.LoginPolicyPasswordless && !features.LoginPolicyRegistration && !features.LoginPolicyUsernameLogin {
|
||||
return MissingFeatureErr(requiredFeature)
|
||||
|
@ -21,6 +21,7 @@ type FeaturesWriteModel struct {
|
||||
LoginPolicyPasswordless bool
|
||||
LoginPolicyRegistration bool
|
||||
LoginPolicyUsernameLogin bool
|
||||
LoginPolicyPasswordReset bool
|
||||
PasswordComplexityPolicy bool
|
||||
LabelPolicy bool
|
||||
CustomDomain bool
|
||||
@ -61,6 +62,9 @@ func (wm *FeaturesWriteModel) Reduce() error {
|
||||
if e.LoginPolicyUsernameLogin != nil {
|
||||
wm.LoginPolicyUsernameLogin = *e.LoginPolicyUsernameLogin
|
||||
}
|
||||
if e.LoginPolicyPasswordReset != nil {
|
||||
wm.LoginPolicyPasswordReset = *e.LoginPolicyPasswordReset
|
||||
}
|
||||
if e.PasswordComplexityPolicy != nil {
|
||||
wm.PasswordComplexityPolicy = *e.PasswordComplexityPolicy
|
||||
}
|
||||
|
@ -39,6 +39,7 @@ func writeModelToLoginPolicy(wm *LoginPolicyWriteModel) *domain.LoginPolicy {
|
||||
AllowUsernamePassword: wm.AllowUserNamePassword,
|
||||
AllowRegister: wm.AllowRegister,
|
||||
AllowExternalIDP: wm.AllowExternalIDP,
|
||||
HidePasswordReset: wm.HidePasswordReset,
|
||||
ForceMFA: wm.ForceMFA,
|
||||
PasswordlessType: wm.PasswordlessType,
|
||||
}
|
||||
|
@ -48,7 +48,7 @@ func (c *Commands) addDefaultLoginPolicy(ctx context.Context, iamAgg *eventstore
|
||||
return nil, caos_errs.ThrowAlreadyExists(nil, "IAM-2B0ps", "Errors.IAM.LoginPolicy.AlreadyExists")
|
||||
}
|
||||
|
||||
return iam_repo.NewLoginPolicyAddedEvent(ctx, iamAgg, policy.AllowUsernamePassword, policy.AllowRegister, policy.AllowExternalIDP, policy.ForceMFA, policy.PasswordlessType), nil
|
||||
return iam_repo.NewLoginPolicyAddedEvent(ctx, iamAgg, policy.AllowUsernamePassword, policy.AllowRegister, policy.AllowExternalIDP, policy.ForceMFA, policy.HidePasswordReset, policy.PasswordlessType), nil
|
||||
}
|
||||
|
||||
func (c *Commands) ChangeDefaultLoginPolicy(ctx context.Context, policy *domain.LoginPolicy) (*domain.LoginPolicy, error) {
|
||||
@ -77,7 +77,7 @@ func (c *Commands) changeDefaultLoginPolicy(ctx context.Context, iamAgg *eventst
|
||||
if existingPolicy.State == domain.PolicyStateUnspecified || existingPolicy.State == domain.PolicyStateRemoved {
|
||||
return nil, caos_errs.ThrowNotFound(nil, "IAM-M0sif", "Errors.IAM.LoginPolicy.NotFound")
|
||||
}
|
||||
changedEvent, hasChanged := existingPolicy.NewChangedEvent(ctx, iamAgg, policy.AllowUsernamePassword, policy.AllowRegister, policy.AllowExternalIDP, policy.ForceMFA, policy.PasswordlessType)
|
||||
changedEvent, hasChanged := existingPolicy.NewChangedEvent(ctx, iamAgg, policy.AllowUsernamePassword, policy.AllowRegister, policy.AllowExternalIDP, policy.ForceMFA, policy.HidePasswordReset, policy.PasswordlessType)
|
||||
if !hasChanged {
|
||||
return nil, caos_errs.ThrowPreconditionFailed(nil, "IAM-5M9vdd", "Errors.IAM.LoginPolicy.NotChanged")
|
||||
}
|
||||
|
@ -58,7 +58,8 @@ func (wm *IAMLoginPolicyWriteModel) NewChangedEvent(
|
||||
allowUsernamePassword,
|
||||
allowRegister,
|
||||
allowExternalIDP,
|
||||
forceMFA bool,
|
||||
forceMFA,
|
||||
hidePasswordReset bool,
|
||||
passwordlessType domain.PasswordlessType,
|
||||
) (*iam.LoginPolicyChangedEvent, bool) {
|
||||
|
||||
@ -78,6 +79,9 @@ func (wm *IAMLoginPolicyWriteModel) NewChangedEvent(
|
||||
if passwordlessType.Valid() && wm.PasswordlessType != passwordlessType {
|
||||
changes = append(changes, policy.ChangePasswordlessType(passwordlessType))
|
||||
}
|
||||
if wm.HidePasswordReset != hidePasswordReset {
|
||||
changes = append(changes, policy.ChangeHidePasswordReset(hidePasswordReset))
|
||||
}
|
||||
if len(changes) == 0 {
|
||||
return nil, false
|
||||
}
|
||||
|
@ -2,6 +2,8 @@ package command
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/caos/zitadel/internal/domain"
|
||||
caos_errs "github.com/caos/zitadel/internal/errors"
|
||||
"github.com/caos/zitadel/internal/eventstore"
|
||||
@ -12,7 +14,6 @@ import (
|
||||
"github.com/caos/zitadel/internal/repository/user"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestCommandSide_AddDefaultLoginPolicy(t *testing.T) {
|
||||
@ -46,6 +47,7 @@ func TestCommandSide_AddDefaultLoginPolicy(t *testing.T) {
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
domain.PasswordlessTypeAllowed,
|
||||
),
|
||||
),
|
||||
@ -79,6 +81,7 @@ func TestCommandSide_AddDefaultLoginPolicy(t *testing.T) {
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
domain.PasswordlessTypeAllowed,
|
||||
),
|
||||
),
|
||||
@ -93,6 +96,7 @@ func TestCommandSide_AddDefaultLoginPolicy(t *testing.T) {
|
||||
AllowUsernamePassword: true,
|
||||
AllowExternalIDP: true,
|
||||
ForceMFA: true,
|
||||
HidePasswordReset: true,
|
||||
PasswordlessType: domain.PasswordlessTypeAllowed,
|
||||
},
|
||||
},
|
||||
@ -106,6 +110,7 @@ func TestCommandSide_AddDefaultLoginPolicy(t *testing.T) {
|
||||
AllowUsernamePassword: true,
|
||||
AllowExternalIDP: true,
|
||||
ForceMFA: true,
|
||||
HidePasswordReset: true,
|
||||
PasswordlessType: domain.PasswordlessTypeAllowed,
|
||||
},
|
||||
},
|
||||
@ -180,6 +185,7 @@ func TestCommandSide_ChangeDefaultLoginPolicy(t *testing.T) {
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
domain.PasswordlessTypeAllowed,
|
||||
),
|
||||
),
|
||||
@ -193,6 +199,7 @@ func TestCommandSide_ChangeDefaultLoginPolicy(t *testing.T) {
|
||||
AllowUsernamePassword: true,
|
||||
AllowExternalIDP: true,
|
||||
ForceMFA: true,
|
||||
HidePasswordReset: true,
|
||||
PasswordlessType: domain.PasswordlessTypeAllowed,
|
||||
},
|
||||
},
|
||||
@ -213,6 +220,7 @@ func TestCommandSide_ChangeDefaultLoginPolicy(t *testing.T) {
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
domain.PasswordlessTypeAllowed,
|
||||
),
|
||||
),
|
||||
@ -220,7 +228,7 @@ func TestCommandSide_ChangeDefaultLoginPolicy(t *testing.T) {
|
||||
expectPush(
|
||||
[]*repository.Event{
|
||||
eventFromEventPusher(
|
||||
newDefaultLoginPolicyChangedEvent(context.Background(), false, false, false, false, domain.PasswordlessTypeNotAllowed),
|
||||
newDefaultLoginPolicyChangedEvent(context.Background(), false, false, false, false, false, domain.PasswordlessTypeNotAllowed),
|
||||
),
|
||||
},
|
||||
),
|
||||
@ -233,6 +241,7 @@ func TestCommandSide_ChangeDefaultLoginPolicy(t *testing.T) {
|
||||
AllowUsernamePassword: false,
|
||||
AllowExternalIDP: false,
|
||||
ForceMFA: false,
|
||||
HidePasswordReset: false,
|
||||
PasswordlessType: domain.PasswordlessTypeNotAllowed,
|
||||
},
|
||||
},
|
||||
@ -246,6 +255,7 @@ func TestCommandSide_ChangeDefaultLoginPolicy(t *testing.T) {
|
||||
AllowUsernamePassword: false,
|
||||
AllowExternalIDP: false,
|
||||
ForceMFA: false,
|
||||
HidePasswordReset: false,
|
||||
PasswordlessType: domain.PasswordlessTypeNotAllowed,
|
||||
},
|
||||
},
|
||||
@ -345,6 +355,7 @@ func TestCommandSide_AddIDPProviderDefaultLoginPolicy(t *testing.T) {
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
domain.PasswordlessTypeAllowed,
|
||||
),
|
||||
),
|
||||
@ -496,6 +507,7 @@ func TestCommandSide_RemoveIDPProviderDefaultLoginPolicy(t *testing.T) {
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
domain.PasswordlessTypeAllowed,
|
||||
),
|
||||
),
|
||||
@ -537,6 +549,7 @@ func TestCommandSide_RemoveIDPProviderDefaultLoginPolicy(t *testing.T) {
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
domain.PasswordlessTypeAllowed,
|
||||
),
|
||||
),
|
||||
@ -583,6 +596,7 @@ func TestCommandSide_RemoveIDPProviderDefaultLoginPolicy(t *testing.T) {
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
domain.PasswordlessTypeAllowed,
|
||||
),
|
||||
),
|
||||
@ -637,6 +651,7 @@ func TestCommandSide_RemoveIDPProviderDefaultLoginPolicy(t *testing.T) {
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
domain.PasswordlessTypeAllowed,
|
||||
),
|
||||
),
|
||||
@ -1181,7 +1196,7 @@ func TestCommandSide_RemoveMultiFactorDefaultLoginPolicy(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func newDefaultLoginPolicyChangedEvent(ctx context.Context, allowRegister, allowUsernamePassword, allowExternalIDP, forceMFA bool, passwordlessType domain.PasswordlessType) *iam.LoginPolicyChangedEvent {
|
||||
func newDefaultLoginPolicyChangedEvent(ctx context.Context, allowRegister, allowUsernamePassword, allowExternalIDP, forceMFA, hidePasswordReset bool, passwordlessType domain.PasswordlessType) *iam.LoginPolicyChangedEvent {
|
||||
event, _ := iam.NewLoginPolicyChangedEvent(ctx,
|
||||
&iam.NewAggregate().Aggregate,
|
||||
[]policy.LoginPolicyChanges{
|
||||
@ -1189,6 +1204,7 @@ func newDefaultLoginPolicyChangedEvent(ctx context.Context, allowRegister, allow
|
||||
policy.ChangeAllowExternalIDP(allowExternalIDP),
|
||||
policy.ChangeForceMFA(forceMFA),
|
||||
policy.ChangeAllowUserNamePassword(allowUsernamePassword),
|
||||
policy.ChangeHidePasswordReset(hidePasswordReset),
|
||||
policy.ChangePasswordlessType(passwordlessType),
|
||||
},
|
||||
)
|
||||
|
@ -31,6 +31,7 @@ func (c *Commands) SetOrgFeatures(ctx context.Context, resourceOwner string, fea
|
||||
features.LoginPolicyPasswordless,
|
||||
features.LoginPolicyRegistration,
|
||||
features.LoginPolicyUsernameLogin,
|
||||
features.LoginPolicyPasswordReset,
|
||||
features.PasswordComplexityPolicy,
|
||||
features.LabelPolicy,
|
||||
features.CustomDomain,
|
||||
@ -165,7 +166,10 @@ func (c *Commands) setAllowedLoginPolicy(ctx context.Context, orgID string, feat
|
||||
if !features.LoginPolicyUsernameLogin && defaultPolicy.AllowUsernamePassword != existingPolicy.AllowUserNamePassword {
|
||||
policy.AllowUserNamePassword = defaultPolicy.AllowUsernamePassword
|
||||
}
|
||||
changedEvent, hasChanged := existingPolicy.NewChangedEvent(ctx, OrgAggregateFromWriteModel(&existingPolicy.WriteModel), policy.AllowUserNamePassword, policy.AllowRegister, policy.AllowExternalIDP, policy.ForceMFA, policy.PasswordlessType)
|
||||
if !features.LoginPolicyPasswordReset && defaultPolicy.HidePasswordReset != existingPolicy.HidePasswordReset {
|
||||
policy.HidePasswordReset = defaultPolicy.HidePasswordReset
|
||||
}
|
||||
changedEvent, hasChanged := existingPolicy.NewChangedEvent(ctx, OrgAggregateFromWriteModel(&existingPolicy.WriteModel), policy.AllowUserNamePassword, policy.AllowRegister, policy.AllowExternalIDP, policy.ForceMFA, policy.HidePasswordReset, policy.PasswordlessType)
|
||||
if hasChanged {
|
||||
events = append(events, changedEvent)
|
||||
}
|
||||
|
@ -67,6 +67,7 @@ func (wm *OrgFeaturesWriteModel) NewSetEvent(
|
||||
loginPolicyPasswordless,
|
||||
loginPolicyRegistration,
|
||||
loginPolicyUsernameLogin,
|
||||
loginPolicyPasswordReset,
|
||||
passwordComplexityPolicy,
|
||||
labelPolicy,
|
||||
customDomain bool,
|
||||
@ -104,6 +105,9 @@ func (wm *OrgFeaturesWriteModel) NewSetEvent(
|
||||
if wm.LoginPolicyUsernameLogin != loginPolicyUsernameLogin {
|
||||
changes = append(changes, features.ChangeLoginPolicyUsernameLogin(loginPolicyUsernameLogin))
|
||||
}
|
||||
if wm.LoginPolicyPasswordReset != loginPolicyPasswordReset {
|
||||
changes = append(changes, features.ChangeLoginPolicyPasswordReset(loginPolicyPasswordReset))
|
||||
}
|
||||
if wm.PasswordComplexityPolicy != passwordComplexityPolicy {
|
||||
changes = append(changes, features.ChangePasswordComplexityPolicy(passwordComplexityPolicy))
|
||||
}
|
||||
|
@ -54,6 +54,7 @@ func TestCommandSide_SetOrgFeatures(t *testing.T) {
|
||||
LoginPolicyPasswordless: false,
|
||||
LoginPolicyRegistration: false,
|
||||
LoginPolicyUsernameLogin: false,
|
||||
LoginPolicyPasswordReset: false,
|
||||
PasswordComplexityPolicy: false,
|
||||
LabelPolicy: false,
|
||||
CustomDomain: false,
|
||||
@ -87,6 +88,7 @@ func TestCommandSide_SetOrgFeatures(t *testing.T) {
|
||||
LoginPolicyPasswordless: false,
|
||||
LoginPolicyRegistration: false,
|
||||
LoginPolicyUsernameLogin: false,
|
||||
LoginPolicyPasswordReset: false,
|
||||
PasswordComplexityPolicy: false,
|
||||
LabelPolicy: false,
|
||||
CustomDomain: false,
|
||||
@ -111,6 +113,7 @@ func TestCommandSide_SetOrgFeatures(t *testing.T) {
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
domain.PasswordlessTypeAllowed,
|
||||
),
|
||||
),
|
||||
@ -191,6 +194,7 @@ func TestCommandSide_SetOrgFeatures(t *testing.T) {
|
||||
LoginPolicyPasswordless: false,
|
||||
LoginPolicyRegistration: false,
|
||||
LoginPolicyUsernameLogin: false,
|
||||
LoginPolicyPasswordReset: false,
|
||||
PasswordComplexityPolicy: false,
|
||||
LabelPolicy: false,
|
||||
CustomDomain: false,
|
||||
@ -217,6 +221,7 @@ func TestCommandSide_SetOrgFeatures(t *testing.T) {
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
domain.PasswordlessTypeAllowed,
|
||||
),
|
||||
),
|
||||
@ -325,6 +330,7 @@ func TestCommandSide_SetOrgFeatures(t *testing.T) {
|
||||
LoginPolicyPasswordless: false,
|
||||
LoginPolicyRegistration: false,
|
||||
LoginPolicyUsernameLogin: false,
|
||||
LoginPolicyPasswordReset: false,
|
||||
PasswordComplexityPolicy: false,
|
||||
LabelPolicy: false,
|
||||
CustomDomain: false,
|
||||
@ -351,6 +357,7 @@ func TestCommandSide_SetOrgFeatures(t *testing.T) {
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
domain.PasswordlessTypeAllowed,
|
||||
),
|
||||
),
|
||||
@ -469,6 +476,7 @@ func TestCommandSide_SetOrgFeatures(t *testing.T) {
|
||||
LoginPolicyPasswordless: false,
|
||||
LoginPolicyRegistration: false,
|
||||
LoginPolicyUsernameLogin: false,
|
||||
LoginPolicyPasswordReset: false,
|
||||
PasswordComplexityPolicy: false,
|
||||
LabelPolicy: false,
|
||||
CustomDomain: false,
|
||||
@ -495,6 +503,7 @@ func TestCommandSide_SetOrgFeatures(t *testing.T) {
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
domain.PasswordlessTypeAllowed,
|
||||
),
|
||||
),
|
||||
@ -623,6 +632,7 @@ func TestCommandSide_SetOrgFeatures(t *testing.T) {
|
||||
LoginPolicyPasswordless: false,
|
||||
LoginPolicyRegistration: false,
|
||||
LoginPolicyUsernameLogin: false,
|
||||
LoginPolicyPasswordReset: false,
|
||||
PasswordComplexityPolicy: false,
|
||||
LabelPolicy: false,
|
||||
CustomDomain: false,
|
||||
@ -653,6 +663,7 @@ func TestCommandSide_SetOrgFeatures(t *testing.T) {
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
domain.PasswordlessTypeAllowed,
|
||||
),
|
||||
),
|
||||
@ -664,6 +675,7 @@ func TestCommandSide_SetOrgFeatures(t *testing.T) {
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
domain.PasswordlessTypeNotAllowed,
|
||||
),
|
||||
),
|
||||
@ -678,6 +690,7 @@ func TestCommandSide_SetOrgFeatures(t *testing.T) {
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
domain.PasswordlessTypeAllowed,
|
||||
),
|
||||
),
|
||||
@ -790,7 +803,7 @@ func TestCommandSide_SetOrgFeatures(t *testing.T) {
|
||||
org.NewLoginPolicyMultiFactorAddedEvent(context.Background(), &org.NewAggregate("org1", "org1").Aggregate, domain.MultiFactorTypeU2FWithPIN),
|
||||
),
|
||||
eventFromEventPusher(
|
||||
newLoginPolicyChangedEvent(context.Background(), "org1", true, true, true, true, domain.PasswordlessTypeAllowed),
|
||||
newLoginPolicyChangedEvent(context.Background(), "org1", true, true, true, true, true, domain.PasswordlessTypeAllowed),
|
||||
),
|
||||
eventFromEventPusher(
|
||||
org.NewPasswordComplexityPolicyRemovedEvent(context.Background(), &org.NewAggregate("org1", "org1").Aggregate),
|
||||
@ -920,6 +933,7 @@ func TestCommandSide_RemoveOrgFeatures(t *testing.T) {
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
domain.PasswordlessTypeAllowed,
|
||||
),
|
||||
),
|
||||
|
@ -42,6 +42,7 @@ func (c *Commands) AddLoginPolicy(ctx context.Context, resourceOwner string, pol
|
||||
policy.AllowRegister,
|
||||
policy.AllowExternalIDP,
|
||||
policy.ForceMFA,
|
||||
policy.HidePasswordReset,
|
||||
policy.PasswordlessType))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -81,7 +82,16 @@ func (c *Commands) ChangeLoginPolicy(ctx context.Context, resourceOwner string,
|
||||
}
|
||||
|
||||
orgAgg := OrgAggregateFromWriteModel(&existingPolicy.LoginPolicyWriteModel.WriteModel)
|
||||
changedEvent, hasChanged := existingPolicy.NewChangedEvent(ctx, orgAgg, policy.AllowUsernamePassword, policy.AllowRegister, policy.AllowExternalIDP, policy.ForceMFA, policy.PasswordlessType)
|
||||
changedEvent, hasChanged := existingPolicy.NewChangedEvent(
|
||||
ctx,
|
||||
orgAgg,
|
||||
policy.AllowUsernamePassword,
|
||||
policy.AllowRegister,
|
||||
policy.AllowExternalIDP,
|
||||
policy.ForceMFA,
|
||||
policy.HidePasswordReset,
|
||||
policy.PasswordlessType)
|
||||
|
||||
if !hasChanged {
|
||||
return nil, caos_errs.ThrowPreconditionFailed(nil, "Org-5M9vdd", "Errors.Org.LoginPolicy.NotChanged")
|
||||
}
|
||||
@ -118,6 +128,9 @@ func (c *Commands) checkLoginPolicyAllowed(ctx context.Context, resourceOwner st
|
||||
if defaultPolicy.AllowUsernamePassword != policy.AllowUsernamePassword {
|
||||
requiredFeatures = append(requiredFeatures, domain.FeatureLoginPolicyUsernameLogin)
|
||||
}
|
||||
if defaultPolicy.HidePasswordReset != policy.HidePasswordReset {
|
||||
requiredFeatures = append(requiredFeatures, domain.FeatureLoginPolicyPasswordReset)
|
||||
}
|
||||
return authz.CheckOrgFeatures(ctx, c.tokenVerifier, resourceOwner, requiredFeatures...)
|
||||
}
|
||||
|
||||
|
@ -61,7 +61,8 @@ func (wm *OrgLoginPolicyWriteModel) NewChangedEvent(
|
||||
allowUsernamePassword,
|
||||
allowRegister,
|
||||
allowExternalIDP,
|
||||
forceMFA bool,
|
||||
forceMFA,
|
||||
hidePasswordReset bool,
|
||||
passwordlessType domain.PasswordlessType,
|
||||
) (*org.LoginPolicyChangedEvent, bool) {
|
||||
|
||||
@ -78,6 +79,9 @@ func (wm *OrgLoginPolicyWriteModel) NewChangedEvent(
|
||||
if wm.ForceMFA != forceMFA {
|
||||
changes = append(changes, policy.ChangeForceMFA(forceMFA))
|
||||
}
|
||||
if wm.HidePasswordReset != hidePasswordReset {
|
||||
changes = append(changes, policy.ChangeHidePasswordReset(hidePasswordReset))
|
||||
}
|
||||
if passwordlessType.Valid() && wm.PasswordlessType != passwordlessType {
|
||||
changes = append(changes, policy.ChangePasswordlessType(passwordlessType))
|
||||
}
|
||||
|
@ -70,6 +70,7 @@ func TestCommandSide_AddLoginPolicy(t *testing.T) {
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
domain.PasswordlessTypeAllowed,
|
||||
),
|
||||
),
|
||||
@ -105,6 +106,7 @@ func TestCommandSide_AddLoginPolicy(t *testing.T) {
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
domain.PasswordlessTypeAllowed,
|
||||
),
|
||||
),
|
||||
@ -141,6 +143,7 @@ func TestCommandSide_AddLoginPolicy(t *testing.T) {
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
domain.PasswordlessTypeAllowed,
|
||||
),
|
||||
),
|
||||
@ -154,6 +157,7 @@ func TestCommandSide_AddLoginPolicy(t *testing.T) {
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
domain.PasswordlessTypeAllowed,
|
||||
),
|
||||
),
|
||||
@ -170,6 +174,7 @@ func TestCommandSide_AddLoginPolicy(t *testing.T) {
|
||||
AllowUsernamePassword: true,
|
||||
AllowExternalIDP: true,
|
||||
ForceMFA: true,
|
||||
HidePasswordReset: true,
|
||||
PasswordlessType: domain.PasswordlessTypeAllowed,
|
||||
},
|
||||
},
|
||||
@ -183,6 +188,7 @@ func TestCommandSide_AddLoginPolicy(t *testing.T) {
|
||||
AllowUsernamePassword: true,
|
||||
AllowExternalIDP: true,
|
||||
ForceMFA: true,
|
||||
HidePasswordReset: true,
|
||||
PasswordlessType: domain.PasswordlessTypeAllowed,
|
||||
},
|
||||
},
|
||||
@ -285,6 +291,7 @@ func TestCommandSide_ChangeLoginPolicy(t *testing.T) {
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
domain.PasswordlessTypeAllowed,
|
||||
),
|
||||
),
|
||||
@ -297,6 +304,7 @@ func TestCommandSide_ChangeLoginPolicy(t *testing.T) {
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
domain.PasswordlessTypeAllowed,
|
||||
),
|
||||
),
|
||||
@ -332,6 +340,7 @@ func TestCommandSide_ChangeLoginPolicy(t *testing.T) {
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
domain.PasswordlessTypeAllowed,
|
||||
),
|
||||
),
|
||||
@ -344,6 +353,7 @@ func TestCommandSide_ChangeLoginPolicy(t *testing.T) {
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
domain.PasswordlessTypeAllowed,
|
||||
),
|
||||
),
|
||||
@ -359,6 +369,7 @@ func TestCommandSide_ChangeLoginPolicy(t *testing.T) {
|
||||
AllowUsernamePassword: true,
|
||||
AllowExternalIDP: true,
|
||||
ForceMFA: true,
|
||||
HidePasswordReset: true,
|
||||
PasswordlessType: domain.PasswordlessTypeAllowed,
|
||||
},
|
||||
},
|
||||
@ -379,6 +390,7 @@ func TestCommandSide_ChangeLoginPolicy(t *testing.T) {
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
domain.PasswordlessTypeAllowed,
|
||||
),
|
||||
),
|
||||
@ -391,6 +403,7 @@ func TestCommandSide_ChangeLoginPolicy(t *testing.T) {
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
domain.PasswordlessTypeNotAllowed,
|
||||
),
|
||||
),
|
||||
@ -398,7 +411,7 @@ func TestCommandSide_ChangeLoginPolicy(t *testing.T) {
|
||||
expectPush(
|
||||
[]*repository.Event{
|
||||
eventFromEventPusher(
|
||||
newLoginPolicyChangedEvent(context.Background(), "org1", false, false, false, false, domain.PasswordlessTypeNotAllowed),
|
||||
newLoginPolicyChangedEvent(context.Background(), "org1", false, false, false, false, false, domain.PasswordlessTypeNotAllowed),
|
||||
),
|
||||
},
|
||||
),
|
||||
@ -426,6 +439,7 @@ func TestCommandSide_ChangeLoginPolicy(t *testing.T) {
|
||||
AllowUsernamePassword: false,
|
||||
AllowExternalIDP: false,
|
||||
ForceMFA: false,
|
||||
HidePasswordReset: false,
|
||||
PasswordlessType: domain.PasswordlessTypeNotAllowed,
|
||||
},
|
||||
},
|
||||
@ -512,6 +526,7 @@ func TestCommandSide_RemoveLoginPolicy(t *testing.T) {
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
domain.PasswordlessTypeAllowed,
|
||||
),
|
||||
),
|
||||
@ -655,6 +670,7 @@ func TestCommandSide_AddIDPProviderLoginPolicy(t *testing.T) {
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
domain.PasswordlessTypeAllowed,
|
||||
),
|
||||
),
|
||||
@ -839,6 +855,7 @@ func TestCommandSide_RemoveIDPProviderLoginPolicy(t *testing.T) {
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
domain.PasswordlessTypeAllowed,
|
||||
),
|
||||
),
|
||||
@ -882,6 +899,7 @@ func TestCommandSide_RemoveIDPProviderLoginPolicy(t *testing.T) {
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
domain.PasswordlessTypeAllowed,
|
||||
),
|
||||
),
|
||||
@ -932,6 +950,7 @@ func TestCommandSide_RemoveIDPProviderLoginPolicy(t *testing.T) {
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
domain.PasswordlessTypeAllowed,
|
||||
),
|
||||
),
|
||||
@ -990,6 +1009,7 @@ func TestCommandSide_RemoveIDPProviderLoginPolicy(t *testing.T) {
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
domain.PasswordlessTypeAllowed,
|
||||
),
|
||||
),
|
||||
@ -1600,7 +1620,7 @@ func TestCommandSide_RemoveMultiFactorLoginPolicy(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func newLoginPolicyChangedEvent(ctx context.Context, orgID string, usernamePassword, register, externalIDP, mfa bool, passwordlessType domain.PasswordlessType) *org.LoginPolicyChangedEvent {
|
||||
func newLoginPolicyChangedEvent(ctx context.Context, orgID string, usernamePassword, register, externalIDP, mfa, passwordReset bool, passwordlessType domain.PasswordlessType) *org.LoginPolicyChangedEvent {
|
||||
event, _ := org.NewLoginPolicyChangedEvent(ctx,
|
||||
&org.NewAggregate(orgID, orgID).Aggregate,
|
||||
[]policy.LoginPolicyChanges{
|
||||
@ -1608,6 +1628,7 @@ func newLoginPolicyChangedEvent(ctx context.Context, orgID string, usernamePassw
|
||||
policy.ChangeAllowRegister(register),
|
||||
policy.ChangeAllowExternalIDP(externalIDP),
|
||||
policy.ChangeForceMFA(mfa),
|
||||
policy.ChangeHidePasswordReset(passwordReset),
|
||||
policy.ChangePasswordlessType(passwordlessType),
|
||||
},
|
||||
)
|
||||
|
@ -13,6 +13,7 @@ type LoginPolicyWriteModel struct {
|
||||
AllowRegister bool
|
||||
AllowExternalIDP bool
|
||||
ForceMFA bool
|
||||
HidePasswordReset bool
|
||||
PasswordlessType domain.PasswordlessType
|
||||
State domain.PolicyState
|
||||
}
|
||||
@ -26,6 +27,7 @@ func (wm *LoginPolicyWriteModel) Reduce() error {
|
||||
wm.AllowExternalIDP = e.AllowExternalIDP
|
||||
wm.ForceMFA = e.ForceMFA
|
||||
wm.PasswordlessType = e.PasswordlessType
|
||||
wm.HidePasswordReset = e.HidePasswordReset
|
||||
wm.State = domain.PolicyStateActive
|
||||
case *policy.LoginPolicyChangedEvent:
|
||||
if e.AllowRegister != nil {
|
||||
@ -40,6 +42,9 @@ func (wm *LoginPolicyWriteModel) Reduce() error {
|
||||
if e.ForceMFA != nil {
|
||||
wm.ForceMFA = *e.ForceMFA
|
||||
}
|
||||
if e.HidePasswordReset != nil {
|
||||
wm.HidePasswordReset = *e.HidePasswordReset
|
||||
}
|
||||
if e.PasswordlessType != nil {
|
||||
wm.PasswordlessType = *e.PasswordlessType
|
||||
}
|
||||
|
@ -13,6 +13,7 @@ const (
|
||||
FeatureLoginPolicyPasswordless = FeatureLoginPolicy + ".passwordless"
|
||||
FeatureLoginPolicyRegistration = FeatureLoginPolicy + ".registration"
|
||||
FeatureLoginPolicyUsernameLogin = FeatureLoginPolicy + ".username_login"
|
||||
FeatureLoginPolicyPasswordReset = FeatureLoginPolicy + ".password_reset"
|
||||
FeaturePasswordComplexityPolicy = "password_complexity_policy"
|
||||
FeatureLabelPolicy = "label_policy"
|
||||
FeatureCustomDomain = "custom_domain"
|
||||
@ -33,6 +34,7 @@ type Features struct {
|
||||
LoginPolicyPasswordless bool
|
||||
LoginPolicyRegistration bool
|
||||
LoginPolicyUsernameLogin bool
|
||||
LoginPolicyPasswordReset bool
|
||||
PasswordComplexityPolicy bool
|
||||
LabelPolicy bool
|
||||
CustomDomain bool
|
||||
|
@ -14,6 +14,7 @@ type LoginPolicy struct {
|
||||
SecondFactors []SecondFactorType
|
||||
MultiFactors []MultiFactorType
|
||||
PasswordlessType PasswordlessType
|
||||
HidePasswordReset bool
|
||||
}
|
||||
|
||||
type IDPProvider struct {
|
||||
|
@ -23,6 +23,7 @@ type FeaturesView struct {
|
||||
LoginPolicyPasswordless bool
|
||||
LoginPolicyRegistration bool
|
||||
LoginPolicyUsernameLogin bool
|
||||
LoginPolicyPasswordReset bool
|
||||
PasswordComplexityPolicy bool
|
||||
LabelPolicy bool
|
||||
CustomDomain bool
|
||||
@ -45,6 +46,9 @@ func (f *FeaturesView) FeatureList() []string {
|
||||
if f.LoginPolicyUsernameLogin {
|
||||
list = append(list, domain.FeatureLoginPolicyUsernameLogin)
|
||||
}
|
||||
if f.LoginPolicyPasswordReset {
|
||||
list = append(list, domain.FeatureLoginPolicyPasswordReset)
|
||||
}
|
||||
if f.PasswordComplexityPolicy {
|
||||
list = append(list, domain.FeaturePasswordComplexityPolicy)
|
||||
}
|
||||
|
@ -36,6 +36,7 @@ type FeaturesView struct {
|
||||
LoginPolicyPasswordless bool `json:"loginPolicyPasswordless" gorm:"column:login_policy_passwordless"`
|
||||
LoginPolicyRegistration bool `json:"loginPolicyRegistration" gorm:"column:login_policy_registration"`
|
||||
LoginPolicyUsernameLogin bool `json:"loginPolicyUsernameLogin" gorm:"column:login_policy_username_login"`
|
||||
LoginPolicyPasswordReset bool `json:"loginPolicyPasswordReset" gorm:"column:login_policy_password_reset"`
|
||||
PasswordComplexityPolicy bool `json:"passwordComplexityPolicy" gorm:"column:password_complexity_policy"`
|
||||
LabelPolicy bool `json:"labelPolicy" gorm:"column:label_policy"`
|
||||
CustomDomain bool `json:"customDomain" gorm:"column:custom_domain"`
|
||||
@ -58,6 +59,7 @@ func FeaturesToModel(features *FeaturesView) *features_model.FeaturesView {
|
||||
LoginPolicyPasswordless: features.LoginPolicyPasswordless,
|
||||
LoginPolicyRegistration: features.LoginPolicyRegistration,
|
||||
LoginPolicyUsernameLogin: features.LoginPolicyUsernameLogin,
|
||||
LoginPolicyPasswordReset: features.LoginPolicyPasswordReset,
|
||||
PasswordComplexityPolicy: features.PasswordComplexityPolicy,
|
||||
LabelPolicy: features.LabelPolicy,
|
||||
CustomDomain: features.CustomDomain,
|
||||
|
@ -1,9 +1,10 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/caos/zitadel/internal/domain"
|
||||
"github.com/caos/zitadel/internal/eventstore/v1/models"
|
||||
"time"
|
||||
)
|
||||
|
||||
type LoginPolicyView struct {
|
||||
@ -12,6 +13,7 @@ type LoginPolicyView struct {
|
||||
AllowRegister bool
|
||||
AllowExternalIDP bool
|
||||
ForceMFA bool
|
||||
HidePasswordReset bool
|
||||
PasswordlessType PasswordlessType
|
||||
SecondFactors []SecondFactorType
|
||||
MultiFactors []MultiFactorType
|
||||
@ -80,6 +82,7 @@ func (p *LoginPolicyView) ToLoginPolicyDomain() *domain.LoginPolicy {
|
||||
AllowRegister: p.AllowRegister,
|
||||
AllowExternalIDP: p.AllowExternalIDP,
|
||||
ForceMFA: p.ForceMFA,
|
||||
HidePasswordReset: p.HidePasswordReset,
|
||||
PasswordlessType: passwordLessTypeToDomain(p.PasswordlessType),
|
||||
SecondFactors: secondFactorsToDomain(p.SecondFactors),
|
||||
MultiFactors: multiFactorsToDomain(p.MultiFactors),
|
||||
|
@ -2,13 +2,16 @@ package model
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
org_es_model "github.com/caos/zitadel/internal/org/repository/eventsourcing/model"
|
||||
"github.com/lib/pq"
|
||||
"time"
|
||||
|
||||
"github.com/lib/pq"
|
||||
|
||||
org_es_model "github.com/caos/zitadel/internal/org/repository/eventsourcing/model"
|
||||
|
||||
es_model "github.com/caos/zitadel/internal/iam/repository/eventsourcing/model"
|
||||
|
||||
"github.com/caos/logging"
|
||||
|
||||
caos_errs "github.com/caos/zitadel/internal/errors"
|
||||
"github.com/caos/zitadel/internal/eventstore/v1/models"
|
||||
"github.com/caos/zitadel/internal/iam/model"
|
||||
@ -29,6 +32,7 @@ type LoginPolicyView struct {
|
||||
AllowUsernamePassword bool `json:"allowUsernamePassword" gorm:"column:allow_username_password"`
|
||||
AllowExternalIDP bool `json:"allowExternalIdp" gorm:"column:allow_external_idp"`
|
||||
ForceMFA bool `json:"forceMFA" gorm:"column:force_mfa"`
|
||||
HidePasswordReset bool `json:"hidePasswordReset" gorm:"column:hide_password_reset"`
|
||||
PasswordlessType int32 `json:"passwordlessType" gorm:"column:passwordless_type"`
|
||||
SecondFactors pq.Int64Array `json:"-" gorm:"column:second_factors"`
|
||||
MultiFactors pq.Int64Array `json:"-" gorm:"column:multi_factors"`
|
||||
@ -47,6 +51,7 @@ func LoginPolicyViewFromModel(policy *model.LoginPolicyView) *LoginPolicyView {
|
||||
AllowExternalIDP: policy.AllowExternalIDP,
|
||||
AllowUsernamePassword: policy.AllowUsernamePassword,
|
||||
ForceMFA: policy.ForceMFA,
|
||||
HidePasswordReset: policy.HidePasswordReset,
|
||||
PasswordlessType: int32(policy.PasswordlessType),
|
||||
SecondFactors: secondFactorsFromModel(policy.SecondFactors),
|
||||
MultiFactors: multiFactorsFromModel(policy.MultiFactors),
|
||||
@ -80,6 +85,7 @@ func LoginPolicyViewToModel(policy *LoginPolicyView) *model.LoginPolicyView {
|
||||
AllowExternalIDP: policy.AllowExternalIDP,
|
||||
AllowUsernamePassword: policy.AllowUsernamePassword,
|
||||
ForceMFA: policy.ForceMFA,
|
||||
HidePasswordReset: policy.HidePasswordReset,
|
||||
PasswordlessType: model.PasswordlessType(policy.PasswordlessType),
|
||||
SecondFactors: secondFactorsToModel(policy.SecondFactors),
|
||||
MultiFactors: multiFactorsToToModel(policy.MultiFactors),
|
||||
|
@ -29,6 +29,7 @@ type FeaturesSetEvent struct {
|
||||
LoginPolicyPasswordless *bool `json:"loginPolicyPasswordless,omitempty"`
|
||||
LoginPolicyRegistration *bool `json:"loginPolicyRegistration,omitempty"`
|
||||
LoginPolicyUsernameLogin *bool `json:"loginPolicyUsernameLogin,omitempty"`
|
||||
LoginPolicyPasswordReset *bool `json:"loginPolicyPasswordReset,omitempty"`
|
||||
PasswordComplexityPolicy *bool `json:"passwordComplexityPolicy,omitempty"`
|
||||
LabelPolicy *bool `json:"labelPolicy,omitempty"`
|
||||
CustomDomain *bool `json:"customDomain,omitempty"`
|
||||
@ -120,6 +121,12 @@ func ChangeLoginPolicyUsernameLogin(loginPolicyUsernameLogin bool) func(event *F
|
||||
}
|
||||
}
|
||||
|
||||
func ChangeLoginPolicyPasswordReset(loginPolicyPasswordReset bool) func(event *FeaturesSetEvent) {
|
||||
return func(e *FeaturesSetEvent) {
|
||||
e.LoginPolicyPasswordReset = &loginPolicyPasswordReset
|
||||
}
|
||||
}
|
||||
|
||||
func ChangePasswordComplexityPolicy(passwordComplexityPolicy bool) func(event *FeaturesSetEvent) {
|
||||
return func(e *FeaturesSetEvent) {
|
||||
e.PasswordComplexityPolicy = &passwordComplexityPolicy
|
||||
|
@ -24,7 +24,8 @@ func NewLoginPolicyAddedEvent(
|
||||
allowUsernamePassword,
|
||||
allowRegister,
|
||||
allowExternalIDP,
|
||||
forceMFA bool,
|
||||
forceMFA,
|
||||
hidePasswordReset bool,
|
||||
passwordlessType domain.PasswordlessType,
|
||||
) *LoginPolicyAddedEvent {
|
||||
return &LoginPolicyAddedEvent{
|
||||
@ -37,6 +38,7 @@ func NewLoginPolicyAddedEvent(
|
||||
allowRegister,
|
||||
allowExternalIDP,
|
||||
forceMFA,
|
||||
hidePasswordReset,
|
||||
passwordlessType),
|
||||
}
|
||||
}
|
||||
|
@ -25,7 +25,8 @@ func NewLoginPolicyAddedEvent(
|
||||
allowUsernamePassword,
|
||||
allowRegister,
|
||||
allowExternalIDP,
|
||||
forceMFA bool,
|
||||
forceMFA,
|
||||
hidePasswordReset bool,
|
||||
passwordlessType domain.PasswordlessType,
|
||||
) *LoginPolicyAddedEvent {
|
||||
return &LoginPolicyAddedEvent{
|
||||
@ -38,6 +39,7 @@ func NewLoginPolicyAddedEvent(
|
||||
allowRegister,
|
||||
allowExternalIDP,
|
||||
forceMFA,
|
||||
hidePasswordReset,
|
||||
passwordlessType),
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ package policy
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/caos/zitadel/internal/domain"
|
||||
"github.com/caos/zitadel/internal/errors"
|
||||
"github.com/caos/zitadel/internal/eventstore"
|
||||
@ -22,6 +23,7 @@ type LoginPolicyAddedEvent struct {
|
||||
AllowRegister bool `json:"allowRegister,omitempty"`
|
||||
AllowExternalIDP bool `json:"allowExternalIdp,omitempty"`
|
||||
ForceMFA bool `json:"forceMFA,omitempty"`
|
||||
HidePasswordReset bool `json:"hidePasswordReset,omitempty"`
|
||||
PasswordlessType domain.PasswordlessType `json:"passwordlessType,omitempty"`
|
||||
}
|
||||
|
||||
@ -38,7 +40,8 @@ func NewLoginPolicyAddedEvent(
|
||||
allowUserNamePassword,
|
||||
allowRegister,
|
||||
allowExternalIDP,
|
||||
forceMFA bool,
|
||||
forceMFA,
|
||||
hidePasswordReset bool,
|
||||
passwordlessType domain.PasswordlessType,
|
||||
) *LoginPolicyAddedEvent {
|
||||
return &LoginPolicyAddedEvent{
|
||||
@ -48,6 +51,7 @@ func NewLoginPolicyAddedEvent(
|
||||
AllowUserNamePassword: allowUserNamePassword,
|
||||
ForceMFA: forceMFA,
|
||||
PasswordlessType: passwordlessType,
|
||||
HidePasswordReset: hidePasswordReset,
|
||||
}
|
||||
}
|
||||
|
||||
@ -71,6 +75,7 @@ type LoginPolicyChangedEvent struct {
|
||||
AllowRegister *bool `json:"allowRegister,omitempty"`
|
||||
AllowExternalIDP *bool `json:"allowExternalIdp,omitempty"`
|
||||
ForceMFA *bool `json:"forceMFA,omitempty"`
|
||||
HidePasswordReset *bool `json:"hidePasswordReset,omitempty"`
|
||||
PasswordlessType *domain.PasswordlessType `json:"passwordlessType,omitempty"`
|
||||
}
|
||||
|
||||
@ -133,6 +138,12 @@ func ChangePasswordlessType(passwordlessType domain.PasswordlessType) func(*Logi
|
||||
}
|
||||
}
|
||||
|
||||
func ChangeHidePasswordReset(hidePasswordReset bool) func(*LoginPolicyChangedEvent) {
|
||||
return func(e *LoginPolicyChangedEvent) {
|
||||
e.HidePasswordReset = &hidePasswordReset
|
||||
}
|
||||
}
|
||||
|
||||
func LoginPolicyChangedEventMapper(event *repository.Event) (eventstore.EventReader, error) {
|
||||
e := &LoginPolicyChangedEvent{
|
||||
BaseEvent: *eventstore.BaseEventFromRepo(event),
|
||||
|
@ -21,7 +21,15 @@ func (l *Login) renderPassword(w http.ResponseWriter, r *http.Request, authReq *
|
||||
errMessage = l.getErrorMessage(r, err)
|
||||
}
|
||||
data := l.getUserData(r, authReq, "Password", errType, errMessage)
|
||||
l.renderer.RenderTemplate(w, r, l.renderer.Templates[tmplPassword], data, nil)
|
||||
funcs := map[string]interface{}{
|
||||
"showPasswordReset": func() bool {
|
||||
if authReq.LoginPolicy != nil {
|
||||
return !authReq.LoginPolicy.HidePasswordReset
|
||||
}
|
||||
return true
|
||||
},
|
||||
}
|
||||
l.renderer.RenderTemplate(w, r, l.renderer.Templates[tmplPassword], data, funcs)
|
||||
}
|
||||
|
||||
func (l *Login) handlePasswordCheck(w http.ResponseWriter, r *http.Request) {
|
||||
|
@ -153,6 +153,9 @@ func CreateRenderer(pathPrefix string, staticDir http.FileSystem, cookieName str
|
||||
"hasUsernamePasswordLogin": func() bool {
|
||||
return false
|
||||
},
|
||||
"showPasswordReset": func() bool {
|
||||
return true
|
||||
},
|
||||
"hasExternalLogin": func() bool {
|
||||
return false
|
||||
},
|
||||
|
@ -21,9 +21,11 @@
|
||||
|
||||
{{template "error-message" .}}
|
||||
|
||||
{{ if showPasswordReset }}
|
||||
<a class="block" href="{{ passwordResetUrl .AuthReqID }}">
|
||||
{{t "Actions.ForgotPassword"}}
|
||||
</a>
|
||||
{{ end }}
|
||||
|
||||
<div class="lgn-actions">
|
||||
<a href="{{ loginNameChangeUrl .AuthReqID }}">
|
||||
|
9
migrations/cockroach/V1.46__password_reset.sql
Normal file
9
migrations/cockroach/V1.46__password_reset.sql
Normal file
@ -0,0 +1,9 @@
|
||||
ALTER TABLE adminapi.features ADD COLUMN login_policy_password_reset BOOLEAN;
|
||||
ALTER TABLE auth.features ADD COLUMN login_policy_password_reset BOOLEAN;
|
||||
ALTER TABLE authz.features ADD COLUMN login_policy_password_reset BOOLEAN;
|
||||
ALTER TABLE management.features ADD COLUMN login_policy_password_reset BOOLEAN;
|
||||
|
||||
|
||||
ALTER TABLE auth.login_policies ADD COLUMN hide_password_reset BOOLEAN;
|
||||
ALTER TABLE adminapi.login_policies ADD COLUMN hide_password_reset BOOLEAN;
|
||||
ALTER TABLE management.login_policies ADD COLUMN hide_password_reset BOOLEAN;
|
@ -2194,6 +2194,7 @@ message SetDefaultFeaturesRequest {
|
||||
bool password_complexity_policy = 11;
|
||||
bool label_policy = 12;
|
||||
bool custom_domain = 13;
|
||||
bool login_policy_password_reset = 14;
|
||||
}
|
||||
|
||||
message SetDefaultFeaturesResponse {
|
||||
@ -2224,6 +2225,7 @@ message SetOrgFeaturesRequest {
|
||||
bool password_complexity_policy = 12;
|
||||
bool label_policy = 13;
|
||||
bool custom_domain = 14;
|
||||
bool login_policy_password_reset = 15;
|
||||
}
|
||||
|
||||
message SetOrgFeaturesResponse {
|
||||
@ -2421,6 +2423,11 @@ message UpdateLoginPolicyRequest {
|
||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
description: "defines if passwordless is allowed for users"
|
||||
}];
|
||||
bool hide_password_reset = 6 [
|
||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
description: "defines if password reset link should be shown in the login screen"
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
message UpdateLoginPolicyResponse {
|
||||
|
@ -21,6 +21,7 @@ message Features {
|
||||
bool password_complexity_policy = 10;
|
||||
bool label_policy = 11;
|
||||
bool custom_domain = 12;
|
||||
bool login_policy_password_reset = 13;
|
||||
}
|
||||
|
||||
message FeatureTier {
|
||||
|
@ -3373,6 +3373,7 @@ message AddCustomLoginPolicyRequest {
|
||||
bool allow_external_idp = 3;
|
||||
bool force_mfa = 4;
|
||||
zitadel.policy.v1.PasswordlessType passwordless_type = 5 [(validate.rules).enum = {defined_only: true}];
|
||||
bool hide_password_reset = 6;
|
||||
}
|
||||
|
||||
message AddCustomLoginPolicyResponse {
|
||||
@ -3385,6 +3386,7 @@ message UpdateCustomLoginPolicyRequest {
|
||||
bool allow_external_idp = 3;
|
||||
bool force_mfa = 4;
|
||||
zitadel.policy.v1.PasswordlessType passwordless_type = 5 [(validate.rules).enum = {defined_only: true}];
|
||||
bool hide_password_reset = 6;
|
||||
}
|
||||
|
||||
message UpdateCustomLoginPolicyResponse {
|
||||
|
@ -77,6 +77,11 @@ message LoginPolicy {
|
||||
description: "defines if the organisation's admin changed the policy"
|
||||
}
|
||||
];
|
||||
bool hide_password_reset = 8 [
|
||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
description: "defines if password reset link should be shown in the login screen"
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
enum SecondFactorType {
|
||||
|
Loading…
x
Reference in New Issue
Block a user