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