diff --git a/libs/auth/src/angular/input-password/input-password.mdx b/libs/auth/src/angular/input-password/input-password.mdx index 77542718f4c..384d6b2bc3d 100644 --- a/libs/auth/src/angular/input-password/input-password.mdx +++ b/libs/auth/src/angular/input-password/input-password.mdx @@ -6,14 +6,21 @@ import * as stories from "./input-password.stories.ts"; # InputPassword Component -The `InputPasswordComponent` allows a user to enter master password related credentials. On form -submission, the component creates cryptographic properties (`newMasterKey`, -`newServerMasterKeyHash`, etc.) and emits those properties to the parent (along with the other -values defined in `PasswordInputResult`). +The `InputPasswordComponent` allows a user to enter master password related credentials. +Specifically, it does the following: -The component is intended for re-use in different scenarios throughout the application. Therefore it -is mostly presentational and simply emits values rather than acting on them itself. It is the job of -the parent component to act on those values as needed. +1. Displays form fields in the UI +2. Validates form fields +3. Generates cryptographic properties based on the form inputs (e.g. `newMasterKey`, + `newServerMasterKeyHash`, etc.) +4. Emits the generated properties to the parent component + +The `InputPasswordComponent` is central to our set/change password flows. It allows us to keep our +form UI and validation logic consistent across our many set/change password flows. + +The component is intended for re-use in different set/change password scenarios throughout the +application. Therefore it is mostly presentational and simply emits values rather than acting on +them itself. It is the job of the parent component to act on those values as needed.
@@ -22,11 +29,13 @@ the parent component to act on those values as needed. - [@Inputs](#inputs) - [@Outputs](#outputs) - [The InputPasswordFlow](#the-inputpasswordflow) + - [Use Cases](#use-cases) - [HTML - Form Fields](#html---form-fields) - [TypeScript - Credential Generation](#typescript---credential-generation) - [Difference between SetInitialPasswordAccountRegistration and SetInitialPasswordAuthedUser](#difference-between-setinitialpasswordaccountregistration-and-setinitialpasswordautheduser) - [Validation](#validation) - [Submit Logic](#submit-logic) +- [Submitting From a Parent Dialog Component](#submitting-from-a-parent-dialog-component) - [Example](#example)
@@ -37,12 +46,23 @@ the parent component to act on those values as needed. - `flow` - the parent component must provide an `InputPasswordFlow`, which is used to determine which form input elements will be displayed in the UI and which cryptographic keys will be created - and emitted. -- `email` - the parent component must provide an email so that the `InputPasswordComponent` can - create a master key. + and emitted. [Click here](#the-inputpasswordflow) to learn more about the different + `InputPasswordFlow` options. + +**Optional (sometimes)** + +These two `@Inputs` are optional on some flows, but required on others. Therefore these `@Inputs` +are not marked as `{ required: true }`, but there _is_ component logic that ensures (requires) that +the `email` and/or `userId` is present in certain flows, while not present in other flows. + +- `email` - allows the `InputPasswordComponent` to generate a master key +- `userId` - allows the `InputPasswordComponent` to do things like get the user's `kdfConfig`, + decrypt the user key, and perform validation prior to user a key rotation on the parent **Optional** +These `@Inputs` are truly optional. + - `loading` - a boolean used to indicate that the parent component is performing some long-running/async operation and that the form should be disabled until the operation is complete. The primary button will also show a spinner if `loading` is true. @@ -57,6 +77,7 @@ the parent component to act on those values as needed. ## `@Output()`'s - `onPasswordFormSubmit` - on form submit, emits a `PasswordInputResult` object + ([see more below](#submit-logic)). - `onSecondaryButtonClick` - on click, emits a notice that the secondary button has been clicked. The parent component can listen for this event and take some custom action as needed (go back, cancel, logout, etc.) @@ -66,44 +87,88 @@ the parent component to act on those values as needed. ## The `InputPasswordFlow` The `InputPasswordFlow` is a crucial and required `@Input` that influences both the HTML and the -credential generation logic of the component. +credential generation logic of the component. It is important for the dev to understand when to use +each flow. -
+### Use Cases + +**`SetInitialPasswordAccountRegistration`** + +Used in scenarios where we have no existing user, and thus NO active account `userId`: + +- Standard Account Registration +- Email Invite Account Registration +- Trial Initiation Account registration

+ +**`SetInitialPasswordAuthedUser`** + +Used in scenarios where we do have an existing and authed user, and thus an active account `userId`: + +- A "just-in-time" (JIT) provisioned user joins a master password (MP) encryption org and must set + their initial password +- A "just-in-time" (JIT) provisioned user joins a trusted device encryption (TDE) org with a + starting role that requires them to have/set their initial password + - A note on JIT provisioned user flows: + - Even though a JIT provisioned user is a brand-new user who was “just” created, we consider + them to be an “existing authed user” _from the perspective of the set-password flow_. This is + because at the time they set their initial password, their account already exists in the + database (before setting their password) and they have already authenticated via SSO. + - The same is not true in the account registration flows above—that is, during account + registration when a user reaches the `/finish-signup` or `/trial-initiation` page to set their + initial password, their account does not yet exist in the database, and will only be created + once they set an initial password. +- An existing user in a TDE org logs in after the org admin upgraded the user to a role that now + requires them to have/set their initial password +- An existing user logs in after their org admin offboarded the org from TDE, and the user must now + have/set their initial password

+ +**`ChangePassword`** + +Used in scenarios where a we simply want simply offer the user the ability to change their password: + +- User clicks an org email invite link an logs in with their password which does not meet the org's + policy requirements +- User logs in with password that does not meet the org's policy requirements +- User logs in after their password was reset via Account Recovery (and now they must change their + password)

+ +**`ChangePasswordWithOptionalUserKeyRotation`** + +Used in scenarios where we want to offer users the additional option of rotating their user key: + +- Account Settings (Web) - change password screen + +Note that the user key rotation itself does not happen on the `InputPasswordComponent`, but rather +on the parent component. The `InputPasswordComponent` simply emits a boolean value that indicates +whether or not the user key should be rotated.

+ +**`ChangePasswordDelegation`** + +Used in scenarios where one user changes the password for another user's account: + +- Emergency Access Takeover +- Account Recovery

### HTML - Form Fields -The `InputPasswordFlow` determines which form fields get displayed in the UI. - -**`InputPasswordFlow.SetInitialPasswordAccountRegistration`** and -**`InputPasswordFlow.SetInitialPasswordAuthedUser`** - -- Input: New password -- Input: Confirm new password -- Input: Hint -- Checkbox: Check for breaches - -**`InputPasswordFlow.ChangePassword`** - -Includes everything above, plus: - -- Input: Current password (as the first element in the UI) - -**`InputPasswordFlow.ChangePasswordWithOptionalUserKeyRotation`** - -Includes everything above, plus: - -- Checkbox: Rotate account encryption key (as the last element in the UI) +Click through the individual Stories in Storybook to see how the `InputPassswordFlow` determines +which form field UI elements get displayed.
### TypeScript - Credential Generation -- The `SetInitialPasswordAccountRegistration` and `SetInitialPasswordAuthedUser` flows involve a - user setting their password for the first time. Therefore on submit the component will only - generate new credentials (`newMasterKey`) and not current credentials (`currentMasterKey`). -- The `ChangePassword` and `ChangePasswordWithOptionalUserKeyRotation` flows both require the user - to enter a current password along with a new password. Therefore on submit the component will - generate current credentials (`currentMasterKey`) along with new credentials (`newMasterKey`). +- **`SetInitialPasswordAccountRegistration`** and **`SetInitialPasswordAuthedUser`** + - These flows involve a user setting their password for the first time. Therefore on submit the + component will only generate new credentials (`newMasterKey`) and not current credentials + (`currentMasterKey`).

+- **`ChangePassword`** and **`ChangePasswordWithOptionalUserKeyRotation`** + - These flows both require the user to enter a current password along with a new password. + Therefore on submit the component will generate current credentials (`currentMasterKey`) along + with new credentials (`newMasterKey`).

+- **`ChangePasswordDelegation`** + - This flow does not generate any credentials, but simply validates the new password and emits it + up to the parent.
@@ -114,32 +179,8 @@ credentials, but we need to keep them separate for the following reasons: - `SetInitialPasswordAccountRegistration` involves scenarios where we have no existing user, and **thus NO active account `userId`**: - - - Standard Account Registration - - Email Invite Account Registration - - Trial Initiation Account Registration - -
- - `SetInitialPasswordAuthedUser` involves scenarios where we do have an existing and authed user, and **thus an active account `userId`**: - - A "just-in-time" (JIT) provisioned user joins a master password (MP) encryption org and must set - their initial password - - A "just-in-time" (JIT) provisioned user joins a trusted device encryption (TDE) org with a - starting role that requires them to have/set their initial password - - A note on JIT provisioned user flows: - - Even though a JIT provisioned user is a brand-new user who was “just” created, we consider - them to be an “existing authed user” _from the perspective of the set-password flow_. This - is because at the time they set their initial password, their account already exists in the - database (before setting their password) and they have already authenticated via SSO. - - The same is not true in the account registration flows above—that is, during account - registration when a user reaches the `/finish-signup` or `/trial-initiation` page to set - their initial password, their account does not yet exist in the database, and will only be - created once they set an initial password. - - An existing user in a TDE org logs in after the org admin upgraded the user to a role that now - requires them to have/set their initial password - - An existing user logs in after their org admin offboarded the org from TDE, and the user must - now have/set their initial password The presence or absence of an active account `userId` is important because it determines how we get the correct `kdfConfig` prior to key generation: @@ -170,11 +211,6 @@ Form validators ensure that: - The new password and confirmed new password are the same - The new password and password hint are NOT the same -Additional submit logic validation ensures that: - -- The new password adheres to any enforced master password policy options (that were passed down - from the parent) -
## Submit Logic @@ -183,9 +219,10 @@ When the form is submitted, the `InputPasswordComponent` does the following in o 1. Verifies inputs: - Checks that the current password is correct (if it was required in the flow) - - Checks if the new password is found in a breach and warns the user if so (if the user selected - the checkbox) - - Checks that the new password meets any master password policy requirements enforced by an org + - Checks that the new password is not weak or found in any breaches (if the user selected the + checkbox) + - Checks that the new password adheres to any enforced master password policies that were + optionally passed down by the parent 2. Uses the form inputs to create cryptographic properties (`newMasterKey`, `newServerMasterKeyHash`, etc.) 3. Emits those cryptographic properties up to the parent (along with other values defined in @@ -209,6 +246,67 @@ export interface PasswordInputResult { } ``` +## Submitting From a Parent Dialog Component + +Some of our set/change password flows use dialogs, such as Emergency Access Takeover and Account +Recovery. These are covered by the `ChangePasswordDelegation` flow. Because dialogs have their own +buttons, we don't want to display an additional Submit button in the `InputPasswordComponent` when +embedded a dialog. + +Therefore we do the following: + +- The `InputPasswordComponent` hides the button in the UI and exposes its `submit()` method as a + public method. +- The parent dialog component can then access this method via `@ViewChild()`. +- When the user clicks the primary button on the parent dialog, we call the `submit()` method on the + `InputPasswordComponent`. + +```html + + + + + +
+ +
+ + + + + +
+``` + +```typescript +// emergency-access-takeover-dialog.component.ts + +export class EmergencyAccessTakeoverDialogComponent implements OnInit { + @ViewChild(InputPasswordComponent) + inputPasswordComponent: InputPasswordComponent; + + // ... + + handlePrimaryButtonClick = async () => { + await this.inputPasswordComponent.submit(); + }; + + async handlePasswordFormSubmit(passwordInputResult: PasswordInputResult) { + // ... run logic that handles the `PasswordInputResult` object emission + } +} +``` + +
+ # Example **`InputPasswordFlow.ChangePasswordWithOptionalUserKeyRotation`**