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 0dafa12e467085e578112a977fb7b3d8f15a3cae..22fe79ccc6205a398ad795eb0673dda0ce299f17 100644 |
--- a/third_party/WebKit/Source/modules/webauth/WebAuthentication.cpp |
+++ b/third_party/WebKit/Source/modules/webauth/WebAuthentication.cpp |
@@ -17,27 +17,30 @@ |
namespace { |
const char kNoAuthenticatorError[] = "Authenticator unavailable."; |
+// Time to wait for an authenticator to successfully complete an operation. |
+static const double adjustedTimeoutLower = 60; |
+static const double adjustedTimeoutUpper = 120; |
} // anonymous namespace |
namespace mojo { |
- |
+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; |
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()), |
- buffer.getAsArrayBuffer()->byteLength()); |
+ vector.Append(static_cast<uint8_t*>(buffer.getAsArrayBuffer()->Data()), |
+ buffer.getAsArrayBuffer()->ByteLength()); |
} else { |
- vector.append( |
- static_cast<uint8_t*>(buffer.getAsArrayBufferView()->baseAddress()), |
+ vector.Append( |
+ static_cast<uint8_t*>(buffer.getAsArrayBufferView()->BaseAddress()), |
buffer.getAsArrayBufferView()->byteLength()); |
} |
return vector; |
@@ -65,17 +68,33 @@ ScopedCredentialOptionsPtr convertScopedCredentialOptions( |
const blink::ScopedCredentialOptions options, |
blink::ScriptPromiseResolver* resolver) { |
auto mojoOptions = ScopedCredentialOptions::New(); |
- mojoOptions->timeout_seconds = options.timeoutSeconds(); |
- mojoOptions->rp_id = options.rpId(); |
- |
- // Adds the excludeList members (which are ScopedCredentialDescriptors) |
- for (const auto& descriptor : options.excludeList()) { |
- auto mojoDescriptor = ScopedCredentialDescriptor::New(); |
- mojoDescriptor->type = convertScopedCredentialType(descriptor.type()); |
- mojoDescriptor->id = convertBufferSource(descriptor.id()); |
- for (const auto& transport : descriptor.transports()) |
- mojoDescriptor->transports.push_back(convertTransport(transport)); |
- mojoOptions->exclude_list.push_back(std::move(mojoDescriptor)); |
+ if (options.hasRpId()) { |
+ mojoOptions->rp_id = options.rpId(); |
+ } |
+ |
+ // Step 1 of https://w3c.github.io/webauthn/#makeCredential |
+ if (options.hasTimeoutSeconds()) { |
+ mojoOptions->adjusted_timeout = |
+ static_cast<double>(options.timeoutSeconds()); |
+ if (mojoOptions->adjusted_timeout > adjustedTimeoutUpper) { |
+ mojoOptions->adjusted_timeout = adjustedTimeoutUpper; |
+ } else if (mojoOptions->adjusted_timeout < adjustedTimeoutLower) { |
+ mojoOptions->adjusted_timeout = adjustedTimeoutLower; |
+ } |
+ } else { |
+ mojoOptions->adjusted_timeout = adjustedTimeoutLower; |
+ } |
+ |
+ if (options.hasExcludeList()) { |
+ // Adds the excludeList members (which are ScopedCredentialDescriptors) |
+ for (const auto& descriptor : options.excludeList()) { |
+ auto mojoDescriptor = ScopedCredentialDescriptor::New(); |
+ mojoDescriptor->type = convertScopedCredentialType(descriptor.type()); |
+ mojoDescriptor->id = convertBufferSource(descriptor.id()); |
+ for (const auto& transport : descriptor.transports()) |
+ mojoDescriptor->transports.push_back(convertTransport(transport)); |
+ mojoOptions->exclude_list.push_back(std::move(mojoDescriptor)); |
+ } |
} |
// TODO (kpaulhamus) add AuthenticationExtensions; |
return mojoOptions; |
@@ -89,64 +108,77 @@ ScopedCredentialParametersPtr convertScopedCredentialParameter( |
// TODO (kpaulhamus) add AlgorithmIdentifier |
return mojoParameter; |
} |
+ |
+blink::DOMException* createExceptionFromStatus(AuthenticatorStatus status) { |
+ switch (status) { |
+ 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.document()) { |
- frame.interfaceProvider()->getInterface(mojo::MakeRequest(&m_authenticator)); |
- m_authenticator.set_connection_error_handler(convertToBaseCallback( |
- WTF::bind(&WebAuthentication::onAuthenticatorConnectionError, |
- wrapWeakPersistent(this)))); |
-} |
+ : ContextLifecycleObserver(frame.GetDocument()) {} |
WebAuthentication::~WebAuthentication() { |
// |m_authenticator| may still be valid but there should be no more |
// outstanding requests because each holds a persistent handle to this object. |
- DCHECK(m_authenticatorRequests.isEmpty()); |
+ DCHECK(m_authenticatorRequests.IsEmpty()); |
} |
void WebAuthentication::Dispose() {} |
+// With options |
ScriptPromise WebAuthentication::makeCredential( |
ScriptState* script_state, |
const RelyingPartyAccount& account_information, |
const HeapVector<ScopedCredentialParameters> crypto_parameters, |
const BufferSource& attestation_challenge, |
ScopedCredentialOptions& options) { |
- ExecutionContext* executionContext = scriptState->getExecutionContext(); |
+ ScriptPromise promise = rejectIfNotSupported(script_state); |
+ if (!promise.IsEmpty()) |
+ return promise; |
- if (!m_authenticator) { |
- return ScriptPromise::rejectWithDOMException( |
- scriptState, DOMException::create(NotSupportedError)); |
- } |
+ ScriptPromiseResolver* resolver = ScriptPromiseResolver::Create(script_state); |
- String errorMessage; |
- if (!executionContext->isSecureContext(errorMessage)) { |
- return ScriptPromise::rejectWithDOMException( |
- scriptState, DOMException::create(SecurityError, errorMessage)); |
- } |
- |
- ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState); |
- ScriptPromise promise = resolver->promise(); |
- |
- // TODO(kpaulhamus) validate parameters according to spec |
- Vector<uint8_t> buffer = mojo::convertBufferSource(attestationChallenge); |
+ Vector<uint8_t> buffer = mojo::convertBufferSource(attestation_challenge); |
auto opts = mojo::convertScopedCredentialOptions(options, resolver); |
Vector<webauth::mojom::blink::ScopedCredentialParametersPtr> parameters; |
- for (const auto& parameter : cryptoParameters) { |
- parameters.push_back( |
- mojo::convertScopedCredentialParameter(parameter, resolver)); |
+ for (const auto& parameter : crypto_parameters) { |
+ if (parameter.hasType()) { // TODO add algorithm |
+ parameters.push_back( |
+ mojo::convertScopedCredentialParameter(parameter, resolver)); |
+ } |
} |
m_authenticatorRequests.insert(resolver); |
- m_authenticator->makeCredential( |
- accountInformation, std::move(parameters), buffer, std::move(opts), |
- convertToBaseCallback(WTF::bind(&WebAuthentication::onMakeCredential, |
- wrapPersistent(this), |
- wrapPersistent(resolver)))); |
- return promise; |
+ m_authenticator->MakeCredential( |
+ account_information, std::move(parameters), buffer, std::move(opts), |
+ ConvertToBaseCallback(WTF::Bind(&WebAuthentication::onMakeCredential, |
+ WrapPersistent(this), |
+ WrapPersistent(resolver)))); |
+ return resolver->Promise(); |
} |
ScriptPromise WebAuthentication::getAssertion( |
@@ -157,59 +189,97 @@ ScriptPromise WebAuthentication::getAssertion( |
return ScriptPromise(); |
} |
-void WebAuthentication::contextDestroyed(ExecutionContext*) { |
- m_authenticator.reset(); |
- m_authenticatorRequests.clear(); |
-} |
- |
-void WebAuthentication::onAuthenticatorConnectionError() { |
- m_authenticator.reset(); |
- for (ScriptPromiseResolver* resolver : m_authenticatorRequests) { |
- resolver->reject( |
- DOMException::create(NotFoundError, kNoAuthenticatorError)); |
- } |
- m_authenticatorRequests.clear(); |
+void WebAuthentication::ContextDestroyed(ExecutionContext*) { |
+ cleanup(); |
} |
+// Step 11 of https://w3c.github.io/webauthn/#makeCredential |
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>> scopedCredentials; |
- for (auto& credential : credentials) { |
- if (credential->client_data.isEmpty() || |
- credential->attestation.isEmpty()) { |
- resolver->reject( |
- DOMException::create(NotFoundError, "No credentials returned.")); |
+ DOMException* error = mojo::createExceptionFromStatus(status); |
+ if (error) { |
+ for (ScriptPromiseResolver* resolver : m_authenticatorRequests) { |
+ resolver->Reject(error); |
+ } |
+ cleanup(); |
Zhiqiang Zhang (Slow)
2017/04/11 19:42:50
Actually, the issue is unrelated to mojo. I checke
|
+ 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) { |
+ ExecutionContext* executionContext = script_state->GetExecutionContext(); |
+ |
+ if (!m_authenticator) { |
+ if (!GetFrame()) { |
+ return ScriptPromise::RejectWithDOMException( |
+ script_state, DOMException::Create(kNotSupportedError)); |
} |
- DOMArrayBuffer* clientDataBuffer = DOMArrayBuffer::create( |
- static_cast<void*>(&credential->client_data.front()), |
- credential->client_data.size()); |
+ GetFrame()->GetInterfaceProvider()->GetInterface( |
+ mojo::MakeRequest(&m_authenticator)); |
- DOMArrayBuffer* attestationBuffer = DOMArrayBuffer::create( |
- static_cast<void*>(&credential->attestation.front()), |
- credential->attestation.size()); |
+ m_authenticator.set_connection_error_handler(ConvertToBaseCallback( |
+ WTF::Bind(&WebAuthentication::onAuthenticatorConnectionError, |
+ WrapWeakPersistent(this)))); |
+ } |
- scopedCredentials.push_back( |
- ScopedCredentialInfo::create(clientDataBuffer, attestationBuffer)); |
+ String errorMessage; |
+ if (!executionContext->IsSecureContext(errorMessage)) { |
+ return ScriptPromise::RejectWithDOMException( |
+ script_state, DOMException::Create(kSecurityError, errorMessage)); |
} |
- resolver->resolve(scopedCredentials); |
- m_authenticatorRequests.erase(resolver); |
+ |
+ return ScriptPromise(); |
+} |
+ |
+void WebAuthentication::onAuthenticatorConnectionError() { |
+ for (ScriptPromiseResolver* resolver : m_authenticatorRequests) { |
+ resolver->Reject( |
+ DOMException::Create(kNotFoundError, kNoAuthenticatorError)); |
+ } |
+ cleanup(); |
} |
bool WebAuthentication::markRequestComplete(ScriptPromiseResolver* resolver) { |
- auto requestEntry = m_authenticatorRequests.find(resolver); |
+ auto requestEntry = m_authenticatorRequests.Find(resolver); |
if (requestEntry == m_authenticatorRequests.end()) |
return false; |
m_authenticatorRequests.erase(requestEntry); |
return true; |
} |
+// Clears the promise resolver and closes the Mojo connection. |
+void WebAuthentication::cleanup() { |
+ m_authenticator.reset(); |
+ m_authenticatorRequests.Clear(); |
+} |
+ |
DEFINE_TRACE(WebAuthentication) { |
- visitor->trace(m_authenticatorRequests); |
- ContextLifecycleObserver::trace(visitor); |
+ visitor->Trace(m_authenticatorRequests); |
+ ContextLifecycleObserver::Trace(visitor); |
} |
} // namespace blink |