Chromium Code Reviews| Index: services/authentication/accounts_db_manager.cc |
| diff --git a/services/authentication/accounts_db_manager.cc b/services/authentication/accounts_db_manager.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..9d4d3de95e70f0f8ca3ac4746ae8e16388b4b5f7 |
| --- /dev/null |
| +++ b/services/authentication/accounts_db_manager.cc |
| @@ -0,0 +1,256 @@ |
| +// Copyright 2015 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. |
| + |
| +#include "services/authentication/accounts_db_manager.h" |
| + |
| +#include <vector> |
| + |
| +#include "base/logging.h" |
| +#include "base/memory/weak_ptr.h" |
| +#include "base/strings/string_tokenizer.h" |
| +#include "mojo/public/cpp/bindings/array.h" |
| +#include "mojo/public/cpp/bindings/type_converter.h" |
| +#include "mojo/services/files/interfaces/files.mojom.h" |
| +#include "services/authentication/authentication_impl_db.mojom.h" |
| +#include "services/authentication/credentials_impl_db.mojom.h" |
| + |
| +namespace authentication { |
| + |
| +char kAccountsDbFileName[] = "creds_db"; |
| +char kAuthDbFileName[] = "auth_db"; |
| +const uint32 kAuthDbVersion = 1; |
| +const uint32 kCredsDbVersion = 1; |
| + |
| +AccountsDbManager::AccountsDbManager(const mojo::files::DirectoryPtr directory) |
| + : creds_db_file_(nullptr), auth_db_file_(nullptr), weak_ptr_factory_(this) { |
| + // Initialize in-memory contents from existing DB file |
| + directory->OpenFile( |
| + kAccountsDbFileName, GetProxy(&creds_db_file_), |
| + mojo::files::kOpenFlagCreate | mojo::files::kOpenFlagRead | |
| + mojo::files::kOpenFlagWrite, |
| + [this](mojo::files::Error error) { |
| + if (mojo::files::Error::OK != error) { |
| + LOG(ERROR) << "Open() error on credentials db:" << error; |
| + delete this; |
| + return; |
| + } |
| + }); |
| + directory->OpenFile(kAuthDbFileName, GetProxy(&auth_db_file_), |
| + mojo::files::kOpenFlagCreate | |
| + mojo::files::kOpenFlagRead | |
| + mojo::files::kOpenFlagWrite, |
| + [this](mojo::files::Error error) { |
| + if (mojo::files::Error::OK != error) { |
| + LOG(ERROR) << "Open() error on auth db:" << error; |
| + delete this; |
| + return; |
| + } |
| + }); |
| + Initialize(); |
| +} |
| + |
| +AccountsDbManager::~AccountsDbManager() { |
| + weak_ptr_factory_.InvalidateWeakPtrs(); |
| + delete this; |
| +} |
| + |
| +base::WeakPtr<AccountsDbManager> AccountsDbManager::GetWeakPtr() { |
| + return weak_ptr_factory_.GetWeakPtr(); |
| +} |
| + |
| +authentication::CredentialsPtr AccountsDbManager::GetCredentials( |
| + const mojo::String& username) { |
| + ensureCredsDbInit(); |
| + |
| + authentication::CredentialsPtr creds = authentication::Credentials::New(); |
| + if (username.is_null()) { |
| + return creds.Pass(); |
| + } |
| + |
| + auto it = creds_store_.credentials.find(username); |
| + if (it != creds_store_.credentials.end()) { |
| + creds->token = it.GetValue()->token; |
| + creds->auth_provider = it.GetValue()->auth_provider; |
| + creds->scopes = it.GetValue()->scopes; |
| + creds->credential_type = it.GetValue()->credential_type; |
| + } |
| + return creds.Pass(); |
| +} |
| + |
| +mojo::Array<mojo::String> AccountsDbManager::GetAllUsers() { |
| + ensureCredsDbInit(); |
| + |
| + mojo::Array<mojo::String> users = |
| + mojo::Array<mojo::String>::New(creds_store_.credentials.size()); |
| + size_t i = 0; |
| + for (auto it = creds_store_.credentials.begin(); |
| + it != creds_store_.credentials.end(); it++) { |
|
qsr
2016/03/04 15:06:45
Why not use a for each loop? Doesn't it work on mo
ukode
2016/03/11 22:48:52
I get this error on using for each: indirection re
|
| + users[i++] = it.GetKey().get(); |
| + } |
| + return users.Pass(); |
| +} |
| + |
| +void AccountsDbManager::UpdateCredentials( |
| + const mojo::String& username, |
| + const authentication::CredentialsPtr creds) { |
| + ensureCredsDbInit(); |
| + |
| + if (username.is_null()) { |
| + return; |
| + } |
| + |
| + // Set the creds db version |
| + if (!creds_store_.version) { |
| + creds_store_.version = kCredsDbVersion; |
|
qsr
2016/03/04 15:06:45
This should be done during init.
ukode
2016/03/11 22:48:51
Done.
|
| + } |
| + |
| + // Update contents cache with new data |
| + creds_store_.credentials[username] = authentication::Credentials::New(); |
| + creds_store_.credentials[username]->token = creds->token; |
| + creds_store_.credentials[username]->auth_provider = creds->auth_provider; |
| + creds_store_.credentials[username]->scopes = creds->scopes; |
| + creds_store_.credentials[username]->credential_type = creds->credential_type; |
| + |
| + size_t buf_size = creds_store_.GetSerializedSize(); |
| + char buf[buf_size]; |
| + MOJO_CHECK(creds_store_.Serialize(buf, buf_size)); |
| + |
| + std::vector<uint8_t> bytes_to_write(buf, buf + buf_size); |
| + mojo::files::Whence whence; |
| + whence = mojo::files::Whence::FROM_START; |
| + |
| + creds_db_file_->Write( |
| + mojo::Array<uint8_t>::From(bytes_to_write), 0, whence, |
| + [this](mojo::files::Error error, uint32_t num_bytes_written) { |
| + this->OnCredFileWriteResponse(error, num_bytes_written); |
| + }); |
| +} |
| + |
| +void AccountsDbManager::OnCredFileWriteResponse( |
| + const mojo::files::Error error, |
| + const uint32_t num_bytes_written) { |
| + if (mojo::files::Error::OK != error) { |
| + LOG(ERROR) << "Write() error on accounts db:" << error; |
| + delete this; |
| + return; |
| + } |
| +} |
| + |
| +void AccountsDbManager::ensureCredsDbInit() { |
| + if ((db_init_option_ & CREDS_DB_INIT_SUCCESS) != CREDS_DB_INIT_SUCCESS) { |
| + CHECK(creds_db_file_.WaitForIncomingResponse()); |
| + } |
| +} |
| + |
| +void AccountsDbManager::ensureAuthDbInit() { |
| + if ((db_init_option_ & AUTH_DB_INIT_SUCCESS) != AUTH_DB_INIT_SUCCESS) { |
| + CHECK(auth_db_file_.WaitForIncomingResponse()); |
| + } |
| +} |
| + |
| +void AccountsDbManager::Initialize() { |
| + auth_grants_.version = kAuthDbVersion; |
|
qsr
2016/03/04 15:06:45
Why is this necessary? Shouldn't you do this when
ukode
2016/03/11 22:48:51
Done, moved it below inside file read operation.
|
| + |
| + const size_t kMaxReadSize = 1 * 1024 * 1024; |
| + mojo::Array<uint8_t> cred_bytes_read; |
| + creds_db_file_->Read( |
| + kMaxReadSize - 1, 0, mojo::files::Whence::FROM_START, |
| + [this](mojo::files::Error error, mojo::Array<uint8_t> cred_bytes_read) { |
| + this->OnCredFileReadResponse(error, cred_bytes_read.Pass()); |
| + }); |
| + |
| + mojo::Array<uint8_t> auth_bytes_read; |
| + auth_db_file_->Read( |
| + kMaxReadSize - 1, 0, mojo::files::Whence::FROM_START, |
| + [this](mojo::files::Error error, mojo::Array<uint8_t> auth_bytes_read) { |
| + this->OnAuthFileReadResponse(error, auth_bytes_read.Pass()); |
| + }); |
| +} |
| + |
| +void AccountsDbManager::OnCredFileReadResponse( |
| + const mojo::files::Error error, |
| + const mojo::Array<uint8_t> bytes_read) { |
| + if (error != mojo::files::Error::OK) { |
| + LOG(ERROR) << "Read() error on accounts db: " << error; |
| + delete this; |
| + return; |
| + } |
| + |
| + if (bytes_read.size() != 0) { |
| + // Deserialize data from file |
| + const char* data = reinterpret_cast<const char*>(&bytes_read[0]); |
| + creds_store_.Deserialize((void*)data); |
| + CHECK_EQ(creds_store_.version, kCredsDbVersion); |
|
qsr
2016/03/04 15:06:45
Maybe put a comment that when we have multiple ver
ukode
2016/03/11 22:48:51
Acknowledged.
|
| + CHECK(creds_store_.credentials.size() > 0); |
|
qsr
2016/03/04 15:06:45
Why do you have this check? Isn't it possible that
ukode
2016/03/11 22:48:52
Good catch. Yes, that's possible. Removed the chec
|
| + } |
| + |
| + db_init_option_ |= CREDS_DB_INIT_SUCCESS; |
| +} |
| + |
| +void AccountsDbManager::OnAuthFileReadResponse( |
| + const mojo::files::Error error, |
| + const mojo::Array<uint8_t> bytes_read) { |
| + if (error != mojo::files::Error::OK) { |
| + LOG(ERROR) << "Read() error on auth db: " << error; |
| + delete this; |
| + return; |
| + } |
| + |
| + if (bytes_read.size() != 0) { |
| + // Deserialize data from file |
| + const char* data = reinterpret_cast<const char*>(&bytes_read[0]); |
| + auth_grants_.Deserialize((void*)data); |
|
qsr
2016/03/04 15:06:45
You want to use Validate before calling Deserializ
ukode
2016/03/11 22:48:52
Done.
|
| + CHECK_EQ(auth_grants_.version, kAuthDbVersion); |
| + CHECK(!auth_grants_.last_selected_accounts.is_null()); |
| + } |
| + |
| + db_init_option_ |= AUTH_DB_INIT_SUCCESS; |
| +} |
| + |
| +mojo::String AccountsDbManager::GetAuthorizedUserForApp(mojo::String app_url) { |
| + ensureAuthDbInit(); |
| + |
| + if (app_url.is_null()) { |
| + return nullptr; |
| + } |
| + auto it = auth_grants_.last_selected_accounts.find(app_url); |
| + if (it == auth_grants_.last_selected_accounts.end()) { |
| + return nullptr; |
| + } |
| + return mojo::String(it.GetValue()); |
| +} |
| + |
| +void AccountsDbManager::UpdateAuthorization(mojo::String app_url, |
| + mojo::String username) { |
| + if (app_url.is_null() || username.is_null()) { |
| + return; |
| + } |
| + auth_grants_.last_selected_accounts[app_url] = username; |
| + |
| + size_t buf_size = auth_grants_.GetSerializedSize(); |
| + char buf[buf_size]; |
|
qsr
2016/03/04 15:06:45
Why not directly creating a mojo::Array<uint8_t> o
ukode
2016/03/11 22:48:51
Done.
|
| + MOJO_CHECK(auth_grants_.Serialize(buf, buf_size)); |
| + |
| + std::vector<uint8_t> bytes_to_write(buf, buf + buf_size); |
| + mojo::files::Whence whence; |
| + whence = mojo::files::Whence::FROM_START; |
| + |
| + auth_db_file_->Write( |
| + mojo::Array<uint8_t>::From(bytes_to_write), 0, whence, |
| + [this](mojo::files::Error error, uint32_t num_bytes_written) { |
| + this->OnAuthFileWriteResponse(error, num_bytes_written); |
| + }); |
| +} |
| + |
| +void AccountsDbManager::OnAuthFileWriteResponse( |
| + const mojo::files::Error error, |
| + const uint32_t num_bytes_written) { |
| + if (mojo::files::Error::OK != error) { |
| + LOG(ERROR) << "Write() error on auth db:" << error; |
| + delete this; |
| + return; |
| + } |
| +} |
| + |
| +} // namespace authentication |