Chromium Code Reviews| 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; |
|
jochen (gone - plz use gerrit)
2017/06/28 07:38:30
nit. static isn't needed since the definition is a
kpaulhamus
2017/06/28 08:48:16
Done.
|
| +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 |