Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "modules/webauth/WebAuthentication.h" | 5 #include "modules/webauth/WebAuthentication.h" |
| 6 | 6 |
| 7 #include "bindings/core/v8/ScriptPromise.h" | 7 #include "bindings/core/v8/ScriptPromise.h" |
| 8 #include "bindings/core/v8/ScriptPromiseResolver.h" | |
| 9 #include "core/dom/DOMException.h" | |
| 10 #include "core/dom/Document.h" | |
| 11 #include "core/dom/ExceptionCode.h" | |
| 12 #include "core/frame/LocalFrame.h" | |
| 13 #include "core/frame/UseCounter.h" | |
| 14 #include "modules/webauth/RelyingPartyAccount.h" | |
| 15 #include "modules/webauth/ScopedCredential.h" | |
| 16 #include "modules/webauth/ScopedCredentialOptions.h" | |
| 17 #include "modules/webauth/ScopedCredentialParameters.h" | |
| 18 #include "public/platform/InterfaceProvider.h" | |
| 19 | |
| 20 namespace { | |
| 21 const char kNoAuthenticatorError[] = "Authenticator unavailable."; | |
| 22 } // anonymous namespace | |
| 23 | |
| 24 namespace mojo { | |
| 25 | |
| 26 using webauth::mojom::blink::RelyingPartyAccount; | |
| 27 using webauth::mojom::blink::RelyingPartyAccountPtr; | |
| 28 using webauth::mojom::blink::ScopedCredentialOptions; | |
| 29 using webauth::mojom::blink::ScopedCredentialOptionsPtr; | |
| 30 using webauth::mojom::blink::ScopedCredentialParameters; | |
| 31 using webauth::mojom::blink::ScopedCredentialParametersPtr; | |
| 32 using webauth::mojom::blink::ScopedCredentialDescriptor; | |
| 33 using webauth::mojom::blink::ScopedCredentialType; | |
| 34 using webauth::mojom::blink::Transport; | |
| 35 | |
| 36 Vector<uint8_t> convertBufferSource(const blink::BufferSource& buffer) { | |
| 37 DCHECK(buffer.isNull()); | |
| 38 Vector<uint8_t> vector; | |
| 39 if (buffer.isArrayBuffer()) { | |
| 40 vector.append(static_cast<uint8_t*>(buffer.getAsArrayBuffer()->data()), | |
| 41 buffer.getAsArrayBuffer()->byteLength()); | |
| 42 } else { | |
| 43 vector.append( | |
| 44 static_cast<uint8_t*>(buffer.getAsArrayBufferView()->baseAddress()), | |
| 45 buffer.getAsArrayBufferView()->byteLength()); | |
| 46 } | |
| 47 return vector; | |
| 48 } | |
| 49 | |
| 50 ScopedCredentialType convertScopedCredentialType(const WTF::String& credType) { | |
|
ikilpatrick
2017/02/28 19:18:18
is there a standard naming for these methods in th
kpaulhamus
2017/03/01 01:56:35
It doesn't really seem like it. Bluetooth doesn't
| |
| 51 if (credType == "ScopedCred") | |
|
dcheng
2017/02/28 07:25:56
Unfortunately, mapping strings to enums is the bes
kpaulhamus
2017/03/01 01:56:35
Acknowledged.
| |
| 52 return ScopedCredentialType::SCOPEDCRED; | |
| 53 NOTREACHED(); | |
| 54 return ScopedCredentialType::SCOPEDCRED; | |
| 55 } | |
| 56 | |
| 57 Transport convertTransport(const WTF::String& transport) { | |
| 58 if (transport == "usb") | |
| 59 return Transport::USB; | |
| 60 if (transport == "nfc") | |
| 61 return Transport::NFC; | |
| 62 if (transport == "ble") | |
| 63 return Transport::BLE; | |
| 64 NOTREACHED(); | |
| 65 return Transport::USB; | |
| 66 } | |
| 67 | |
| 68 RelyingPartyAccountPtr convertRelyingPartyAccount( | |
| 69 const blink::RelyingPartyAccount& accountInformation, | |
|
dcheng
2017/02/28 07:25:56
However, this can be implemented by using somethin
kpaulhamus
2017/03/01 01:56:34
Got it, I'll take a closer look.
| |
| 70 blink::ScriptPromiseResolver* resolver) { | |
| 71 auto mojoAccount = RelyingPartyAccount::New(); | |
| 72 | |
| 73 mojoAccount->rpDisplayName = accountInformation.rpDisplayName(); | |
| 74 mojoAccount->displayName = accountInformation.displayName(); | |
| 75 mojoAccount->id = accountInformation.id(); | |
| 76 mojoAccount->name = accountInformation.name(); | |
| 77 mojoAccount->imageURL = accountInformation.imageURL(); | |
| 78 return mojoAccount; | |
| 79 } | |
| 80 | |
| 81 ScopedCredentialOptionsPtr convertScopedCredentialOptions( | |
| 82 const blink::ScopedCredentialOptions options, | |
| 83 blink::ScriptPromiseResolver* resolver) { | |
| 84 auto mojoOptions = ScopedCredentialOptions::New(); | |
| 85 mojoOptions->timeoutSeconds = options.timeoutSeconds(); | |
| 86 mojoOptions->rpId = options.rpId(); | |
| 87 | |
| 88 // Adds the excludeList members (which are ScopedCredentialDescriptors) | |
| 89 for (const auto& descriptor : options.excludeList()) { | |
| 90 auto mojoDescriptor = ScopedCredentialDescriptor::New(); | |
| 91 mojoDescriptor->type = convertScopedCredentialType(descriptor.type()); | |
| 92 mojoDescriptor->id = convertBufferSource(descriptor.id()); | |
| 93 for (const auto& transport : descriptor.transports()) | |
| 94 mojoDescriptor->transports.push_back(convertTransport(transport)); | |
| 95 mojoOptions->excludeList.push_back(std::move(mojoDescriptor)); | |
| 96 } | |
| 97 // TODO (kpaulhamus) add AuthenticationExtensions; | |
| 98 return mojoOptions; | |
| 99 } | |
| 100 | |
| 101 ScopedCredentialParametersPtr convertScopedCredentialParameter( | |
| 102 const blink::ScopedCredentialParameters parameter, | |
| 103 blink::ScriptPromiseResolver* resolver) { | |
| 104 auto mojoParameter = ScopedCredentialParameters::New(); | |
| 105 mojoParameter->type = convertScopedCredentialType(parameter.type()); | |
| 106 // TODO (kpaulhamus) add AlgorithmIdentifier | |
| 107 return mojoParameter; | |
| 108 } | |
| 109 } // namespace mojo | |
| 8 | 110 |
| 9 namespace blink { | 111 namespace blink { |
| 10 | 112 |
| 11 WebAuthentication::WebAuthentication(LocalFrame& frame) {} | 113 WebAuthentication::WebAuthentication(LocalFrame& frame) |
| 114 : ContextLifecycleObserver(frame.document()) { | |
| 115 frame.interfaceProvider()->getInterface(mojo::MakeRequest(&m_authenticator)); | |
| 116 m_authenticator.set_connection_error_handler(convertToBaseCallback( | |
| 117 WTF::bind(&WebAuthentication::onAuthenticatorConnectionError, | |
|
dcheng
2017/02/28 07:25:56
Usually, the renderer won't ever see a connection
kpaulhamus
2017/03/01 01:56:34
I don't know enough about the pipe life cycle to m
| |
| 118 wrapWeakPersistent(this)))); | |
| 119 } | |
| 12 | 120 |
| 13 WebAuthentication::~WebAuthentication() {} | 121 WebAuthentication::~WebAuthentication() { |
| 122 // |m_authenticator| may still be valid but there should be no more | |
| 123 // outstanding requests because each holds a persistent handle to this object. | |
| 124 DCHECK(m_authenticatorRequests.isEmpty()); | |
| 125 } | |
| 14 | 126 |
| 15 void WebAuthentication::dispose() {} | 127 void WebAuthentication::dispose() {} |
| 16 | 128 |
| 17 ScriptPromise WebAuthentication::makeCredential( | 129 ScriptPromise WebAuthentication::makeCredential( |
| 18 ScriptState* scriptState, | 130 ScriptState* scriptState, |
| 19 const RelyingPartyAccount& accountInformation, | 131 const RelyingPartyAccount& accountInformation, |
| 20 const HeapVector<ScopedCredentialParameters> cryptoParameters, | 132 const HeapVector<ScopedCredentialParameters> cryptoParameters, |
| 21 const BufferSource& attestationChallenge, | 133 const BufferSource& attestationChallenge, |
| 22 ScopedCredentialOptions& options) { | 134 ScopedCredentialOptions& options) { |
| 23 NOTREACHED(); | 135 ExecutionContext* executionContext = scriptState->getExecutionContext(); |
| 24 return ScriptPromise(); | 136 UseCounter::count(executionContext, UseCounter::AuthenticationMakeCredential); |
| 137 | |
| 138 ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState); | |
| 139 ScriptPromise promise = resolver->promise(); | |
| 140 if (!m_authenticator) { | |
|
ikilpatrick
2017/02/28 19:18:18
can you un-nest these if stmts?, e.g.
if (!m_auth
kpaulhamus
2017/03/01 01:56:34
Done.
| |
| 141 resolver->reject(DOMException::create(NotSupportedError)); | |
| 142 } else { | |
| 143 String errorMessage; | |
| 144 if (!executionContext->isSecureContext(errorMessage)) { | |
|
dcheng
2017/02/28 07:25:56
Do you know if there any plan to implement the [Se
kpaulhamus
2017/03/01 01:56:34
It's a work in progress:
https://bugs.chromium.org
| |
| 145 resolver->reject(DOMException::create(SecurityError, errorMessage)); | |
| 146 } else { | |
| 147 // TODO(kpaulhamus) validate parameters according to spec | |
| 148 auto account = | |
| 149 mojo::convertRelyingPartyAccount(accountInformation, resolver); | |
| 150 Vector<uint8_t> buffer = mojo::convertBufferSource(attestationChallenge); | |
| 151 auto opts = mojo::convertScopedCredentialOptions(options, resolver); | |
| 152 Vector<webauth::mojom::blink::ScopedCredentialParametersPtr> parameters; | |
| 153 for (const auto& parameter : cryptoParameters) { | |
| 154 parameters.push_back( | |
| 155 mojo::convertScopedCredentialParameter(parameter, resolver)); | |
| 156 } | |
| 157 | |
| 158 m_authenticatorRequests.insert(resolver); | |
| 159 m_authenticator->makeCredential( | |
| 160 std::move(account), std::move(parameters), buffer, std::move(opts), | |
| 161 convertToBaseCallback(WTF::bind(&WebAuthentication::onMakeCredential, | |
| 162 wrapPersistent(this), | |
|
dcheng
2017/02/28 07:25:56
Should this be a weak persistent? If this object w
kpaulhamus
2017/03/01 01:56:34
I talked with reillyg about this, just because I w
| |
| 163 wrapPersistent(resolver)))); | |
| 164 } | |
| 165 } | |
| 166 return promise; | |
| 25 } | 167 } |
| 26 | 168 |
| 27 ScriptPromise WebAuthentication::getAssertion( | 169 ScriptPromise WebAuthentication::getAssertion( |
| 28 ScriptState* scriptState, | 170 ScriptState* scriptState, |
| 29 const BufferSource& assertionChallenge, | 171 const BufferSource& assertionChallenge, |
| 30 const AuthenticationAssertionOptions& options) { | 172 const AuthenticationAssertionOptions& options) { |
| 31 NOTREACHED(); | 173 NOTREACHED(); |
| 32 return ScriptPromise(); | 174 return ScriptPromise(); |
| 33 } | 175 } |
| 34 | 176 |
| 177 void WebAuthentication::contextDestroyed(ExecutionContext*) { | |
| 178 m_authenticator.reset(); | |
| 179 m_authenticatorRequests.clear(); | |
| 180 } | |
| 181 | |
| 182 void WebAuthentication::onAuthenticatorConnectionError() { | |
| 183 m_authenticator.reset(); | |
| 184 for (ScriptPromiseResolver* resolver : m_authenticatorRequests) { | |
| 185 resolver->reject( | |
| 186 DOMException::create(NotFoundError, kNoAuthenticatorError)); | |
| 187 } | |
| 188 m_authenticatorRequests.clear(); | |
| 189 } | |
| 190 | |
| 191 void WebAuthentication::onMakeCredential( | |
| 192 ScriptPromiseResolver* resolver, | |
| 193 Vector<webauth::mojom::blink::ScopedCredentialInfoPtr> credentials) { | |
| 194 if (!markRequestComplete(resolver)) | |
|
ikilpatrick
2017/02/28 19:18:18
Should this reject promise? Or DCHECK that this ne
kpaulhamus
2017/03/01 01:56:34
markRequestCompleted has the additional action of
| |
| 195 return; | |
| 196 | |
| 197 HeapVector<Member<ScopedCredentialInfo>> scopedCredentials; | |
| 198 for (auto& credential : credentials) { | |
| 199 if (credential->clientData.isEmpty() || credential->attestation.isEmpty()) { | |
| 200 resolver->reject( | |
|
ikilpatrick
2017/02/28 19:18:18
just rejectWithDOMException?
kpaulhamus
2017/03/01 01:56:34
Do you have an example for this where the callback
| |
| 201 DOMException::create(NotFoundError, "No credentials returned.")); | |
| 202 } | |
| 203 DOMArrayBuffer* clientDataBuffer = DOMArrayBuffer::create( | |
| 204 static_cast<void*>(&credential->clientData.front()), | |
| 205 credential->clientData.size()); | |
| 206 | |
| 207 DOMArrayBuffer* attestationBuffer = DOMArrayBuffer::create( | |
| 208 static_cast<void*>(&credential->attestation.front()), | |
| 209 credential->attestation.size()); | |
| 210 | |
| 211 scopedCredentials.push_back( | |
| 212 ScopedCredentialInfo::create(clientDataBuffer, attestationBuffer)); | |
| 213 } | |
| 214 resolver->resolve(scopedCredentials); | |
| 215 m_authenticatorRequests.erase(resolver); | |
| 216 } | |
| 217 | |
| 218 bool WebAuthentication::markRequestComplete(ScriptPromiseResolver* resolver) { | |
| 219 auto requestEntry = m_authenticatorRequests.find(resolver); | |
| 220 if (requestEntry == m_authenticatorRequests.end()) | |
| 221 return false; | |
| 222 m_authenticatorRequests.erase(requestEntry); | |
| 223 return true; | |
| 224 } | |
| 225 | |
| 226 DEFINE_TRACE(WebAuthentication) { | |
| 227 visitor->trace(m_authenticatorRequests); | |
| 228 ContextLifecycleObserver::trace(visitor); | |
| 229 } | |
| 230 | |
| 35 } // namespace blink | 231 } // namespace blink |
| OLD | NEW |