Skip to content

Commit defdb66

Browse files
authored
Add enforcementState and forceUpgradeOnSignin to PasswordPolicy type (#7476)
* Add enforcementState and forceUpgradeOnSignin to PasswordPolicy type
1 parent a70a9ac commit defdb66

File tree

8 files changed

+123
-4
lines changed

8 files changed

+123
-4
lines changed

common/api-review/auth.api.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -573,6 +573,8 @@ export interface PasswordPolicy {
573573
readonly containsNumericCharacter?: boolean;
574574
readonly containsNonAlphanumericCharacter?: boolean;
575575
};
576+
readonly enforcementState: string;
577+
readonly forceUpgradeOnSignin: boolean;
576578
}
577579

578580
// @public

docs-devsite/auth.passwordpolicy.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ export interface PasswordPolicy
2424
| --- | --- | --- |
2525
| [allowedNonAlphanumericCharacters](./auth.passwordpolicy.md#passwordpolicyallowednonalphanumericcharacters) | string | List of characters that are considered non-alphanumeric during validation. |
2626
| [customStrengthOptions](./auth.passwordpolicy.md#passwordpolicycustomstrengthoptions) | { readonly minPasswordLength?: number; readonly maxPasswordLength?: number; readonly containsLowercaseLetter?: boolean; readonly containsUppercaseLetter?: boolean; readonly containsNumericCharacter?: boolean; readonly containsNonAlphanumericCharacter?: boolean; } | Requirements enforced by this password policy. |
27+
| [enforcementState](./auth.passwordpolicy.md#passwordpolicyenforcementstate) | string | The enforcement state of the policy. Can be 'OFF' or 'ENFORCE'. |
28+
| [forceUpgradeOnSignin](./auth.passwordpolicy.md#passwordpolicyforceupgradeonsignin) | boolean | Whether existing passwords must meet the policy. |
2729

2830
## PasswordPolicy.allowedNonAlphanumericCharacters
2931

@@ -51,3 +53,23 @@ readonly customStrengthOptions: {
5153
readonly containsNonAlphanumericCharacter?: boolean;
5254
};
5355
```
56+
57+
## PasswordPolicy.enforcementState
58+
59+
The enforcement state of the policy. Can be 'OFF' or 'ENFORCE'.
60+
61+
<b>Signature:</b>
62+
63+
```typescript
64+
readonly enforcementState: string;
65+
```
66+
67+
## PasswordPolicy.forceUpgradeOnSignin
68+
69+
Whether existing passwords must meet the policy.
70+
71+
<b>Signature:</b>
72+
73+
```typescript
74+
readonly forceUpgradeOnSignin: boolean;
75+
```

packages/auth/src/api/password_policy/get_password_policy.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ export interface GetPasswordPolicyResponse {
4343
containsNonAlphanumericCharacter?: boolean;
4444
};
4545
allowedNonAlphanumericCharacters: string[];
46+
enforcementState: string;
47+
forceUpgradeOnSignin?: boolean;
4648
schemaVersion: number;
4749
}
4850

packages/auth/src/core/auth/auth_impl.test.ts

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -794,6 +794,8 @@ describe('core/auth/auth_impl', () => {
794794
const TEST_ALLOWED_NON_ALPHANUMERIC_STRING =
795795
TEST_ALLOWED_NON_ALPHANUMERIC_CHARS.join('');
796796
const TEST_MIN_PASSWORD_LENGTH = 6;
797+
const TEST_ENFORCEMENT_STATE_ENFORCE = 'ENFORCE';
798+
const TEST_FORCE_UPGRADE_ON_SIGN_IN = false;
797799
const TEST_SCHEMA_VERSION = 1;
798800
const TEST_UNSUPPORTED_SCHEMA_VERSION = 0;
799801
const TEST_TENANT_ID = 'tenant-id';
@@ -805,6 +807,7 @@ describe('core/auth/auth_impl', () => {
805807
minPasswordLength: TEST_MIN_PASSWORD_LENGTH
806808
},
807809
allowedNonAlphanumericCharacters: TEST_ALLOWED_NON_ALPHANUMERIC_CHARS,
810+
enforcementState: TEST_ENFORCEMENT_STATE_ENFORCE,
808811
schemaVersion: TEST_SCHEMA_VERSION
809812
};
810813
const PASSWORD_POLICY_RESPONSE_REQUIRE_NUMERIC = {
@@ -813,6 +816,7 @@ describe('core/auth/auth_impl', () => {
813816
containsNumericCharacter: true
814817
},
815818
allowedNonAlphanumericCharacters: TEST_ALLOWED_NON_ALPHANUMERIC_CHARS,
819+
enforcementState: TEST_ENFORCEMENT_STATE_ENFORCE,
816820
schemaVersion: TEST_SCHEMA_VERSION
817821
};
818822
const PASSWORD_POLICY_RESPONSE_UNSUPPORTED_SCHEMA_VERSION = {
@@ -821,13 +825,17 @@ describe('core/auth/auth_impl', () => {
821825
unsupportedPasswordPolicyProperty: 10
822826
},
823827
allowedNonAlphanumericCharacters: TEST_ALLOWED_NON_ALPHANUMERIC_CHARS,
828+
enforcementState: TEST_ENFORCEMENT_STATE_ENFORCE,
829+
forceUpgradeOnSignin: TEST_FORCE_UPGRADE_ON_SIGN_IN,
824830
schemaVersion: TEST_UNSUPPORTED_SCHEMA_VERSION
825831
};
826832
const CACHED_PASSWORD_POLICY = {
827833
customStrengthOptions: {
828834
minPasswordLength: TEST_MIN_PASSWORD_LENGTH
829835
},
830836
allowedNonAlphanumericCharacters: TEST_ALLOWED_NON_ALPHANUMERIC_STRING,
837+
enforcementState: TEST_ENFORCEMENT_STATE_ENFORCE,
838+
forceUpgradeOnSignin: TEST_FORCE_UPGRADE_ON_SIGN_IN,
831839
schemaVersion: TEST_SCHEMA_VERSION
832840
};
833841
const CACHED_PASSWORD_POLICY_REQUIRE_NUMERIC = {
@@ -836,13 +844,17 @@ describe('core/auth/auth_impl', () => {
836844
containsNumericCharacter: true
837845
},
838846
allowedNonAlphanumericCharacters: TEST_ALLOWED_NON_ALPHANUMERIC_STRING,
847+
enforcementState: TEST_ENFORCEMENT_STATE_ENFORCE,
848+
forceUpgradeOnSignin: TEST_FORCE_UPGRADE_ON_SIGN_IN,
839849
schemaVersion: TEST_SCHEMA_VERSION
840850
};
841-
const PASSWORD_POLICY_UNSUPPORTED_SCHEMA_VERSION = {
851+
const CACHED_PASSWORD_POLICY_UNSUPPORTED_SCHEMA_VERSION = {
842852
customStrengthOptions: {
843853
maxPasswordLength: TEST_MIN_PASSWORD_LENGTH
844854
},
845855
allowedNonAlphanumericCharacters: TEST_ALLOWED_NON_ALPHANUMERIC_STRING,
856+
enforcementState: TEST_ENFORCEMENT_STATE_ENFORCE,
857+
forceUpgradeOnSignin: TEST_FORCE_UPGRADE_ON_SIGN_IN,
846858
schemaVersion: TEST_UNSUPPORTED_SCHEMA_VERSION
847859
};
848860

@@ -915,7 +927,7 @@ describe('core/auth/auth_impl', () => {
915927
await expect(auth._updatePasswordPolicy()).to.be.fulfilled;
916928

917929
expect(auth._getPasswordPolicyInternal()).to.eql(
918-
PASSWORD_POLICY_UNSUPPORTED_SCHEMA_VERSION
930+
CACHED_PASSWORD_POLICY_UNSUPPORTED_SCHEMA_VERSION
919931
);
920932
});
921933

packages/auth/src/core/auth/password_policy_impl.test.ts

Lines changed: 59 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,10 @@ describe('core/auth/password_policy_impl', () => {
3939
const TEST_ALLOWED_NON_ALPHANUMERIC_CHARS = ['!', '(', ')', '@'];
4040
const TEST_ALLOWED_NON_ALPHANUMERIC_STRING =
4141
TEST_ALLOWED_NON_ALPHANUMERIC_CHARS.join('');
42+
const TEST_ENFORCEMENT_STATE_ENFORCE = 'ENFORCE';
43+
const TEST_ENFORCEMENT_STATE_OFF = 'OFF';
44+
const TEST_REQUIRE_ALL_FORCE_UPGRADE_ON_SIGN_IN = true;
45+
const TEST_REQUIRE_LENGTH_FORCE_UPGRADE_ON_SIGN_IN = false;
4246
const TEST_SCHEMA_VERSION = 1;
4347
const PASSWORD_POLICY_RESPONSE_REQUIRE_ALL: GetPasswordPolicyResponse = {
4448
customStrengthOptions: {
@@ -50,6 +54,8 @@ describe('core/auth/password_policy_impl', () => {
5054
containsNonAlphanumericCharacter: TEST_CONTAINS_NON_ALPHANUMERIC
5155
},
5256
allowedNonAlphanumericCharacters: TEST_ALLOWED_NON_ALPHANUMERIC_CHARS,
57+
enforcementState: TEST_ENFORCEMENT_STATE_ENFORCE,
58+
forceUpgradeOnSignin: TEST_REQUIRE_ALL_FORCE_UPGRADE_ON_SIGN_IN,
5359
schemaVersion: TEST_SCHEMA_VERSION
5460
};
5561
const PASSWORD_POLICY_RESPONSE_REQUIRE_LENGTH: GetPasswordPolicyResponse = {
@@ -58,6 +64,8 @@ describe('core/auth/password_policy_impl', () => {
5864
maxPasswordLength: TEST_MAX_PASSWORD_LENGTH
5965
},
6066
allowedNonAlphanumericCharacters: TEST_ALLOWED_NON_ALPHANUMERIC_CHARS,
67+
enforcementState: TEST_ENFORCEMENT_STATE_OFF,
68+
forceUpgradeOnSignin: TEST_REQUIRE_LENGTH_FORCE_UPGRADE_ON_SIGN_IN,
6169
schemaVersion: TEST_SCHEMA_VERSION
6270
};
6371
const PASSWORD_POLICY_RESPONSE_REQUIRE_NUMERIC: GetPasswordPolicyResponse = {
@@ -67,8 +75,19 @@ describe('core/auth/password_policy_impl', () => {
6775
containsNumericCharacter: TEST_CONTAINS_NUMERIC
6876
},
6977
allowedNonAlphanumericCharacters: TEST_ALLOWED_NON_ALPHANUMERIC_CHARS,
78+
enforcementState: TEST_ENFORCEMENT_STATE_ENFORCE,
7079
schemaVersion: TEST_SCHEMA_VERSION
7180
};
81+
const PASSWORD_POLICY_RESPONSE_UNSPECIFIED_ENFORCEMENT_STATE: GetPasswordPolicyResponse =
82+
{
83+
customStrengthOptions: {
84+
minPasswordLength: TEST_MIN_PASSWORD_LENGTH,
85+
maxPasswordLength: TEST_MAX_PASSWORD_LENGTH
86+
},
87+
allowedNonAlphanumericCharacters: TEST_ALLOWED_NON_ALPHANUMERIC_CHARS,
88+
enforcementState: 'ENFORCEMENT_STATE_UNSPECIFIED',
89+
schemaVersion: TEST_SCHEMA_VERSION
90+
};
7291
const PASSWORD_POLICY_REQUIRE_ALL: PasswordPolicy = {
7392
customStrengthOptions: {
7493
minPasswordLength: TEST_MIN_PASSWORD_LENGTH,
@@ -78,14 +97,18 @@ describe('core/auth/password_policy_impl', () => {
7897
containsNumericCharacter: TEST_CONTAINS_NUMERIC,
7998
containsNonAlphanumericCharacter: TEST_CONTAINS_UPPERCASE
8099
},
81-
allowedNonAlphanumericCharacters: TEST_ALLOWED_NON_ALPHANUMERIC_STRING
100+
allowedNonAlphanumericCharacters: TEST_ALLOWED_NON_ALPHANUMERIC_STRING,
101+
enforcementState: TEST_ENFORCEMENT_STATE_ENFORCE,
102+
forceUpgradeOnSignin: TEST_REQUIRE_ALL_FORCE_UPGRADE_ON_SIGN_IN
82103
};
83104
const PASSWORD_POLICY_REQUIRE_LENGTH: PasswordPolicy = {
84105
customStrengthOptions: {
85106
minPasswordLength: TEST_MIN_PASSWORD_LENGTH,
86107
maxPasswordLength: TEST_MAX_PASSWORD_LENGTH
87108
},
88-
allowedNonAlphanumericCharacters: TEST_ALLOWED_NON_ALPHANUMERIC_STRING
109+
allowedNonAlphanumericCharacters: TEST_ALLOWED_NON_ALPHANUMERIC_STRING,
110+
enforcementState: TEST_ENFORCEMENT_STATE_OFF,
111+
forceUpgradeOnSignin: TEST_REQUIRE_LENGTH_FORCE_UPGRADE_ON_SIGN_IN
89112
};
90113
const TEST_EMPTY_PASSWORD = '';
91114

@@ -100,6 +123,9 @@ describe('core/auth/password_policy_impl', () => {
100123
expect(policy.allowedNonAlphanumericCharacters).to.eql(
101124
PASSWORD_POLICY_REQUIRE_ALL.allowedNonAlphanumericCharacters
102125
);
126+
expect(policy.enforcementState).to.eql(
127+
PASSWORD_POLICY_REQUIRE_ALL.enforcementState
128+
);
103129
expect(policy.schemaVersion).to.eql(
104130
PASSWORD_POLICY_RESPONSE_REQUIRE_ALL.schemaVersion
105131
);
@@ -115,6 +141,9 @@ describe('core/auth/password_policy_impl', () => {
115141
expect(policy.allowedNonAlphanumericCharacters).to.eql(
116142
PASSWORD_POLICY_REQUIRE_LENGTH.allowedNonAlphanumericCharacters
117143
);
144+
expect(policy.enforcementState).to.eql(
145+
PASSWORD_POLICY_REQUIRE_LENGTH.enforcementState
146+
);
118147
expect(policy.schemaVersion).to.eql(
119148
PASSWORD_POLICY_RESPONSE_REQUIRE_LENGTH.schemaVersion
120149
);
@@ -129,6 +158,20 @@ describe('core/auth/password_policy_impl', () => {
129158
.be.undefined;
130159
});
131160

161+
it("assigns 'OFF' as the enforcement state when it is unspecified", () => {
162+
const policy: PasswordPolicyInternal = new PasswordPolicyImpl(
163+
PASSWORD_POLICY_RESPONSE_UNSPECIFIED_ENFORCEMENT_STATE
164+
);
165+
expect(policy.enforcementState).to.eql(TEST_ENFORCEMENT_STATE_OFF);
166+
});
167+
168+
it('assigns false to forceUpgradeOnSignin when it is undefined in the response', () => {
169+
const policy: PasswordPolicyInternal = new PasswordPolicyImpl(
170+
PASSWORD_POLICY_RESPONSE_REQUIRE_NUMERIC
171+
);
172+
expect(policy.forceUpgradeOnSignin).to.be.false;
173+
});
174+
132175
context('#validatePassword', () => {
133176
const PASSWORD_POLICY_IMPL_REQUIRE_ALL = new PasswordPolicyImpl(
134177
PASSWORD_POLICY_RESPONSE_REQUIRE_ALL
@@ -339,6 +382,20 @@ describe('core/auth/password_policy_impl', () => {
339382
expect(status.containsUppercaseLetter).to.be.undefined;
340383
expect(status.containsNonAlphanumericCharacter).to.be.undefined;
341384
});
385+
386+
it("should consider a password invalid if it does not meet all requirements even if the enforcement state is 'OFF'", async () => {
387+
const policy = PASSWORD_POLICY_IMPL_REQUIRE_NUMERIC;
388+
const expectedValidationStatus: PasswordValidationStatus = {
389+
isValid: false,
390+
meetsMinPasswordLength: false,
391+
meetsMaxPasswordLength: true,
392+
containsNumericCharacter: true,
393+
passwordPolicy: policy
394+
};
395+
396+
const status = policy.validatePassword('p4ss');
397+
expect(status).to.eql(expectedValidationStatus);
398+
});
342399
});
343400
});
344401
});

packages/auth/src/core/auth/password_policy_impl.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ import { PasswordValidationStatus } from '../../model/public_types';
3131
export class PasswordPolicyImpl implements PasswordPolicyInternal {
3232
readonly customStrengthOptions: PasswordPolicyCustomStrengthOptions;
3333
readonly allowedNonAlphanumericCharacters: string;
34+
readonly enforcementState: string;
35+
readonly forceUpgradeOnSignin: boolean;
3436
readonly schemaVersion: number;
3537

3638
constructor(response: GetPasswordPolicyResponse) {
@@ -62,8 +64,14 @@ export class PasswordPolicyImpl implements PasswordPolicyInternal {
6264
responseOptions.containsNonAlphanumericCharacter;
6365
}
6466

67+
this.enforcementState = response.enforcementState;
68+
if (this.enforcementState === 'ENFORCEMENT_STATE_UNSPECIFIED') {
69+
this.enforcementState = 'OFF';
70+
}
71+
6572
this.allowedNonAlphanumericCharacters =
6673
response.allowedNonAlphanumericCharacters.join('');
74+
this.forceUpgradeOnSignin = response.forceUpgradeOnSignin ?? false;
6775
this.schemaVersion = response.schemaVersion;
6876
}
6977

packages/auth/src/core/strategies/email_and_password.test.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -802,6 +802,8 @@ describe('password policy cache is updated in auth flows upon error', () => {
802802
const TEST_ALLOWED_NON_ALPHANUMERIC_CHARS = ['!', '(', ')'];
803803
const TEST_ALLOWED_NON_ALPHANUMERIC_STRING =
804804
TEST_ALLOWED_NON_ALPHANUMERIC_CHARS.join('');
805+
const TEST_ENFORCEMENT_STATE = 'ENFORCE';
806+
const TEST_FORCE_UPGRADE_ON_SIGN_IN = false;
805807
const TEST_SCHEMA_VERSION = 1;
806808
const TEST_TENANT_ID = 'tenant-id';
807809
const TEST_TENANT_ID_REQUIRE_NUMERIC = 'other-tenant-id';
@@ -812,6 +814,7 @@ describe('password policy cache is updated in auth flows upon error', () => {
812814
minPasswordLength: TEST_MIN_PASSWORD_LENGTH
813815
},
814816
allowedNonAlphanumericCharacters: TEST_ALLOWED_NON_ALPHANUMERIC_CHARS,
817+
enforcementState: TEST_ENFORCEMENT_STATE,
815818
schemaVersion: TEST_SCHEMA_VERSION
816819
};
817820
const PASSWORD_POLICY_RESPONSE_REQUIRE_NUMERIC = {
@@ -820,13 +823,16 @@ describe('password policy cache is updated in auth flows upon error', () => {
820823
containsNumericCharacter: true
821824
},
822825
allowedNonAlphanumericCharacters: TEST_ALLOWED_NON_ALPHANUMERIC_CHARS,
826+
enforcementState: TEST_ENFORCEMENT_STATE,
823827
schemaVersion: TEST_SCHEMA_VERSION
824828
};
825829
const CACHED_PASSWORD_POLICY = {
826830
customStrengthOptions: {
827831
minPasswordLength: TEST_MIN_PASSWORD_LENGTH
828832
},
829833
allowedNonAlphanumericCharacters: TEST_ALLOWED_NON_ALPHANUMERIC_STRING,
834+
enforcementState: TEST_ENFORCEMENT_STATE,
835+
forceUpgradeOnSignin: TEST_FORCE_UPGRADE_ON_SIGN_IN,
830836
schemaVersion: TEST_SCHEMA_VERSION
831837
};
832838
const CACHED_PASSWORD_POLICY_REQUIRE_NUMERIC = {
@@ -835,6 +841,8 @@ describe('password policy cache is updated in auth flows upon error', () => {
835841
containsNumericCharacter: true
836842
},
837843
allowedNonAlphanumericCharacters: TEST_ALLOWED_NON_ALPHANUMERIC_STRING,
844+
enforcementState: TEST_ENFORCEMENT_STATE,
845+
forceUpgradeOnSignin: TEST_FORCE_UPGRADE_ON_SIGN_IN,
838846
schemaVersion: TEST_SCHEMA_VERSION
839847
};
840848
let policyEndpointMock: mockFetch.Route;

packages/auth/src/model/public_types.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1292,6 +1292,14 @@ export interface PasswordPolicy {
12921292
* List of characters that are considered non-alphanumeric during validation.
12931293
*/
12941294
readonly allowedNonAlphanumericCharacters: string;
1295+
/**
1296+
* The enforcement state of the policy. Can be 'OFF' or 'ENFORCE'.
1297+
*/
1298+
readonly enforcementState: string;
1299+
/**
1300+
* Whether existing passwords must meet the policy.
1301+
*/
1302+
readonly forceUpgradeOnSignin: boolean;
12951303
}
12961304

12971305
/**

0 commit comments

Comments
 (0)