mirror of
https://github.com/zitadel/zitadel.git
synced 2025-08-11 19:07:30 +00:00
feat: password age policy (#8132)
# Which Problems Are Solved Some organizations / customers have the requirement, that there users regularly need to change their password. ZITADEL already had the possibility to manage a `password age policy` ( thought the API) with the maximum amount of days a password should be valid, resp. days after with the user should be warned of the upcoming expiration. The policy could not be managed though the Console UI and was not checked in the Login UI. # How the Problems Are Solved - The policy can be managed in the Console UI's settings sections on an instance and organization level. - During an authentication in the Login UI, if a policy is set with an expiry (>0) and the user's last password change exceeds the amount of days set, the user will be prompted to change their password. - The prompt message of the Login UI can be customized in the Custom Login Texts though the Console and API on the instance and each organization. - The information when the user last changed their password is returned in the Auth, Management and User V2 API. - The policy can be retrieved in the settings service as `password expiry settings`. # Additional Changes None. # Additional Context - closes #8081 --------- Co-authored-by: Tim Möhlmann <tim+github@zitadel.com>
This commit is contained in:
@@ -2655,7 +2655,7 @@ service AdminService {
|
||||
tags: "Settings";
|
||||
tags: "Password Settings";
|
||||
summary: "Get Password Age Settings";
|
||||
description: "Not implemented"
|
||||
description: "Returns the password age settings configured on the instance. It affects all organizations, that do not have a custom setting configured. The settings specify the expiry of password, after which a user is forced to change it on the next login.";
|
||||
responses: {
|
||||
key: "200";
|
||||
value: {
|
||||
@@ -2679,7 +2679,7 @@ service AdminService {
|
||||
tags: "Settings";
|
||||
tags: "Password Settings";
|
||||
summary: "Update Password Age Settings";
|
||||
description: "Not implemented"
|
||||
description: "Updates the default password complexity settings configured on the instance. It affects all organizations, that do not have a custom setting configured. The settings specify the expiry of password, after which a user is forced to change it on the next login.";
|
||||
responses: {
|
||||
key: "200";
|
||||
value: {
|
||||
@@ -6736,18 +6736,10 @@ message GetPasswordAgePolicyResponse {
|
||||
}
|
||||
|
||||
message UpdatePasswordAgePolicyRequest {
|
||||
uint32 max_age_days = 1 [
|
||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
description: "Maximum days since last password change"
|
||||
example: "\"365\""
|
||||
}
|
||||
];
|
||||
uint32 expire_warn_days = 2 [
|
||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
description: "Days before the password expiry the user gets notified to change the password"
|
||||
example: "\"10\""
|
||||
}
|
||||
];
|
||||
// Amount of days after which a password will expire. The user will be forced to change the password on the following authentication.
|
||||
uint32 max_age_days = 1;
|
||||
// Amount of days after which the user should be notified of the upcoming expiry. ZITADEL will not notify the user.
|
||||
uint32 expire_warn_days = 2;
|
||||
}
|
||||
|
||||
message UpdatePasswordAgePolicyResponse {
|
||||
|
@@ -4742,7 +4742,6 @@ service ManagementService {
|
||||
};
|
||||
}
|
||||
|
||||
// The password age policy is not used at the moment
|
||||
rpc GetPasswordAgePolicy(GetPasswordAgePolicyRequest) returns (GetPasswordAgePolicyResponse) {
|
||||
option (google.api.http) = {
|
||||
get: "/policies/password/age"
|
||||
@@ -4756,7 +4755,7 @@ service ManagementService {
|
||||
tags: "Settings";
|
||||
tags: "Password Settings";
|
||||
summary: "Get Password Age Settings";
|
||||
description: "Not implemented";
|
||||
description: "Returns the password age settings configured on the organization. The settings specify the expiry of password, after which a user is forced to change it on the next login.";
|
||||
parameters: {
|
||||
headers: {
|
||||
name: "x-zitadel-orgid";
|
||||
@@ -4768,7 +4767,6 @@ service ManagementService {
|
||||
};
|
||||
}
|
||||
|
||||
// The password age policy is not used at the moment
|
||||
rpc GetDefaultPasswordAgePolicy(GetDefaultPasswordAgePolicyRequest) returns (GetDefaultPasswordAgePolicyResponse) {
|
||||
option (google.api.http) = {
|
||||
get: "/policies/default/password/age"
|
||||
@@ -4782,7 +4780,7 @@ service ManagementService {
|
||||
tags: "Settings";
|
||||
tags: "Password Settings";
|
||||
summary: "Get Default Password Age Settings";
|
||||
description: "Not implemented";
|
||||
description: "Returns the default password age settings configured on the instance. The settings specify the expiry of password, after which a user is forced to change it on the next login.";
|
||||
parameters: {
|
||||
headers: {
|
||||
name: "x-zitadel-orgid";
|
||||
@@ -4794,7 +4792,6 @@ service ManagementService {
|
||||
};
|
||||
}
|
||||
|
||||
// The password age policy is not used at the moment
|
||||
rpc AddCustomPasswordAgePolicy(AddCustomPasswordAgePolicyRequest) returns (AddCustomPasswordAgePolicyResponse) {
|
||||
option (google.api.http) = {
|
||||
post: "/policies/password/age"
|
||||
@@ -4809,7 +4806,7 @@ service ManagementService {
|
||||
tags: "Settings";
|
||||
tags: "Password Settings";
|
||||
summary: "Add Password Age Settings";
|
||||
description: "Not implemented";
|
||||
description: "Create new password age settings for the organization. This will overwrite the settings of the instance for this organization. The settings specify the expiry of password, after which a user is forced to change it on the next login.";
|
||||
parameters: {
|
||||
headers: {
|
||||
name: "x-zitadel-orgid";
|
||||
@@ -4821,7 +4818,6 @@ service ManagementService {
|
||||
};
|
||||
}
|
||||
|
||||
// The password age policy is not used at the moment
|
||||
rpc UpdateCustomPasswordAgePolicy(UpdateCustomPasswordAgePolicyRequest) returns (UpdateCustomPasswordAgePolicyResponse) {
|
||||
option (google.api.http) = {
|
||||
put: "/policies/password/age"
|
||||
@@ -4836,7 +4832,7 @@ service ManagementService {
|
||||
tags: "Settings";
|
||||
tags: "Password Settings";
|
||||
summary: "Update Password Age Settings";
|
||||
description: "Not implemented";
|
||||
description: "Update the password age settings of the organization. The settings specify the expiry of password, after which a user is forced to change it on the next login.";
|
||||
parameters: {
|
||||
headers: {
|
||||
name: "x-zitadel-orgid";
|
||||
@@ -4848,7 +4844,6 @@ service ManagementService {
|
||||
};
|
||||
}
|
||||
|
||||
// The password age policy is not used at the moment
|
||||
rpc ResetPasswordAgePolicyToDefault(ResetPasswordAgePolicyToDefaultRequest) returns (ResetPasswordAgePolicyToDefaultResponse) {
|
||||
option (google.api.http) = {
|
||||
delete: "/policies/password/age"
|
||||
@@ -4862,7 +4857,7 @@ service ManagementService {
|
||||
tags: "Settings";
|
||||
tags: "Password Settings";
|
||||
summary: "Reset Password Age Settings to Default";
|
||||
description: "Not implemented";
|
||||
description: "Remove the password age settings of the organization and therefore use the default settings on the instance.. The settings specify the expiry of password, after which a user is forced to change it on the next login.";
|
||||
parameters: {
|
||||
headers: {
|
||||
name: "x-zitadel-orgid";
|
||||
@@ -10604,7 +10599,9 @@ message GetDefaultPasswordAgePolicyResponse {
|
||||
}
|
||||
|
||||
message AddCustomPasswordAgePolicyRequest {
|
||||
// Amount of days after which a password will expire. The user will be forced to change the password on the following authentication.
|
||||
uint32 max_age_days = 1;
|
||||
// Amount of days after which the user should be notified of the upcoming expiry. ZITADEL will not notify the user.
|
||||
uint32 expire_warn_days = 2;
|
||||
}
|
||||
|
||||
@@ -10613,7 +10610,9 @@ message AddCustomPasswordAgePolicyResponse {
|
||||
}
|
||||
|
||||
message UpdateCustomPasswordAgePolicyRequest {
|
||||
// Amount of days after which a password will expire. The user will be forced to change the password on the following authentication.
|
||||
uint32 max_age_days = 1;
|
||||
// Amount of days after which the user should be notified of the upcoming expiry. ZITADEL will not notify the user.
|
||||
uint32 expire_warn_days = 2;
|
||||
}
|
||||
|
||||
|
@@ -310,23 +310,20 @@ message PasswordComplexityPolicy {
|
||||
|
||||
message PasswordAgePolicy {
|
||||
zitadel.v1.ObjectDetails details = 1;
|
||||
// Amount of days after which a password will expire. The user will be forced to change the password on the following authentication.
|
||||
uint64 max_age_days = 2 [
|
||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
description: "Maximum days since last password change"
|
||||
example: "\"365\""
|
||||
}
|
||||
];
|
||||
// Amount of days after which the user should be notified of the upcoming expiry. ZITADEL will not notify the user.
|
||||
uint64 expire_warn_days = 3 [
|
||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
description: "Days before the password expiry the user gets notified to change the password"
|
||||
example: "\"10\""
|
||||
}
|
||||
];
|
||||
bool is_default = 4 [
|
||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
description: "defines if the organization's admin changed the policy"
|
||||
}
|
||||
];
|
||||
// If true, the returned values represent the instance settings, e.g. by an organization without custom settings.
|
||||
bool is_default = 4;
|
||||
}
|
||||
|
||||
message LockoutPolicy {
|
||||
|
@@ -41,3 +41,20 @@ message PasswordComplexitySettings {
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
message PasswordExpirySettings {
|
||||
// Amount of days after which a password will expire. The user will be forced to change the password on the following authentication.
|
||||
uint64 max_age_days = 1 [
|
||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
example: "\"365\""
|
||||
}
|
||||
];
|
||||
// Amount of days after which the user should be notified of the upcoming expiry. ZITADEL will not notify the user.
|
||||
uint64 expire_warn_days = 2 [
|
||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
example: "\"10\""
|
||||
}
|
||||
];
|
||||
// resource_owner_type returns if the settings is managed on the organization or on the instance
|
||||
ResourceOwnerType resource_owner_type = 3;
|
||||
}
|
||||
|
@@ -204,6 +204,30 @@ service SettingsService {
|
||||
};
|
||||
}
|
||||
|
||||
// Get the password expiry settings
|
||||
rpc GetPasswordExpirySettings (GetPasswordExpirySettingsRequest) returns (GetPasswordExpirySettingsResponse) {
|
||||
option (google.api.http) = {
|
||||
get: "/v2beta/settings/password/expiry"
|
||||
};
|
||||
|
||||
option (zitadel.protoc_gen_zitadel.v2.options) = {
|
||||
auth_option: {
|
||||
permission: "policy.read"
|
||||
}
|
||||
};
|
||||
|
||||
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {
|
||||
summary: "Get the password expiry settings";
|
||||
description: "Return the password expiry settings for the requested context"
|
||||
responses: {
|
||||
key: "200"
|
||||
value: {
|
||||
description: "OK";
|
||||
}
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
// Get the current active branding settings
|
||||
rpc GetBrandingSettings (GetBrandingSettingsRequest) returns (GetBrandingSettingsResponse) {
|
||||
option (google.api.http) = {
|
||||
@@ -358,6 +382,15 @@ message GetPasswordComplexitySettingsResponse {
|
||||
zitadel.settings.v2beta.PasswordComplexitySettings settings = 2;
|
||||
}
|
||||
|
||||
message GetPasswordExpirySettingsRequest {
|
||||
zitadel.object.v2beta.RequestContext ctx = 1;
|
||||
}
|
||||
|
||||
message GetPasswordExpirySettingsResponse {
|
||||
zitadel.object.v2beta.Details details = 1;
|
||||
zitadel.settings.v2beta.PasswordExpirySettings settings = 2;
|
||||
}
|
||||
|
||||
message GetBrandingSettingsRequest {
|
||||
zitadel.object.v2beta.RequestContext ctx = 1;
|
||||
}
|
||||
|
@@ -272,6 +272,7 @@ message PasswordChangeScreenText {
|
||||
string new_password_confirm_label = 5 [(validate.rules).string = {max_len: 200}];
|
||||
string cancel_button_text = 6 [(validate.rules).string = {max_len: 100}];
|
||||
string next_button_text = 7 [(validate.rules).string = {max_len: 100}];
|
||||
string expired_description = 8 [(validate.rules).string = {max_len: 500}];
|
||||
}
|
||||
|
||||
message PasswordChangeDoneScreenText {
|
||||
|
@@ -65,6 +65,8 @@ message Human {
|
||||
Profile profile = 1;
|
||||
Email email = 2;
|
||||
Phone phone = 3;
|
||||
// The time the user last changed their password.
|
||||
google.protobuf.Timestamp password_changed = 4;
|
||||
}
|
||||
|
||||
message Machine {
|
||||
|
@@ -5,6 +5,7 @@ package zitadel.user.v2beta;
|
||||
option go_package = "github.com/zitadel/zitadel/pkg/grpc/user/v2beta;user";
|
||||
|
||||
import "google/api/field_behavior.proto";
|
||||
import "google/protobuf/timestamp.proto";
|
||||
import "protoc-gen-openapiv2/options/annotations.proto";
|
||||
import "validate/validate.proto";
|
||||
import "zitadel/object/v2beta/object.proto";
|
||||
@@ -172,6 +173,8 @@ message HumanUser {
|
||||
HumanPhone phone = 8;
|
||||
// User is required to change the used password on the next login.
|
||||
bool password_change_required = 9;
|
||||
// The time the user last changed their password.
|
||||
google.protobuf.Timestamp password_changed = 10;
|
||||
}
|
||||
|
||||
message User {
|
||||
|
Reference in New Issue
Block a user