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 "modules/webauth/RelyingPartyAccount.h" | |
| 14 #include "modules/webauth/ScopedCredential.h" | |
| 15 #include "modules/webauth/ScopedCredentialOptions.h" | |
| 16 #include "modules/webauth/ScopedCredentialParameters.h" | |
| 17 #include "public/platform/InterfaceProvider.h" | |
| 18 | |
| 19 namespace { | |
| 20 const char kNoAuthenticatorError[] = "Authenticator unavailable."; | |
| 21 } // anonymous namespace | |
| 22 | |
| 23 namespace mojo { | |
| 24 | |
| 25 using webauth::mojom::blink::RelyingPartyAccount; | |
| 26 using webauth::mojom::blink::RelyingPartyAccountPtr; | |
| 27 using webauth::mojom::blink::ScopedCredentialOptions; | |
| 28 using webauth::mojom::blink::ScopedCredentialOptionsPtr; | |
| 29 using webauth::mojom::blink::ScopedCredentialParameters; | |
| 30 using webauth::mojom::blink::ScopedCredentialParametersPtr; | |
| 31 using webauth::mojom::blink::ScopedCredentialDescriptor; | |
| 32 using webauth::mojom::blink::ScopedCredentialType; | |
| 33 using webauth::mojom::blink::Transport; | |
| 34 | |
| 35 Vector<uint8_t> convertBufferSource(const blink::BufferSource& buffer) { | |
| 36 DCHECK(buffer.isNull()); | |
| 37 Vector<uint8_t> vector; | |
| 38 if (buffer.isArrayBuffer()) { | |
| 39 vector.Append(static_cast<uint8_t*>(buffer.getAsArrayBuffer()->Data()), | |
| 40 buffer.getAsArrayBuffer()->ByteLength()); | |
| 41 } else { | |
| 42 vector.Append(static_cast<uint8_t*>( | |
| 43 buffer.getAsArrayBufferView().View()->BaseAddress()), | |
| 44 buffer.getAsArrayBufferView().View()->byteLength()); | |
| 45 } | |
| 46 return vector; | |
| 47 } | |
| 48 | |
| 49 ScopedCredentialType convertScopedCredentialType(const String& credType) { | |
| 50 if (credType == "ScopedCred") | |
| 51 return ScopedCredentialType::SCOPEDCRED; | |
| 52 NOTREACHED(); | |
| 53 return ScopedCredentialType::SCOPEDCRED; | |
| 54 } | |
| 55 | |
| 56 Transport convertTransport(const String& transport) { | |
| 57 if (transport == "usb") | |
| 58 return Transport::USB; | |
| 59 if (transport == "nfc") | |
| 60 return Transport::NFC; | |
| 61 if (transport == "ble") | |
| 62 return Transport::BLE; | |
| 63 NOTREACHED(); | |
| 64 return Transport::USB; | |
| 65 } | |
| 66 | |
| 67 RelyingPartyAccountPtr convertRelyingPartyAccount( | |
| 68 const blink::RelyingPartyAccount& accountInformation, | |
| 69 blink::ScriptPromiseResolver* resolver) { | |
| 70 auto mojoAccount = RelyingPartyAccount::New(); | |
| 71 | |
| 72 mojoAccount->relying_party_display_name = accountInformation.rpDisplayName(); | |
| 73 mojoAccount->display_name = accountInformation.displayName(); | |
| 74 mojoAccount->id = accountInformation.id(); | |
| 75 mojoAccount->name = accountInformation.name(); | |
| 76 mojoAccount->image_url = accountInformation.imageURL(); | |
| 77 return mojoAccount; | |
| 78 } | |
| 79 | |
| 80 ScopedCredentialOptionsPtr convertScopedCredentialOptions( | |
| 81 const blink::ScopedCredentialOptions options, | |
| 82 blink::ScriptPromiseResolver* resolver) { | |
| 83 auto mojoOptions = ScopedCredentialOptions::New(); | |
| 84 mojoOptions->timeout_seconds = options.timeoutSeconds(); | |
| 85 mojoOptions->relying_party_id = options.rpId(); | |
| 86 | |
| 87 // Adds the excludeList members (which are ScopedCredentialDescriptors) | |
| 88 for (const auto& descriptor : options.excludeList()) { | |
| 89 auto mojoDescriptor = ScopedCredentialDescriptor::New(); | |
| 90 mojoDescriptor->type = convertScopedCredentialType(descriptor.type()); | |
| 91 mojoDescriptor->id = convertBufferSource(descriptor.id()); | |
| 92 for (const auto& transport : descriptor.transports()) | |
| 93 mojoDescriptor->transports.push_back(convertTransport(transport)); | |
| 94 mojoOptions->exclude_list.push_back(std::move(mojoDescriptor)); | |
| 95 } | |
| 96 // TODO (kpaulhamus) add AuthenticationExtensions; | |
| 97 return mojoOptions; | |
| 98 } | |
| 99 | |
| 100 ScopedCredentialParametersPtr convertScopedCredentialParameter( | |
| 101 const blink::ScopedCredentialParameters parameter, | |
| 102 blink::ScriptPromiseResolver* resolver) { | |
| 103 auto mojoParameter = ScopedCredentialParameters::New(); | |
| 104 mojoParameter->type = convertScopedCredentialType(parameter.type()); | |
| 105 // TODO (kpaulhamus) add AlgorithmIdentifier | |
| 106 return mojoParameter; | |
| 107 } | |
| 108 } // namespace mojo | |
| 8 | 109 |
| 9 namespace blink { | 110 namespace blink { |
| 10 | 111 |
| 11 WebAuthentication::WebAuthentication(LocalFrame& frame) {} | 112 WebAuthentication::WebAuthentication(LocalFrame& frame) |
| 113 : ContextLifecycleObserver(frame.GetDocument()) { | |
| 114 frame.GetInterfaceProvider()->GetInterface( | |
| 115 mojo::MakeRequest(&m_authenticator)); | |
| 116 m_authenticator.set_connection_error_handler(ConvertToBaseCallback( | |
| 117 WTF::Bind(&WebAuthentication::onAuthenticatorConnectionError, | |
| 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* script_state, | 130 ScriptState* script_state, |
| 19 const RelyingPartyAccount& account_information, | 131 const RelyingPartyAccount& account_information, |
| 20 const HeapVector<ScopedCredentialParameters> crypto_parameters, | 132 const HeapVector<ScopedCredentialParameters> crypto_parameters, |
| 21 const BufferSource& attestation_challenge, | 133 const BufferSource& attestation_challenge, |
| 22 ScopedCredentialOptions& options) { | 134 ScopedCredentialOptions& options) { |
| 23 NOTREACHED(); | 135 ExecutionContext* executionContext = script_state->GetExecutionContext(); |
| 24 return ScriptPromise(); | 136 |
| 137 if (!m_authenticator) { | |
| 138 return ScriptPromise::RejectWithDOMException( | |
| 139 script_state, DOMException::Create(kNotSupportedError)); | |
| 140 } | |
| 141 | |
| 142 String errorMessage; | |
| 143 if (!executionContext->IsSecureContext(errorMessage)) { | |
|
ikilpatrick
2017/04/24 22:11:44
should this go before the !m-authenticator check?
kpaulhamus
2017/04/25 00:03:08
Done.
| |
| 144 return ScriptPromise::RejectWithDOMException( | |
| 145 script_state, DOMException::Create(kSecurityError, errorMessage)); | |
| 146 } | |
| 147 | |
| 148 ScriptPromiseResolver* resolver = ScriptPromiseResolver::Create(script_state); | |
| 149 ScriptPromise promise = resolver->Promise(); | |
| 150 | |
| 151 // TODO(kpaulhamus) validate parameters according to spec | |
| 152 auto account = | |
| 153 mojo::convertRelyingPartyAccount(account_information, resolver); | |
| 154 Vector<uint8_t> buffer = mojo::convertBufferSource(attestation_challenge); | |
| 155 auto opts = mojo::convertScopedCredentialOptions(options, resolver); | |
| 156 Vector<webauth::mojom::blink::ScopedCredentialParametersPtr> parameters; | |
| 157 for (const auto& parameter : crypto_parameters) { | |
| 158 parameters.push_back( | |
| 159 mojo::convertScopedCredentialParameter(parameter, resolver)); | |
| 160 } | |
| 161 | |
| 162 m_authenticatorRequests.insert(resolver); | |
| 163 m_authenticator->makeCredential( | |
| 164 std::move(account), std::move(parameters), buffer, std::move(opts), | |
| 165 ConvertToBaseCallback(Bind(&WebAuthentication::onMakeCredential, | |
| 166 WrapPersistent(this), | |
| 167 WrapPersistent(resolver)))); | |
| 168 return promise; | |
| 25 } | 169 } |
| 26 | 170 |
| 27 ScriptPromise WebAuthentication::getAssertion( | 171 ScriptPromise WebAuthentication::getAssertion( |
| 28 ScriptState* script_state, | 172 ScriptState* script_state, |
| 29 const BufferSource& assertion_challenge, | 173 const BufferSource& assertion_challenge, |
| 30 const AuthenticationAssertionOptions& options) { | 174 const AuthenticationAssertionOptions& options) { |
| 31 NOTREACHED(); | 175 NOTREACHED(); |
| 32 return ScriptPromise(); | 176 return ScriptPromise(); |
| 33 } | 177 } |
| 34 | 178 |
| 179 void WebAuthentication::ContextDestroyed(ExecutionContext*) { | |
| 180 m_authenticator.reset(); | |
| 181 m_authenticatorRequests.Clear(); | |
| 182 } | |
| 183 | |
| 184 void WebAuthentication::onAuthenticatorConnectionError() { | |
| 185 m_authenticator.reset(); | |
| 186 for (ScriptPromiseResolver* resolver : m_authenticatorRequests) { | |
| 187 resolver->Reject( | |
| 188 DOMException::Create(kNotFoundError, kNoAuthenticatorError)); | |
| 189 } | |
| 190 m_authenticatorRequests.Clear(); | |
| 191 } | |
| 192 | |
| 193 void WebAuthentication::onMakeCredential( | |
| 194 ScriptPromiseResolver* resolver, | |
| 195 Vector<webauth::mojom::blink::ScopedCredentialInfoPtr> credentials) { | |
| 196 if (!markRequestComplete(resolver)) | |
| 197 return; | |
| 198 | |
| 199 HeapVector<Member<ScopedCredentialInfo>> scopedCredentials; | |
| 200 for (auto& credential : credentials) { | |
| 201 if (credential->client_data.IsEmpty() || | |
| 202 credential->attestation.IsEmpty()) { | |
| 203 resolver->Reject( | |
| 204 DOMException::Create(kNotFoundError, "No credentials returned.")); | |
| 205 } | |
| 206 DOMArrayBuffer* clientDataBuffer = DOMArrayBuffer::Create( | |
| 207 static_cast<void*>(&credential->client_data.front()), | |
| 208 credential->client_data.size()); | |
| 209 | |
| 210 DOMArrayBuffer* attestationBuffer = DOMArrayBuffer::Create( | |
| 211 static_cast<void*>(&credential->attestation.front()), | |
| 212 credential->attestation.size()); | |
| 213 | |
| 214 scopedCredentials.push_back( | |
| 215 ScopedCredentialInfo::Create(clientDataBuffer, attestationBuffer)); | |
| 216 } | |
| 217 resolver->Resolve(scopedCredentials); | |
| 218 m_authenticatorRequests.erase(resolver); | |
| 219 } | |
| 220 | |
| 221 bool WebAuthentication::markRequestComplete(ScriptPromiseResolver* resolver) { | |
| 222 auto requestEntry = m_authenticatorRequests.Find(resolver); | |
| 223 if (requestEntry == m_authenticatorRequests.end()) | |
| 224 return false; | |
| 225 m_authenticatorRequests.erase(requestEntry); | |
| 226 return true; | |
| 227 } | |
| 228 | |
| 229 DEFINE_TRACE(WebAuthentication) { | |
| 230 visitor->Trace(m_authenticatorRequests); | |
| 231 ContextLifecycleObserver::Trace(visitor); | |
| 232 } | |
| 233 | |
| 35 } // namespace blink | 234 } // namespace blink |
| OLD | NEW |