Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Strawman of an integration between WebAuthn and Credential Management. #384

Merged
merged 31 commits into from Apr 19, 2017

Conversation

mikewest
Copy link
Member

@battre: I took a different tack in this patch, leveraging most of the work you've already done.

The main distinction between what we talked about yesterday and what I ended up with here is the value of the ScopedCredential's id parameter. I no longer agree with myself from yesterday; it doesn't make much sense to treat this as the Account's ID. I think we should keep the existing relationship between the credential's ID and the "credential identifier" that the authenticator produces. I've just stored that ArrayBuffer as an internal property, and turned the id getter into a base64url encoded version of that buffer.

Also note that this set of patches focuses on getAssertion(), but doesn't make much change to makeCredential() (other than the rename). I'd still like to turn that into a dictionary, but this is already a big patch, so...

WDYT?

This is a temporary step to get rid of WebAuthentication, and pave the way
to move to 'get()' in the next patch.
In order to align with CredentialsContainer::get(), merge the challenge into 'AssertionOptions'
and rename 'AssertionOptions' to 'ScopedCredentialRequestOptions'.
This relies on some things that aren't official yet, in particular the
[[Retrieve]](options, mediation) internal method defined at
https://w3c.github.io/webappsec-credential-management/base.html#dom-credential-retrieve-slot.
But I think it all works. :)
@mikewest
Copy link
Member Author

Whoops! I meant to make this a PR against @battre's fork of this repo, as there are still some open issues to work out. Ah well. :(

So, hello, webauthn! This is a slightly-more-fleshed-out strawman than we discussed on the call last week, but the broad strokes are the same.

