Skip to content

Conversation

@ryanbas21
Copy link
Contributor

@ryanbas21 ryanbas21 commented Apr 24, 2023

JIRA Ticket

https://bugster.forgerock.org/jira/browse/SDKS-2298

Description

make it so register accepts a parameter for registering a device name. An optional generic parameter that adds a device name to the registration step. This makes it so that ::${devicename} is concated to the device string that is made from the outcome.

Type of Change

Please Delete options that are not relevant

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • This change requires a documentation update

How Has This Been Tested?

See the e2e example, which uses stoyans tenant

  const url = new URL(window.location.href);
  const amUrl =
    url.searchParams.get('amUrl') || 'https://openam-forgerrock-sdksteanant.forgeblocks.com/am/';
  const realmPath = url.searchParams.get('realmPath') || 'alpha';
  const un = url.searchParams.get('un') || 'ryan';
  const pw = url.searchParams.get('pw') || 'Password1!';
  const tree = url.searchParams.get('tree') || 'WebAuthn-Registration';

Click the device registration button and then go through the flow there. You should see the hidden callback have the outcome value with DeviceName (as passed in) concated to the end.

The name can be very long and cut off

Screenshot 2023-04-25 at 1 18 17 PM

Definition of Done

Check all that apply

  • Acceptance criteria is met.
  • All tasks listed in the user story have been completed.
  • Coded to standards.
  • Code peer-reviewed.
  • Ensure backward compatibility (special attention).
  • API reference docs is updated.
  • Unit tests are written.
  • Integration tests are written.
  • e2e tests are written.
  • CI build passing on the feature branch.
  • Functional spec is written/updated
  • contains example code snippets.
  • Change log updated.
  • Documentation story is created and tracked.
  • UI is completed or ticket is created.
  • Demo to PO and team.
  • Tech debts and remaining tasks are tracked in separated ticket(s).

Documentation

  • Acceptance criteria met
  • Spell-check run
  • Peer reviewed
  • Proofread

@ryanbas21 ryanbas21 temporarily deployed to Preview April 24, 2023 19:33 — with GitHub Actions Inactive
@github-actions
Copy link
Contributor

github-actions bot commented Apr 24, 2023

"executor": "@nrwl/rollup:rollup",
"options": {
"compiler": "babel",
"compiler": "tsc",
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so typechecking happens on build, was an oversight by me.

@ryanbas21 ryanbas21 temporarily deployed to Preview April 24, 2023 19:51 — with GitHub Actions Inactive
@nx-cloud
Copy link

nx-cloud bot commented Apr 24, 2023

☁️ Nx Cloud Report

CI is running/has finished running commands for commit f845505. As they complete they will appear below. Click to see the status, the terminal output, and the build insights.

📂 See all runs for this branch


✅ Successfully ran 5 targets

Sent with 💌 from NxCloud.

import { parseWebAuthnAuthenticateText, parseWebAuthnRegisterText } from './script-parser';

// <clientdata>::<attestation>::<publickeyCredential>::<DeviceName>
type DeviceName<
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a type that can create a Device Name if given a name or not

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like the strictness of this type, but the name feels a bit misleading.

PubKeyCred extends PublicKeyCredential,
Name = '',
> = Name extends infer P extends string
? `${ClientId}::${Attestation}::${PubKeyCred['id']}${P extends '' ? '' : `::${P}`}`
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

realistically, i thought a simpler type could be used, i have no idea why i couldn't use a simpler type, it only worked when I went this route.

}

hiddenCallback.setInputValue(outcome);
hiddenCallback.setInputValue(deviceName ? `${outcome}::${deviceName}` : outcome);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hypothetically, we could give hiddenCallback a generic that defaults to unknown and then we can provide that here for more type inference and passing.


let stringOutput = `${clientDataJSON}::${authenticatorData}::${signature}::${credential.id}`;
let stringOutput =
`${clientDataJSON}::${authenticatorData}::${signature}::${credential.id}` as DeviceName<
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Had to force this type, theres probably a way to create a string builder that outputs as the type though that may fit better.

string,
AttestationType,
PublicKeyCredential,
typeof userHandle
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suppose this will always be string, but if userHandle is ever a more strict type then we could leverage that here.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

userHandle is just a username, so it can be any kind of string. This is used for supporting the "usernameless" flow where the username is stored on the WebAuthn device.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right but one could pass “username” and in typescript 5 we could leverage a const generic which would make the type “username” and not string so it could be used more strictly

"target": "ES2020"
},
"include": ["**/*.ts"],
"include": ["**/*.ts", "jest.setup.js"],
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I addedt his when I was trying to find ways to test this with jest, but I can remove it.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably should remove it then, if it's not needed.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

removed

<body>
<!-- script src="/_polyfills/fast-text-encoder.js"></script -->
<button class="login-btn">Login</button>
<button class="device-registration">Device Registration</button>
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is just for that manual test I wrote, has no affect on the automation

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, I was wondering why the additional flow was added. There's currently no automation around WebAuthn; everything is manually tested. So, nothing should prevent you from adding your feature to the existing flow, rather than create an entirely new flow.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I only added it because the only difference is that the previous flow didn't add a device name, but i could just add a device name and remvoe this i think if preferred.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The main reason for this flow, is that the tenant i used had a different tree, so I used stoyans tenant and the flow itself requires certs that run without errors.

So my testing was done in a dfiferent env and couldn't use the mock server itself.

Copy link
Contributor

@cerebrl cerebrl left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks good overall. A few additional comments:

  • Can you fill out the PR description template?
  • Provide screenshots of the results from testing this new feature from Platform Admin (showing full end-to-end testing)
  • Rework the name of the new type
  • I don't think you need to create a whole new flow in the autoscript.ts, but let me know if I'm missing something

console.log('Handle WebAuthn Registration');
try {
step = await forgerock.FRWebAuthn.register<'mydevice'>(step, 'mydevice');
// ensure the step here has the 'mydevice' name at the end of the value. (outcome)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this a TODO comment?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, this was instructions for when you get to this step, you can ensure the callback has the value with mydevice at the end since it concates with a stringifed object its messy.

see here:
Screenshot 2023-04-25 at 1 18 17 PM

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, okay. Rather than this comment instructing the manual tester to inspect the step in the console, can we just have a condition in the code to check this for us, similar to the other conditions that are ensuring things are working properly? If mydevice is not present, let's just throw an error like how we handle other issues.

<body>
<!-- script src="/_polyfills/fast-text-encoder.js"></script -->
<button class="login-btn">Login</button>
<button class="device-registration">Device Registration</button>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, I was wondering why the additional flow was added. There's currently no automation around WebAuthn; everything is manually tested. So, nothing should prevent you from adding your feature to the existing flow, rather than create an entirely new flow.

const { hiddenCallback, metadataCallback, textOutputCallback } = this.getCallbacks(step);
if (hiddenCallback && (metadataCallback || textOutputCallback)) {
let outcome: string;
let outcome: DeviceName<string, AttestationType, PublicKeyCredential>;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This type reads a bit odd for me. Should the type name be something more like OutcomeWithName, rather than DeviceName?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

import { parseWebAuthnAuthenticateText, parseWebAuthnRegisterText } from './script-parser';

// <clientdata>::<attestation>::<publickeyCredential>::<DeviceName>
type DeviceName<
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like the strictness of this type, but the name feels a bit misleading.

string,
AttestationType,
PublicKeyCredential,
typeof userHandle
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

userHandle is just a username, so it can be any kind of string. This is used for supporting the "usernameless" flow where the username is stored on the WebAuthn device.

"target": "ES2020"
},
"include": ["**/*.ts"],
"include": ["**/*.ts", "jest.setup.js"],
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably should remove it then, if it's not needed.

@ryanbas21 ryanbas21 temporarily deployed to Preview April 25, 2023 19:36 — with GitHub Actions Inactive
@ryanbas21 ryanbas21 temporarily deployed to Preview April 25, 2023 21:26 — with GitHub Actions Inactive
@ryanbas21 ryanbas21 temporarily deployed to Preview April 25, 2023 21:57 — with GitHub Actions Inactive
@ryanbas21 ryanbas21 temporarily deployed to Preview April 26, 2023 21:39 — with GitHub Actions Inactive
@ryanbas21 ryanbas21 temporarily deployed to Preview April 26, 2023 21:43 — with GitHub Actions Inactive
@ryanbas21 ryanbas21 temporarily deployed to Preview April 26, 2023 21:44 — with GitHub Actions Inactive
make it so `register` accepts a parameter for registering a device name
@ryanbas21 ryanbas21 temporarily deployed to Preview April 26, 2023 22:16 — with GitHub Actions Inactive
Copy link
Contributor

@cerebrl cerebrl left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

@ryanbas21 ryanbas21 merged commit b99946a into develop Apr 26, 2023
@ryanbas21 ryanbas21 deleted the webauthn branch August 2, 2024 14:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Development

Successfully merging this pull request may close these issues.

3 participants