Re: PR #384 CredMan Integration

Hey Alexei! Thanks for your feedback, I'm glad we're continuing the
conversation. Apologies for the ridiculous length, but it's midnight, my
brain is shutting down, and I'm giving up on making this shorter or more
coherent. :P

On Tue, Apr 11, 2017 at 6:05 PM, Alexei Czeskis <aczeskis@google.com> wrote:

> I'm all for getting the spec done fast, for getting implementations out
> fast, and for making the world a better place faster.  If we want to speed
> things up, I'm not convinced that the PR as it is right now is the right
> move.  I'm not simply arguing for making fast progress and accepting a
> messy API landscape in return.  I'm arguing for not venturing into the
> unknown to find the perfect -- in effect passing on the known-good.
>

I appreciate the time and consideration y'all are giving the proposal I put
forward in #384. I agree wholeheartedly with the admonition against putting
the perfect ahead of the good, and while I hope you'll accept a little more
discussion (and, unfortunately, probably a few long emails), I don't want
to hold you up unreasonably.

That said, I'd suggest that "the unknown" isn't as scary and dark as it might
look. Chrome is shipping the credential management API, developers are
using it today, and building up expectations about its use that I think we
would be well-served to consider and align with. You're entirely correct to
suggest that there are interesting questions to consider, but, in my
opinion, they're managable in a timeframe that I hope y'all can support.


> I believe that in its current form, the merge will cause questions that
> will take a while to iron out.  I would suggest an alternate approach: hold
> off on the merge until the proposal does not have as many unknowns.  Maybe
> that means waiting until version 2.
>

I agree that merging #384 right now would be a bad idea, given the
sincere objections
you and Dirk have raised. We should continue conversations like this one to
make sure we're on the same page regarding the concepts we're trying to
align.


> In my opinion, the big reason to be hesitant about this merge is that it
> takes us down the path of one single .makeAuthFactor() and one single
> .getAuthFactor() methods.
>

I suspect you won't be shocked to learn that I think this is a big reason to
be excited about the proposal. :)

While I agree that it would be strange to request both a password and a
yubico-style security key assertion in a single call to `get()`, the single
entry-point approach seems like an essential component of the story for
more complicated authenticators that folks might trust as an authentication
vector in and of themselves. I tried to sketch this out in more detail at
the end of my response to Dirk's email earlier this week:
https://lists.w3.org/Archives/Public/public-webauthn/2017Apr/0147.html


> For example, for usernames and password -- the browser manages identities
> and shows the UX for selection.  For authenticators such as phones, the
> phone does.  I'm not sure what the right way to show UX is there.  Maybe
> it's not a problem for Edge that might just call Hello, but I'm not sure
> what cross-operating-system browsers such as FF and Chrome would do.
>

Long term, I think this is a problem we very much need to solve: it should be
possible for a developer to transition from passwords to something stronger
without throwing multiple, disconnected dialogs up in the user's face.

Shorter-term, I think we have two options:

1.  We enforce a disconnect between the credential types that the user
    agent knows about a priori, and those that require an external
    service for discovery (this might boil down to rejecting calls like
    `get({ password: true, scoped: { ... })`).

2.  We launch something strange to support these kinds of requests, and
    iterate on it. The credential management spec currently suggests
    something like displaying the known credentials in a
    user-agent-controlled chooser, along with a friendly name for the
    type of credentials that could be discovered. That is, given the
    above call to `get()`, the chooser might render:

    *  User/Password 1
    *  User/Password 2
    *  Use a Security Key

    And clicking the last item would nicely push you off to the
    authenticator for the real decision (and, presumably, make all
    your security keys flash).

The second option doesn't seem terrible to me, and the first option
leaves obvious
room for future improvement.


> Or for example, consider during the create account phase when acme.com
> tells the browser that it'll accept a username/password/oauth token from
> Google or Facebook or an Authenticator -- what does the browser draw then?
> How does the user choose?
>

I think this boils down to the same question as above, with the slight twist
that we're talking about sign-up rather than sign-in. Here, I agree with
you that punting is a pretty reasonable option, as I don't think we've
worked out a good story for sign-up with the existing credential types,
much less new ones.

https://github.com/w3c/webappsec-credential-management/pull/72 is something of
a first step in this direction; aligning `Credential` object creation under
a single, async constructor gives us a lot of room for future improvements.


> We haven't figured out what it means to not require user mediation for
> webauthn, because there are lots of details.
>

The top of that response to Dirk's email that I mentioned earlier
addresses some
of his concern with `requireUserMediation()`, and tries to explain how I
see it fitting into the story we'd tell developers around the various kinds
of user-presence semantics y'all are discussing. Do my claims there make
sense?


> The relationships between user accounts and passwords is 1:1 -- but that's
> not the case for users and authenticators.
>