index.bs Outdated
@@ -92,8 +89,11 @@ is [=Registration=], where a [=scoped credential=] is created on an [=authentica
with the present user's account (the account may already exist or may be created at this time). The second is
[=Authentication=], where the [=[RP]=] is presented with an <em>[=Authentication Assertion=]</em> proving the presence
and consent of the user who registered the [=scoped credential=]. Functionally, the [=Web Authentication API=] comprises
two methods (along with associated data structures): {{makeCredential()}} and {{getAssertion()}}. The former is used
during [=Registration=] and the latter during [=Authentication=].
a {{ScopedCredential}} which extends the Credential Management API, and infrastructure which allows those credentials to be
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit: Should add a normative reference link to the CM API.

Copy link
Member Author

Choose a reason for hiding this comment

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

Added in b1e87ca.

index.bs Outdated
@@ -186,8 +186,7 @@ below and in [[#index-defined-elsewhere]].

: HTML
:: The concepts of [=relevant settings object=], [=origin=],
[=opaque origin=], [=is a registrable domain suffix of or is equal to=], and the {{Navigator}} interface are
defined in [[!HTML52]].
[=opaque origin=], [=is a registrable domain suffix of or is equal to=].
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit: missed the ending of the sentence.

Copy link
Member Author

Choose a reason for hiding this comment

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

Fixed in b1e87ca

index.bs Outdated
:: This method allows a developer to request the User Agent to create a new credential, and persist it to the underlying
platform, which may involve data storage managed by the browser or the OS. The user agent will prompt the user to
approve this operation. On success, the promise will be resolved with a {{ScopedCredential}} which contains an
{{AuthenticatorAttestationResponse}} object. Implementation details are found in [#createCredential].
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit: missing one set of brackets around #createCredential

Copy link
Member Author

Choose a reason for hiding this comment

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

Fixed in b1e87ca.

index.bs Outdated

<xmp class="idl">
[SecureContext]
interface WebAuthentication {
Promise<ScopedCredentialInfo> makeCredential(
interface ScopedCredential : Credential {
Copy link
Contributor

Choose a reason for hiding this comment

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

Does this mean that ScopedCredential implements Transferable as well? If so, do we need to define a structured clone algorithm for it? If not, is CM API going to drop the requirement around implementing Transferable?

Copy link
Contributor

Choose a reason for hiding this comment

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

hm, https://w3c.github.io/webappsec-credential-management/base.html seems to have dropped "Transferable"

fyi/fwiw, part of our webauthn's rationale for not declaring "transferable" is that making credentials transferable means that they can be postMessage'd to another origin (as we understand it) and that seemed to violate our security & privacy requirements.

Copy link
Member Author

Choose a reason for hiding this comment

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

Transferable basically means that when the object is postMessaged, it doesn't copy the data, but moves it out of your window. We don't need that behavior for any of the current credential types, and if y'all don't need it either, then I'm happy to drop Transferable from the CM spec.

That said, there's nothing stopping a malicious developer from copying or serializing the ScopedCredential object and using postMessage() to transfer that data to a different window. What's the threat you'd like to defend against?

Copy link
Contributor

Choose a reason for hiding this comment

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

Thanks @equalsJeffH, I had been reading the ED which differs from the base.html version.

Copy link
Member Author

Choose a reason for hiding this comment

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

*cough* To make things more confusing (but hopefully less confusing in the long term!), I've now folded those two documents back into https://w3c.github.io/webappsec-credential-management/. :)


## <dfn interface>WebAuthentication</dfn> Interface ## {#iface-credential}
The {{ScopedCredential}} interface inherits from {{Credential}} [[!CREDENTIAL-MANAGEMENT-1]], and contains the attributes that
are returned to the caller when a new credential is created, or a new assertion is requested.
Copy link
Contributor

Choose a reason for hiding this comment

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

We should probably add some text here about what a ScopedCredential object actually represents. One of the challenges I had when reading this was keeping in mind that "credential" as used in this spec is not the same as "Credential" which is the base interface of the same name. AIUI we a page might have multiple ScopedCredential objects representing a single "credential" on an underlying authenticator. Can we find better words to overcome this semantic confusion?

This is less of an issue with password credentials, because every copy of a password is a valid credential. But in the WebAuthn case this is more salient because there is only a single thing underlying all these objects, and the objects are essentially invalidated if I, for example, pull my USB authenticator out of the port.

Copy link
Member Author

Choose a reason for hiding this comment

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

I agree that there's a lot of prose that needs rethinking. This PR really only concentrates on the mechanics right now, and one explicit goal is to work through y'all's thoughts on the confusing bits that remain unaddressed. :)

index.bs Outdated
: <dfn method>\[[Retrieve]](options, mediation)</dfn>
:: The {{ScopedCredential}} [=interface object=] defines this internal method to override {{Credential}}'s implementation,
which will enable support for assertion generation through {{CredentialsContainer/get()}}. Implementation details are
found in [[#getAssertion]].
Copy link
Contributor

Choose a reason for hiding this comment

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

Perhaps it's my lack of knowledge of WebIDL, but I have many questions about this.

How does this actually show up in the author's code? We're saying here that a method in an internal slot of the ScopedCredential object overrides a method of the CredentialsContainer interface. Does this then constitute a monkey patch on section 4.1.1 of Credentials Management? Maybe this should be broken out of here and into a real extension point?

Copy link
Member Author

Choose a reason for hiding this comment

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

How does this actually show up in the author's code?

It doesn't. The [[...]] syntax is what the ECMAScript spec uses for internal properties... slots and methods that exist on an object for explanation purposes, but don't have IDL bindings).

We're saying here that a method in an internal slot of the ScopedCredential object overrides a method of the CredentialsContainer interface.

No, sorry for the confusion: here, we're overriding Credential's implementation of [[Retreive]]. [[Retrieve]] is used by CredentialsContainer/get(), but isn't monkeying around with CredentialsContainer's implementation. I'll walk through the new flow below:

Does this then constitute a monkey patch on section 4.1.1 of Credentials Management?

In https://w3c.github.io/webappsec-credential-management/base.html, I'm fiddling around with how get() is wired up to specific kinds of credential objects. The existing document is pretty hand-wavey about how it knows that get({ 'password': true }) is a request that operates on PasswordCredential objects. That new document attempts to be a little more rigorous. I'll try to spell it out briefly here:

  1. All Credential interface objects have an internal (e.g. not exposed to the web) implementation of [[Retrieve]](options, mediation) (https://w3c.github.io/webappsec-credential-management/base.html#credential-internal-methods).

  2. During get(), we walk through all the interface objects that derive from Credential directly or indirectly (step 5.1 of https://w3c.github.io/webappsec-credential-management/base.html#abstract-opdef-request-a-credential), and examine their [[type]] slot's value. If that value is the same as one of the keys in the dictionary that we passed into get(), then we'll grab the interface object's [[Retrieve]] method.

  3. If, after walking through all such objects, we've only gotten one [[Retrieve]] method, then we'll execute it and return the resulting Credential to the developer.

    If we got more than one hit (e.g. the developer passed in { 'password': true, 'scoped': { ... } }), then we'll error out.

It might be easier to explain this on a call. It's a bit convoluted, but I do think it's more clearly explained than the last attempt, at least from a mechanical perspective of what the browser would actually do. :)

index.bs Outdated

: <dfn method>create(accountInformation, cryptoParameters, attestationChallenge, options)</dfn>
:: This method allows a developer to request the User Agent to create a new credential, and persist it to the underlying
platform, which may involve data storage managed by the browser or the OS. The user agent will prompt the user to
Copy link
Contributor

Choose a reason for hiding this comment

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

Re: "persist it to the underlying platform..." - I think it would be more accurate and consistent to say "persist it to an authenticator" which may be an external device or built into the client. I think referring to "data storage" is misleading in either case as it implies general-purpose data stores.

Copy link
Member Author

Choose a reason for hiding this comment

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

I borrowed this text from the current section 4.1.1: https://w3c.github.io/webauthn/#makeCredential. I'm happy to change it to something more accurate, though! I'll do that in a distinct patch.

Copy link
Member Author

Choose a reason for hiding this comment

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

Changed in b1e87ca. The bit about prompting might also be something to address, as it's not clear to me whether that's actually a requirement imposed by this spec.

@vijaybh
Copy link
Contributor

vijaybh commented Mar 16, 2017

I have to run now, so I just published a half-done review. I will go through the rest of the PR later (likely this weekend) but please feel free to respond to these comments now if you'd like.

@mikewest
Copy link
Member Author

I appreciate you taking a look, @vijaybh. I've answered your comments inline, and I'll clean up the nits you've noted later today. Good eye!

extension identifier, and the value MUST be the [=client argument=].

<pre class="example" highlight="js">
var assertionPromise = credentials.getAssertion(..., /* extensions */ {
"webauthnExample_foobar": 42
var assertionPromise = navigator.credentials.get({
Copy link

Choose a reason for hiding this comment

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

nit: navigator.credentials.get({"scoped": {

also below...

Copy link
Member Author

Choose a reason for hiding this comment

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

Taken care of in c48c70b.

index.bs Outdated
data contained in the object's {{ScopedCredential/[[identifier]]}} slot.

: {{ScopedCredential/rawID}}
:: This attribute returns the {{ArrayBuffer}} contained in the {{ScopedCredential/[[identifier]]}} internal slot.
Copy link
Member

Choose a reason for hiding this comment

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

Note that ArrayBuffers are mutable, so folks will be able to change the value of that internal slot. Web Bluetooth invented a "read only ArrayBuffer" variant to handle this, but I don't think we've implemented the read-only aspect yet.

Copy link
Member Author

@mikewest mikewest Mar 22, 2017

Choose a reason for hiding this comment

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

This is equally a concern in the status quo API, right? readonly attribute doesn't prevent the contents of the ArrayBuffer stored in ScopedCredential/id from being modified.

If we need that kind of guarantee, then we probably need to chat with folks like @tobie, @bzbarsky, and @domenic about WebIDL and ECMAScript bindings.

Copy link
Member

Choose a reason for hiding this comment

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

Yep.

Copy link
Member

Choose a reason for hiding this comment

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

Does ES even let you freeze Typed Arrays?

Choose a reason for hiding this comment

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

Typed arrays are "Integer Indexed Exotic Objects". Per https://tc39.github.io/ecma262/#sec-integer-indexed-exotic-objects that means their integer-named properties are writable and non-configurable, so you can't make them non-writable.

But that's a red herring anyway, because you can just create a new typed array of your own using the same backing arraybuffer.

If you actually perform a set on a typed array, you end up in https://tc39.github.io/ecma262/#sec-integer-indexed-exotic-objects-set-p-v-receiver and thence in https://tc39.github.io/ecma262/#sec-integerindexedelementset which will do some validation and call https://tc39.github.io/ecma262/#sec-setvalueinbuffer

There are no provisions for readonlyness of arraybuffers and therefore no provisions for readonlyness of typed arrays. The bluetooth spec is basically unimplementable as written.

Oh, and adding such provisions is likely to cause prohibitive performance regressions for code that uses typed arrays. Which means JS engine implementors will push back very hard on attempts to add something like this. They have before.

The right way to expose binary data that you don't want mutated is to expose a copy.

Copy link
Member Author

Choose a reason for hiding this comment

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

I agree with @bzbarsky. I'm also not sure I understand why it's necessary to freeze these buffers in the first place, as they're all already munged copies of things passed into other methods. I haven't looked at the bluetooth usage, but it's not clear to me why you need read-onlyness there either. shrug

Copy link
Member

Choose a reason for hiding this comment

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

If a user mutates the ArrayBuffer returned by rawId, does that change the value returned by id? If so (which is what the spec implies to me right now), then cred.id !== cred.id. If not, does the result of id reflect the initial value of [[identifier]] or the value at the point where id was first retrieved? I think we wind up needing to store both values eagerly and separately.

Copy link
Member Author

Choose a reason for hiding this comment

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

If a user mutates the ArrayBuffer returned by rawId, does that change the value returned by id? If so (which is what the spec implies to me right now), then cred.id !== cred.id.

That's how things are written now, yes. That seems reasonable, given that the ID would indeed change if the underlying data changed. If that seems untenable, then we could make rawID return a copy of the underlying buffer. That seems expensive, but maybe it's worthwhile?

A simpler alternative would be to drop the internal slot entirely, and just store the base64url encoded data. It isn't actually clear to me from our various conversations whether the raw buffer is necessary. I only introduced rawID to maintain some portion of the status quo while migrating over to derive from Credential.

Copy link
Member

Choose a reason for hiding this comment

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

I think dropping the internal slot makes sense here. It's also not clear to me if we need to keep the ArrayBuffer version.

index.bs Outdated
2. Let |value| be a new {{ScopedCredential}} associated with |global| whose fields are:

: {{ScopedCredential/[[identifier]]}}
:: A new {{ArrayBuffer}} containing the bytes of the credential ID returned from the successful
Copy link
Member

Choose a reason for hiding this comment

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

Keep the "created using |global|'s [=%ArrayBuffer%=]" phrase.

Copy link
Member Author

Choose a reason for hiding this comment

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

Thanks! Fixed in fedcced.

index.bs Outdated

## Information about Scoped Credential (interface <dfn interface>ScopedCredentialInfo</dfn>) ## {#iface-credentialInfo}
The {{AuthenticatorResponse}} interface and its derieved interfaces represent the data
Copy link
Member

Choose a reason for hiding this comment

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

I think you're missing the end of a sentence here.

Copy link
Member Author

Choose a reason for hiding this comment

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

Thanks! Fixed in fedcced.

index.bs Outdated
<dl dfn-for="AuthenticatorResponse">
: <dfn attribute>clientDataJSON</dfn>
:: This attribute contains a representation of the data sent from the client to the authenticator in order to generate
a given response. The {{AuthenticatorAttestationResponse}} and {{AuthenticatorAssertionResponse}}
Copy link
Member

Choose a reason for hiding this comment

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

Another truncated sentence here.

Copy link
Member Author

Choose a reason for hiding this comment

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

Thanks! Fixed in fedcced.

Copy link
Member Author

@mikewest mikewest left a comment

Choose a reason for hiding this comment

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

I spent this morning merging in the changes from #397, #398, and #399, and addressing @equalsJeffH's feedback. I need to take another pass to make sure that the state we've ended up in is sane, but it would be helpful if other folks skimmed the result as well, as those three patches introduced a lot of churn. :)

index.bs Outdated
data contained in the object's {{ScopedCredential/[[identifier]]}} slot.

: {{ScopedCredential/rawID}}
:: This attribute returns the {{ArrayBuffer}} contained in the {{ScopedCredential/[[identifier]]}} internal slot.
Copy link
Member Author

Choose a reason for hiding this comment

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

If a user mutates the ArrayBuffer returned by rawId, does that change the value returned by id? If so (which is what the spec implies to me right now), then cred.id !== cred.id.

That's how things are written now, yes. That seems reasonable, given that the ID would indeed change if the underlying data changed. If that seems untenable, then we could make rawID return a copy of the underlying buffer. That seems expensive, but maybe it's worthwhile?

A simpler alternative would be to drop the internal slot entirely, and just store the base64url encoded data. It isn't actually clear to me from our various conversations whether the raw buffer is necessary. I only introduced rawID to maintain some portion of the status quo while migrating over to derive from Credential.

index.bs Outdated
{{CredentialsContainer/get()}}, and this attribute's value will be an {{AuthenticatorAssertionResponse}}.

: <dfn>\[[type]]</dfn>
:: The {{ScopedCredential}} [=interface object=]'s {{Credential/[[type]]}} slot's value is the string "`scoped`".
Copy link
Member Author

Choose a reason for hiding this comment

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

It seems implied, but I'm happy to imply less if it's helpful.

@@ -651,8 +716,8 @@ When this method is invoked, the user agent MUST execute the following algorithm

1. [=set/Append=] |authenticator| to |issuedRequests|.

1. Let |promise| be [=a new Promise=]. Return |promise| and start a timer for |adjustedTimeout| milliseconds. Then execute the
following steps [=in parallel=]. The [=task source=] for these [=tasks=] is the [=dom manipulation task source=].
1. Start a timer for |adjustedTimeout| milliseconds. Then execute the following steps [=in parallel=]. The [=task source=] for
Copy link
Member Author

Choose a reason for hiding this comment

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

create(), above, directly implements an IDL API, so it returns a promise directly. In this section, on the other hand, we're implementing a function called by https://w3c.github.io/webappsec-credential-management/#algorithm-request. We don't need to manage the promise bits, we return a result to our caller, and our caller uses that result to resolve the promise.

(Note that create() will move to a similar model once w3c/webappsec-credential-management#72 lands)

</dd>
</dl>

1. [=Reject=] |promise| with a {{DOMException}} whose name is "{{NotAllowedError}}".
1. Return a {{DOMException}} whose name is "{{NotAllowedError}}".
Copy link
Member Author

Choose a reason for hiding this comment

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

See the explanation above.

index.bs Outdated
## Information about Scoped Credential (interface <dfn interface>ScopedCredentialInfo</dfn>) ## {#iface-credentialInfo}
The {{AuthenticatorResponse}} interface represents the data returned from an [=authenticator=] in response to a client's
request. This base interface contains common attributes for all response types, while derived interfaces like
{{AuthenticatorAttestationResponse}} and {{AuthenticatorAssertionResponse}} add attribute specific to a particular kind
Copy link
Member Author

Choose a reason for hiding this comment

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

Skipping these comments, as we reworded/reworked this section in #397.

index.bs Outdated
@@ -806,8 +914,7 @@ authorizing an authenticator with which to complete the operation.
complete. This is treated as a hint, and may be overridden by the platform.

- The <dfn>rpId</dfn> parameter explicitly specifies the RP ID that the credential should be associated with. If it is
omitted, the RP ID will be set to the [=origin=] specified by the {{WebAuthentication}} object's [=relevant settings
object=].
omitted, the RP ID will be set to the [=environment settings object/origin=] specified by the [=current settings object=].
Copy link
Member Author

Choose a reason for hiding this comment

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

(Fixed in #397)

index.bs Outdated

- The optional <dfn>timeout</dfn> parameter specifies a time, in milliseconds, that the caller is willing to wait for the
call to complete. This is treated as a hint, and may be overridden by the platform.

- The optional <dfn>rpId</dfn> parameter specifies the rpId claimed by the caller. If it is omitted, it will be assumed to
be equal to the [=origin=] specified by the {{WebAuthentication}} object's [=relevant settings object=].
be equal to the [=environment settings object/origin=] specified by the [=current settings object=].
Copy link
Member Author

Choose a reason for hiding this comment

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

Fixed in #397.

@domenic
Copy link
Contributor

domenic commented Apr 18, 2017

Drive-by comment: it should be rawId, not rawID: https://w3ctag.github.io/design-principles/#casing-rules

@AngeloKai
Copy link
Contributor

I looked through the PR and haven't found problem with it.

index.bs Outdated
object's [=relevant settings object=]. This default can be overridden by the caller subject to certain restrictions, as
specified in [[#makeCredential]] and [[#getAssertion]].
them. By default, the RP ID for a WebAuthn operation is set to the [=environment settings object/origin=] specified by the
[=current settings object=]. This default can be overridden by the caller subject to certain restrictions, as
Copy link
Contributor

Choose a reason for hiding this comment

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

wrt [=current settings object=] -- given the language a ways below of:

Let |callerOrigin| be the [=environment settings object/origin=] specified by this {{ScopedCredential}} object's [=relevant settings object=].

..is using [=current settings object=] here correct?

Copy link
Member Author

Choose a reason for hiding this comment

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

Probably not. Fixing.

@@ -651,8 +716,8 @@ When this method is invoked, the user agent MUST execute the following algorithm

1. [=set/Append=] |authenticator| to |issuedRequests|.

1. Let |promise| be [=a new Promise=]. Return |promise| and start a timer for |adjustedTimeout| milliseconds. Then execute the
following steps [=in parallel=]. The [=task source=] for these [=tasks=] is the [=dom manipulation task source=].
1. Start a timer for |adjustedTimeout| milliseconds. Then execute the following steps [=in parallel=]. The [=task source=] for
Copy link
Contributor

Choose a reason for hiding this comment

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

alrightie -- i wonder whether that rationale ought to be captured somewhere in these spec(s)?

</dd>
</dl>

1. [=Reject=] |promise| with a {{DOMException}} whose name is "{{NotAllowedError}}".
1. Return a {{DOMException}} whose name is "{{NotAllowedError}}".
Copy link
Contributor

Choose a reason for hiding this comment

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

ACK

index.bs Outdated
@@ -870,7 +914,7 @@ use a [=roaming authenticator=] which was originally registered with the [RP] us

: <dfn>attachment</dfn>
:: This member contains authenticator attachment descriptions, which are used as an additional constraint on which
authenticators are eligible to participate in a [[#makeCredential]] or [[#getAssertion]] operation. See [[#attachment]]
authenticators are eligible to participate in a {{ScopedCredential/create()}} operation. See [[#attachment]]
Copy link
Contributor

Choose a reason for hiding this comment

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

[=attachment=] is not used in get() ?

Copy link
Member Author

Choose a reason for hiding this comment

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

It's only passed into a create() operation, but I suppose it is used in the backend decisions for get()? Do we need to pass it into get() as well?

index.bs Outdated
the {{makeCredential()}} or {{getAssertion()}} method. It mirrors the fields of the {{ScopedCredential}} object returned by
these methods.
the {{create()}} or {{CredentialsContainer/get()}} methods. It mirrors the fields of the {{ScopedCredential}} object returned by
latter method.
Copy link
Contributor

Choose a reason for hiding this comment

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

s/latter method/the latter methods/

index.bs Outdated
@@ -806,8 +914,7 @@ authorizing an authenticator with which to complete the operation.
complete. This is treated as a hint, and may be overridden by the platform.

- The <dfn>rpId</dfn> parameter explicitly specifies the RP ID that the credential should be associated with. If it is
omitted, the RP ID will be set to the [=origin=] specified by the {{WebAuthentication}} object's [=relevant settings
object=].
omitted, the RP ID will be set to the [=environment settings object/origin=] specified by the [=current settings object=].
Copy link
Contributor

Choose a reason for hiding this comment

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

ACK

Copy link
Contributor

@equalsJeffH equalsJeffH 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 nominally OK given our decision on call last Fri 12-Apr-2017 (https://www.w3.org/2017/04/14-webauthn-minutes.html) to "merging in, in order to get the namespaces nailed down, and deal with problems afterwards". Thanks for addressing my comments. I have a couple/few additional ones above.

@equalsJeffH
Copy link
Contributor

equalsJeffH commented Apr 18, 2017

I've re-reviewed and changed my "changes requested" to "approved" given our decision on call last Fri 12-Apr-2017 (https://www.w3.org/2017/04/14-webauthn-minutes.html) to "merging in, in order to get the namespaces nailed down, and deal with problems afterwards".

[ i added this comment because presently "reviews" are not cc'd to the mailing list :-/ ]

@mikewest
Copy link
Member Author

w3c/webappsec-credential-management#72 added a create() method to CredentialsContainer for asynchronous creation of all credential types: 2335da4 shifts this patch to use that method rather than a static method on ScopedCredential, which I think will address one of @leshi's earlier concerns.

I'll address @equalsJeffH's other feedback shortly.

{{WebAuthentication/makeCredential(options)/options}}.{{MakeCredentialOptions/user}} passed to {{makeCredential()}}, by
associating it with the credential ID and credential public key contained in |authData|'s [=attestation data=], as
{{ScopedCredential/[[Create]](options)/options}}.{{MakeCredentialOptions/user}} passed to {{CredentialsContainer/create()}},
by associating it with the credential ID and credential public key contained in |authData|'s [=attestation data=], as
Copy link
Contributor

Choose a reason for hiding this comment

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

After the CM API merge, the implication of the current text is that the RP should take the credential ID directly from the attestation data, and ignore the id in the credential object itself. This seems like the right thing to do and actually a security measure. Should we make this explicit in the text here?

Copy link
Member Author

Choose a reason for hiding this comment

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

They should be the same, shouldn't they? I suppose there's additional confidence that the signed attestation data is more trustworthy...

Copy link
Contributor

Choose a reason for hiding this comment

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

RP should take the credential ID directly from the attestation data, and ignore the id in the credential object itself. This seems like the right thing to do...

agreed.

...and actually a security measure. Should we make this explicit in the text here?

I think so, and perhaps discussed in a sec-cons section.

index.bs Outdated
The <dfn for="ScopedCredential" method>\[[DiscoverFromExternalSource]](options)</dfn> method is used to discover and use an
existing scoped credential, with the user's consent. The script optionally specifies some criteria to indicate what credentials
are acceptable to it. The user agent and/or platform locates credentials matching the specified criteria, and guides the user
to pick one that the script should be allowed to use. The user may choose not to provide a credential even if one is present,
Copy link
Contributor

Choose a reason for hiding this comment

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

s/should be allowed/will be allowed/ ?

index.bs Outdated
imageURL: "https://pics.acme.com/00/p/aBjjjpqPb.png"
};
var scoped = {
challenge: new TextEncoded().encode("climb a mountain"),
Copy link
Contributor

Choose a reason for hiding this comment

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

I have angst wrt this bogus client-side non-random setting of challenge (see #404) -- perhaps we should change it to (if I have it correct)..

var challenge = Uint8Array.from(window.atob("PGifxAoBwCkWkm4b1CiIl5otCphiIh6MijdjbWFjomA="), c=>c.charCodeAt(0))

for now as we await #404 to be decided?

Copy link
Member Author

Choose a reason for hiding this comment

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

Sure (although that's hideous). ;)

@equalsJeffH
Copy link
Contributor

the new changes in the latest commits today look overall ok to me -- thx @mikewest -- i did make a couple detail-level comments.

@mikewest
Copy link
Member Author

@equalsJeffH: a042dd9 should address your two nits.

When we resolve #404, we'll certainly want to update the other challenge examples... https://w3c.github.io/webauthn/#example-33d07a93 in particular. But let's address those separately. :)

@equalsJeffH
Copy link
Contributor

@mikewest thanks for your patience & perseverance. will merge forthwith.

also, closes #249, improves #404

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet