| Index: third_party/WebKit/Source/modules/webauth/WebAuthentication.cpp
|
| diff --git a/third_party/WebKit/Source/modules/webauth/WebAuthentication.cpp b/third_party/WebKit/Source/modules/webauth/WebAuthentication.cpp
|
| index 06cba2c2be2f6b4296dedf8ac97fc645435b2f85..5975027b5693bca3973a0c941644159a5aa3ebf2 100644
|
| --- a/third_party/WebKit/Source/modules/webauth/WebAuthentication.cpp
|
| +++ b/third_party/WebKit/Source/modules/webauth/WebAuthentication.cpp
|
| @@ -1,4 +1,4 @@
|
| -// Copyright 2016 The Chromium Authors. All rights reserved.
|
| +// Copyright 2017 The Chromium Authors. All rights reserved.
|
| // Use of this source code is governed by a BSD-style license that can be
|
| // found in the LICENSE file.
|
|
|
| @@ -20,23 +20,26 @@
|
|
|
| namespace {
|
| const char kNoAuthenticatorError[] = "Authenticator unavailable.";
|
| +// Time to wait for an authenticator to successfully complete an operation.
|
| +static const int kAdjustedTimeoutLower = 60;
|
| +static const int kAdjustedTimeoutUpper = 120;
|
| } // anonymous namespace
|
|
|
| namespace mojo {
|
| -
|
| using webauth::mojom::blink::RelyingPartyAccount;
|
| using webauth::mojom::blink::RelyingPartyAccountPtr;
|
| +using webauth::mojom::blink::AuthenticatorStatus;
|
| +using webauth::mojom::blink::ScopedCredentialDescriptor;
|
| using webauth::mojom::blink::ScopedCredentialOptions;
|
| using webauth::mojom::blink::ScopedCredentialOptionsPtr;
|
| using webauth::mojom::blink::ScopedCredentialParameters;
|
| using webauth::mojom::blink::ScopedCredentialParametersPtr;
|
| -using webauth::mojom::blink::ScopedCredentialDescriptor;
|
| using webauth::mojom::blink::ScopedCredentialType;
|
| using webauth::mojom::blink::Transport;
|
|
|
| // TODO(kpaulhamus): Make this a TypeConverter
|
| Vector<uint8_t> ConvertBufferSource(const blink::BufferSource& buffer) {
|
| - DCHECK(buffer.isNull());
|
| + DCHECK(!buffer.isNull());
|
| Vector<uint8_t> vector;
|
| if (buffer.isArrayBuffer()) {
|
| vector.Append(static_cast<uint8_t*>(buffer.getAsArrayBuffer()->Data()),
|
| @@ -69,6 +72,7 @@ Transport ConvertTransport(const String& transport) {
|
| return Transport::USB;
|
| }
|
|
|
| +// TODO(kpaulhamus): Make this a TypeConverter
|
| RelyingPartyAccountPtr ConvertRelyingPartyAccount(
|
| const blink::RelyingPartyAccount& account_information,
|
| blink::ScriptPromiseResolver* resolver) {
|
| @@ -88,17 +92,32 @@ ScopedCredentialOptionsPtr ConvertScopedCredentialOptions(
|
| const blink::ScopedCredentialOptions options,
|
| blink::ScriptPromiseResolver* resolver) {
|
| auto mojo_options = ScopedCredentialOptions::New();
|
| - mojo_options->timeout_seconds = options.timeoutSeconds();
|
| - mojo_options->relying_party_id = options.rpId();
|
| -
|
| - // Adds the excludeList members (which are ScopedCredentialDescriptors)
|
| - for (const auto& descriptor : options.excludeList()) {
|
| - auto mojo_descriptor = ScopedCredentialDescriptor::New();
|
| - mojo_descriptor->type = ConvertScopedCredentialType(descriptor.type());
|
| - mojo_descriptor->id = ConvertBufferSource(descriptor.id());
|
| - for (const auto& transport : descriptor.transports())
|
| - mojo_descriptor->transports.push_back(ConvertTransport(transport));
|
| - mojo_options->exclude_list.push_back(std::move(mojo_descriptor));
|
| + if (options.hasRpId()) {
|
| + // if rpID is missing, it will later be set to the origin of the page
|
| + // in the secure browser process.
|
| + mojo_options->relying_party_id = options.rpId();
|
| + }
|
| +
|
| + // Step 4 of https://w3c.github.io/webauthn/#createCredential
|
| + int predicted_timeout = kAdjustedTimeoutLower;
|
| + if (options.hasTimeoutSeconds()) {
|
| + predicted_timeout = static_cast<int>(options.timeoutSeconds());
|
| + }
|
| +
|
| + mojo_options->adjusted_timeout = static_cast<double>(
|
| + std::max(kAdjustedTimeoutLower,
|
| + std::min(kAdjustedTimeoutUpper, predicted_timeout)));
|
| +
|
| + if (options.hasExcludeList()) {
|
| + // Adds the excludeList members (which are ScopedCredentialDescriptors)
|
| + for (const auto& descriptor : options.excludeList()) {
|
| + auto mojo_descriptor = ScopedCredentialDescriptor::New();
|
| + mojo_descriptor->type = ConvertScopedCredentialType(descriptor.type());
|
| + mojo_descriptor->id = ConvertBufferSource(descriptor.id());
|
| + for (const auto& transport : descriptor.transports())
|
| + mojo_descriptor->transports.push_back(ConvertTransport(transport));
|
| + mojo_options->exclude_list.push_back(std::move(mojo_descriptor));
|
| + }
|
| }
|
| // TODO(kpaulhamus): add AuthenticationExtensions;
|
| return mojo_options;
|
| @@ -113,18 +132,40 @@ ScopedCredentialParametersPtr ConvertScopedCredentialParameter(
|
| // TODO(kpaulhamus): add AlgorithmIdentifier
|
| return mojo_parameter;
|
| }
|
| +
|
| +blink::DOMException* CreateExceptionFromStatus(AuthenticatorStatus status) {
|
| + switch (status) {
|
| + case AuthenticatorStatus::NOT_IMPLEMENTED:
|
| + return blink::DOMException::Create(blink::kNotSupportedError,
|
| + "Not implemented.");
|
| + case AuthenticatorStatus::NOT_ALLOWED_ERROR:
|
| + return blink::DOMException::Create(blink::kNotAllowedError,
|
| + "Not allowed.");
|
| + case AuthenticatorStatus::NOT_SUPPORTED_ERROR:
|
| + return blink::DOMException::Create(
|
| + blink::kNotSupportedError,
|
| + "Parameters for this operation are not supported.");
|
| + case AuthenticatorStatus::SECURITY_ERROR:
|
| + return blink::DOMException::Create(blink::kSecurityError,
|
| + "The operation was not allowed.");
|
| + case AuthenticatorStatus::UNKNOWN_ERROR:
|
| + return blink::DOMException::Create(blink::kUnknownError,
|
| + "Request failed.");
|
| + case AuthenticatorStatus::CANCELLED:
|
| + return blink::DOMException::Create(blink::kNotAllowedError,
|
| + "User canceled the operation.");
|
| + case AuthenticatorStatus::SUCCESS:
|
| + return nullptr;
|
| + default:
|
| + NOTREACHED();
|
| + return nullptr;
|
| + }
|
| +}
|
| } // namespace mojo
|
|
|
| namespace blink {
|
| -
|
| WebAuthentication::WebAuthentication(LocalFrame& frame)
|
| - : ContextLifecycleObserver(frame.GetDocument()) {
|
| - frame.GetInterfaceProvider()->GetInterface(
|
| - mojo::MakeRequest(&authenticator_));
|
| - authenticator_.set_connection_error_handler(ConvertToBaseCallback(
|
| - WTF::Bind(&WebAuthentication::OnAuthenticatorConnectionError,
|
| - WrapWeakPersistent(this))));
|
| -}
|
| + : ContextLifecycleObserver(frame.GetDocument()) {}
|
|
|
| WebAuthentication::~WebAuthentication() {
|
| // |authenticator_| may still be valid but there should be no more
|
| @@ -132,40 +173,36 @@ WebAuthentication::~WebAuthentication() {
|
| DCHECK(authenticator_requests_.IsEmpty());
|
| }
|
|
|
| -void WebAuthentication::Dispose() {}
|
| -
|
| ScriptPromise WebAuthentication::makeCredential(
|
| ScriptState* script_state,
|
| const RelyingPartyAccount& account_information,
|
| const HeapVector<ScopedCredentialParameters> crypto_parameters,
|
| const BufferSource& attestation_challenge,
|
| ScopedCredentialOptions& options) {
|
| - if (!authenticator_) {
|
| - return ScriptPromise::RejectWithDOMException(
|
| - script_state, DOMException::Create(kNotSupportedError));
|
| - }
|
| + ScriptPromise promise = RejectIfNotSupported(script_state);
|
| + if (!promise.IsEmpty())
|
| + return promise;
|
|
|
| ScriptPromiseResolver* resolver = ScriptPromiseResolver::Create(script_state);
|
| - ScriptPromise promise = resolver->Promise();
|
|
|
| - // TODO(kpaulhamus) validate parameters according to spec
|
| - auto account =
|
| - mojo::ConvertRelyingPartyAccount(account_information, resolver);
|
| Vector<uint8_t> buffer = mojo::ConvertBufferSource(attestation_challenge);
|
| auto opts = mojo::ConvertScopedCredentialOptions(options, resolver);
|
| Vector<webauth::mojom::blink::ScopedCredentialParametersPtr> parameters;
|
| for (const auto& parameter : crypto_parameters) {
|
| - parameters.push_back(
|
| - mojo::ConvertScopedCredentialParameter(parameter, resolver));
|
| + if (parameter.hasType()) {
|
| + parameters.push_back(
|
| + mojo::ConvertScopedCredentialParameter(parameter, resolver));
|
| + }
|
| }
|
| -
|
| + auto account =
|
| + mojo::ConvertRelyingPartyAccount(account_information, resolver);
|
| authenticator_requests_.insert(resolver);
|
| authenticator_->MakeCredential(
|
| std::move(account), std::move(parameters), buffer, std::move(opts),
|
| - ConvertToBaseCallback(Bind(&WebAuthentication::OnMakeCredential,
|
| - WrapPersistent(this),
|
| - WrapPersistent(resolver))));
|
| - return promise;
|
| + ConvertToBaseCallback(WTF::Bind(&WebAuthentication::OnMakeCredential,
|
| + WrapPersistent(this),
|
| + WrapPersistent(resolver))));
|
| + return resolver->Promise();
|
| }
|
|
|
| ScriptPromise WebAuthentication::getAssertion(
|
| @@ -177,44 +214,66 @@ ScriptPromise WebAuthentication::getAssertion(
|
| }
|
|
|
| void WebAuthentication::ContextDestroyed(ExecutionContext*) {
|
| - authenticator_.reset();
|
| - authenticator_requests_.clear();
|
| -}
|
| -
|
| -void WebAuthentication::OnAuthenticatorConnectionError() {
|
| - authenticator_.reset();
|
| - for (ScriptPromiseResolver* resolver : authenticator_requests_) {
|
| - resolver->Reject(
|
| - DOMException::Create(kNotFoundError, kNoAuthenticatorError));
|
| - }
|
| - authenticator_requests_.clear();
|
| + Cleanup();
|
| }
|
|
|
| void WebAuthentication::OnMakeCredential(
|
| ScriptPromiseResolver* resolver,
|
| - Vector<webauth::mojom::blink::ScopedCredentialInfoPtr> credentials) {
|
| + webauth::mojom::blink::AuthenticatorStatus status,
|
| + webauth::mojom::blink::ScopedCredentialInfoPtr credential) {
|
| if (!MarkRequestComplete(resolver))
|
| return;
|
|
|
| - HeapVector<Member<ScopedCredentialInfo>> scoped_credentials;
|
| - for (auto& credential : credentials) {
|
| - if (credential->client_data.IsEmpty() ||
|
| - credential->attestation.IsEmpty()) {
|
| - resolver->Reject(
|
| - DOMException::Create(kNotFoundError, "No credentials returned."));
|
| + DOMException* error = mojo::CreateExceptionFromStatus(status);
|
| + if (error) {
|
| + DCHECK(!credential);
|
| + resolver->Reject(error);
|
| + Cleanup();
|
| + return;
|
| + }
|
| +
|
| + if (credential->client_data.IsEmpty() || credential->attestation.IsEmpty()) {
|
| + resolver->Reject(
|
| + DOMException::Create(kNotFoundError, "No credential returned."));
|
| + return;
|
| + }
|
| +
|
| + DOMArrayBuffer* clientDataBuffer = DOMArrayBuffer::Create(
|
| + static_cast<void*>(&credential->client_data.front()),
|
| + credential->client_data.size());
|
| +
|
| + DOMArrayBuffer* attestationBuffer = DOMArrayBuffer::Create(
|
| + static_cast<void*>(&credential->attestation.front()),
|
| + credential->attestation.size());
|
| +
|
| + ScopedCredentialInfo* scopedCredential =
|
| + ScopedCredentialInfo::Create(clientDataBuffer, attestationBuffer);
|
| + resolver->Resolve(scopedCredential);
|
| +}
|
| +
|
| +ScriptPromise WebAuthentication::RejectIfNotSupported(
|
| + ScriptState* script_state) {
|
| + if (!authenticator_) {
|
| + if (!GetFrame()) {
|
| + return ScriptPromise::RejectWithDOMException(
|
| + script_state, DOMException::Create(kNotSupportedError));
|
| }
|
| - DOMArrayBuffer* client_data_buffer = DOMArrayBuffer::Create(
|
| - static_cast<void*>(&credential->client_data.front()),
|
| - credential->client_data.size());
|
| + GetFrame()->GetInterfaceProvider()->GetInterface(
|
| + mojo::MakeRequest(&authenticator_));
|
|
|
| - DOMArrayBuffer* attestation_buffer = DOMArrayBuffer::Create(
|
| - static_cast<void*>(&credential->attestation.front()),
|
| - credential->attestation.size());
|
| + authenticator_.set_connection_error_handler(ConvertToBaseCallback(
|
| + WTF::Bind(&WebAuthentication::OnAuthenticatorConnectionError,
|
| + WrapWeakPersistent(this))));
|
| + }
|
| + return ScriptPromise();
|
| +}
|
|
|
| - scoped_credentials.push_back(
|
| - ScopedCredentialInfo::Create(client_data_buffer, attestation_buffer));
|
| +void WebAuthentication::OnAuthenticatorConnectionError() {
|
| + for (ScriptPromiseResolver* resolver : authenticator_requests_) {
|
| + resolver->Reject(
|
| + DOMException::Create(kNotFoundError, kNoAuthenticatorError));
|
| }
|
| - resolver->Resolve();
|
| + Cleanup();
|
| }
|
|
|
| bool WebAuthentication::MarkRequestComplete(ScriptPromiseResolver* resolver) {
|
| @@ -230,4 +289,10 @@ DEFINE_TRACE(WebAuthentication) {
|
| ContextLifecycleObserver::Trace(visitor);
|
| }
|
|
|
| +// Clears the promise resolver, timer, and closes the Mojo connection.
|
| +void WebAuthentication::Cleanup() {
|
| + authenticator_.reset();
|
| + authenticator_requests_.clear();
|
| +}
|
| +
|
| } // namespace blink
|
|
|