My understanding is that the relationship between users and public keys is
1:N: `mkwst@google.com` on `google.com` has a few security keys, all of which
are valid for the account. The relationship between public keys and users,
on the other hand, is 1:1: each of `mkwst@google.com`'s public keys for `
google.com` is unique, and cannot be used to validate any other user.

It's the latter relationship that seems important here: just as
the username/password credential unambiguously identifies a single
relationship, so does the public key/assertion credential.


> I can keep going,
>

Please do! I'd rather have your questions as known unknowns, rather
than leaving
the Rumsfeldian specter of unknown unknowns hanging over the discussion. :)


> but the point is that there are questions here -- lots of them.  It will
> take a while to iron them out, to play with implementations, to iterate, to
> refactor, to make a UX that users understand.  On the other hand, we pretty
> much know how to build webauthn in its current form.  It's self-contained
> and doesn't depend on any outsides specs.
>

I agree with you that shipping the current spec is likely going to be
faster than shipping something different than the current spec, if only
because we haven't yet agreed upon what "different" means. :)

That said, I believe that the proposal in #384 is not that far off from what's
in the current spec. The public API surface shifts in a number of ways, but
I don't honestly think that the public API surface is where implementations
are going to find most of the challenge. In Chrome's terms, I suspect that
the Blink layer (IDL, bindings, etc) will be managable either way you go,
while the //content layer changes will be more substantial. I think this is
reflected in the PR: the IDL shifts quite a bit, while the attestation and
assertion algorithms barely change at all.

Perhaps JC, Anthony, Angelo, etc can weigh in with their thoughts as
vendors with existing (partial?) implementations?


> If I understand the proposed merge correctly, it also requires that the
> credential management API be changed.  So now, before any webauthn api can
> be put out, the credential management API must be refactored and only then
> can webauthn be developed.  Also, let's not forget that there are websites
> that depend on the current credential management API.
>

I don't think this is the case. While putting together the PR that
we're discussing,
I did rewrite the credential management spec to refine and improve the
extension points and internal algorithms, but the public API surface
remained intact. The only visible change I can think of at the moment is
the removal of the `SiteBoundCredential` intermediate interface, which
seems like a good idea regardless.

The thought exercise of putting the PR together sparked some good discussion
about additions that we could make to the API that would be good for
existing developers (the `create()` proposal above is one), and
clarifications that might likewise be useful in the status quo (the
naming/structure of `unmediated`, for instance). These latter changes would
make it easier to merge webauthn, to be sure, but they seem useful in
themselves, and I expect we'll run with them regardless of the outcome of
this discussion.


> The PR is not the only possible credman merge proposal.  Here is another
> (if you don't like this one, we've got another):
>

I'm sorry; Ugh. This is a long email, and I haven't even gotten to your IDL
yet. Rather than going line-by-line through it, I'll throw out some
high-level opinions. At first glance, I think that splitting the top-level
into `navigator.credentials.bearer` and `navigator.credentials.publicKey`
feels a bit like the worst of both worlds. It conjoins two distinct APIs
together through the use of a common noun ("credential"), but that noun
seems to be a homograph: one side of the API uses "credential" to mean "the
thing you give to the website in order to authenticate a user", while the
other side uses "credential" as metadata adorning the actual authentication
bits.

Contrast that with #384, which aims to unify the usage of "credential" by
inverting the relationship between `ScopedCredential` and
`AuthenticatorResponse`. Developers get a `Credential`, whatever API they
call, and can send it up to the server for processing.

Perhaps more foundationally, though, this split makes it quite difficult to
create a single entry-point to obtain credentials for a user, as we
discussed above. Again, I see that as a clear selling point of the proposal
you're countering.

Practically, as you noted above, there are websites that depend on the
current credential management API. There are practical implications to
pulling that API out from under existing users by moving
`navigator.credentials.get()` to `navigator.credentials.bearer.get()`. It's
painful for developers, and I think that kind of change needs more
substantial justification than expedience. Ideally, we could avoid this
kind of churn.

Regarding the claimed advantages:

1.  Size of change to existing APIs: It's not clear to me that this is a
smaller change to webauthn than #384, and it's pretty clearly a
substantially larger change to existing users of `navigator.credentials`.

2.  Store: I discussed `store()` a bit in the response to Dirk earlier this
week: right in the middle of
https://lists.w3.org/Archives/Public/public-webauthn/2017Apr/0147.html. I
hope that clarifies the way I'm approaching it.

3.  Mediation: Likewise, this is the last piece of that email.

4.  Developers will only have to understand `credential`: This cuts both
ways, as developers familiar with the credential management spec can't
apply that knowledge to the new `publicKey` branch of the API, and in fact
their existing experience will work against them due to the distinctions in
usage of "credential".

5.  New methods can be added to `publicKey` without considering `bearer`:
It's quite possible to hang methods off of a particular credential type if
they only apply to a certain credential type. Moreover, I don't think this
division actually removes the necessity to consider generalizing a given
API, it just punts the question down the road. *shrug* I see this as a
long-term drawback for short-term gain, in other words. :)

All that said, I'd like to pull out some points where I think we agree.
Perhaps we can start with these smaller changes first:

1.  Allowing both attestations and assertions to derive from
    `AuthenticatorResponse` is a good idea. Let's extract this into
    something that we can merge on its own to improve the status quo.

2.  `PublicKeyCredential` is a better name than `ScopedCredential`!

3.  `PublicKeyCredential` inheriting from `Credential` (and therefore
    changing the types of both `id` and `type` properties) seems like
    a good step towards talking about the same thing when we say
    "credential".

All that is a somewhat negative note to end up on. Hrm. So instead, I'll
say again that I appeciate the time y'all are spending on this with me, and
I'm pretty confident that we'll end up with something better and cleaner
than either of the proposals on the table through this discussion.

Thanks for your attention! Apologies for the length... I'll try to more
agressively trim future responses. :)

-mike

Received on Tuesday, 11 April 2017 22:37:52 UTC