OLD | NEW |
(Empty) | |
| 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 |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "services/authentication/accounts_db_manager.h" |
| 6 |
| 7 #include <vector> |
| 8 |
| 9 #include "base/logging.h" |
| 10 #include "base/strings/string_tokenizer.h" |
| 11 #include "mojo/public/cpp/bindings/array.h" |
| 12 #include "mojo/public/cpp/bindings/type_converter.h" |
| 13 #include "mojo/services/files/interfaces/files.mojom.h" |
| 14 #include "services/authentication/authentication_impl_db.mojom.h" |
| 15 #include "services/authentication/credentials_impl_db.mojom.h" |
| 16 |
| 17 namespace authentication { |
| 18 |
| 19 char kAccountsDbFileName[] = "creds_db"; |
| 20 char kAuthDbFileName[] = "auth_db"; |
| 21 const uint32 kAuthDbVersion = 1; |
| 22 const uint32 kCredsDbVersion = 1; |
| 23 |
| 24 AccountsDbManager::AccountsDbManager(const mojo::files::DirectoryPtr directory) |
| 25 : creds_db_file_(nullptr), auth_db_file_(nullptr) { |
| 26 // Initialize in-memory contents from existing DB file |
| 27 directory->OpenFile( |
| 28 kAccountsDbFileName, GetProxy(&creds_db_file_), |
| 29 mojo::files::kOpenFlagCreate | mojo::files::kOpenFlagRead | |
| 30 mojo::files::kOpenFlagWrite, |
| 31 [this](mojo::files::Error error) { |
| 32 if (mojo::files::Error::OK != error) { |
| 33 LOG(ERROR) << "Open() error on credentials db:" << error; |
| 34 error_ = CREDENTIALS_DB_READ_ERROR; |
| 35 return; |
| 36 } |
| 37 }); |
| 38 directory->OpenFile(kAuthDbFileName, GetProxy(&auth_db_file_), |
| 39 mojo::files::kOpenFlagCreate | |
| 40 mojo::files::kOpenFlagRead | |
| 41 mojo::files::kOpenFlagWrite, |
| 42 [this](mojo::files::Error error) { |
| 43 if (mojo::files::Error::OK != error) { |
| 44 LOG(ERROR) << "Open() error on auth db:" << error; |
| 45 error_ = AUTHORIZATIONS_DB_READ_ERROR; |
| 46 return; |
| 47 } |
| 48 }); |
| 49 |
| 50 Initialize(); |
| 51 } |
| 52 |
| 53 AccountsDbManager::~AccountsDbManager() {} |
| 54 |
| 55 bool AccountsDbManager::isValid() { |
| 56 return error_ == NONE; |
| 57 } |
| 58 |
| 59 authentication::CredentialsPtr AccountsDbManager::GetCredentials( |
| 60 const mojo::String& username) { |
| 61 ensureCredentialsDbInit(); |
| 62 CHECK(error_ == NONE); |
| 63 |
| 64 authentication::CredentialsPtr creds = authentication::Credentials::New(); |
| 65 if (username.is_null()) { |
| 66 return creds.Pass(); |
| 67 } |
| 68 |
| 69 auto it = creds_store_.credentials.find(username); |
| 70 if (it != creds_store_.credentials.end()) { |
| 71 creds->token = it.GetValue()->token; |
| 72 creds->auth_provider = it.GetValue()->auth_provider; |
| 73 creds->scopes = it.GetValue()->scopes; |
| 74 creds->credential_type = it.GetValue()->credential_type; |
| 75 } |
| 76 return creds.Pass(); |
| 77 } |
| 78 |
| 79 mojo::Array<mojo::String> AccountsDbManager::GetAllUsers() { |
| 80 ensureCredentialsDbInit(); |
| 81 CHECK(error_ == NONE); |
| 82 |
| 83 mojo::Array<mojo::String> users = |
| 84 mojo::Array<mojo::String>::New(creds_store_.credentials.size()); |
| 85 size_t i = 0; |
| 86 |
| 87 for (auto it = creds_store_.credentials.begin(); |
| 88 it != creds_store_.credentials.end(); it++) { |
| 89 users[i++] = it.GetKey().get(); |
| 90 } |
| 91 |
| 92 return users.Pass(); |
| 93 } |
| 94 |
| 95 void AccountsDbManager::UpdateCredentials( |
| 96 const mojo::String& username, |
| 97 const authentication::CredentialsPtr creds) { |
| 98 ensureCredentialsDbInit(); |
| 99 CHECK(error_ == NONE); |
| 100 |
| 101 if (username.is_null()) { |
| 102 return; |
| 103 } |
| 104 |
| 105 // Update contents cache with new data |
| 106 creds_store_.credentials[username] = authentication::Credentials::New(); |
| 107 creds_store_.credentials[username]->token = creds->token; |
| 108 creds_store_.credentials[username]->auth_provider = creds->auth_provider; |
| 109 creds_store_.credentials[username]->scopes = creds->scopes; |
| 110 creds_store_.credentials[username]->credential_type = creds->credential_type; |
| 111 |
| 112 size_t buf_size = creds_store_.GetSerializedSize(); |
| 113 auto bytes_to_write = mojo::Array<uint8_t>::New(buf_size); |
| 114 MOJO_CHECK(creds_store_.Serialize(&bytes_to_write.front(), buf_size)); |
| 115 |
| 116 mojo::files::Whence whence; |
| 117 whence = mojo::files::Whence::FROM_START; |
| 118 creds_db_file_->Write( |
| 119 bytes_to_write.Pass(), 0, whence, |
| 120 [this](mojo::files::Error error, uint32_t num_bytes_written) { |
| 121 this->OnCredentialsFileWriteResponse(error, num_bytes_written); |
| 122 }); |
| 123 } |
| 124 |
| 125 void AccountsDbManager::OnCredentialsFileWriteResponse( |
| 126 const mojo::files::Error error, |
| 127 const uint32_t num_bytes_written) { |
| 128 CHECK(error_ == NONE); |
| 129 |
| 130 if (mojo::files::Error::OK != error) { |
| 131 LOG(ERROR) << "Write() error on accounts db:" << error; |
| 132 error_ = CREDENTIALS_DB_WRITE_ERROR; |
| 133 return; |
| 134 } |
| 135 } |
| 136 |
| 137 void AccountsDbManager::ensureCredentialsDbInit() { |
| 138 if ((db_init_option_ & CREDENTIALS_DB_INIT_SUCCESS) != |
| 139 CREDENTIALS_DB_INIT_SUCCESS) { |
| 140 CHECK(creds_db_file_.WaitForIncomingResponse()); |
| 141 } |
| 142 } |
| 143 |
| 144 void AccountsDbManager::ensureAuthorizationsDbInit() { |
| 145 if ((db_init_option_ & AUTHORIZATIONS_DB_INIT_SUCCESS) != |
| 146 AUTHORIZATIONS_DB_INIT_SUCCESS) { |
| 147 CHECK(auth_db_file_.WaitForIncomingResponse()); |
| 148 } |
| 149 } |
| 150 |
| 151 void AccountsDbManager::Initialize() { |
| 152 CHECK(error_ == NONE); |
| 153 |
| 154 const size_t kMaxReadSize = 1 * 1024 * 1024; |
| 155 mojo::Array<uint8_t> cred_bytes_read; |
| 156 creds_db_file_->Read( |
| 157 kMaxReadSize - 1, 0, mojo::files::Whence::FROM_START, |
| 158 [this](mojo::files::Error error, mojo::Array<uint8_t> cred_bytes_read) { |
| 159 this->OnCredentialsFileReadResponse(error, cred_bytes_read.Pass()); |
| 160 }); |
| 161 |
| 162 mojo::Array<uint8_t> auth_bytes_read; |
| 163 auth_db_file_->Read( |
| 164 kMaxReadSize - 1, 0, mojo::files::Whence::FROM_START, |
| 165 [this](mojo::files::Error error, mojo::Array<uint8_t> auth_bytes_read) { |
| 166 this->OnAuthorizationsFileReadResponse(error, auth_bytes_read.Pass()); |
| 167 }); |
| 168 } |
| 169 |
| 170 void AccountsDbManager::OnCredentialsFileReadResponse( |
| 171 const mojo::files::Error error, |
| 172 const mojo::Array<uint8_t> bytes_read) { |
| 173 CHECK(error_ == NONE); |
| 174 |
| 175 if (error != mojo::files::Error::OK) { |
| 176 LOG(ERROR) << "Read() error on accounts db: " << error; |
| 177 error_ = CREDENTIALS_DB_READ_ERROR; |
| 178 return; |
| 179 } |
| 180 |
| 181 if (bytes_read.size() != 0) { |
| 182 // Deserialize data from file |
| 183 const char* data = reinterpret_cast<const char*>(&bytes_read[0]); |
| 184 |
| 185 // Validate the file contents before deserializing |
| 186 mojo::internal::BoundsChecker bounds_checker(data, bytes_read.size(), 0); |
| 187 std::string error; |
| 188 mojo::internal::ValidationError verror = |
| 189 internal::CredentialStore_Data::Validate(data, &bounds_checker, &error); |
| 190 if (verror != mojo::internal::ValidationError::NONE) { |
| 191 LOG(ERROR) << "Validation() error on accounts db [" |
| 192 << ValidationErrorToString(verror) << "][" << error << "]"; |
| 193 error_ = CREDENTIALS_DB_VALIDATE_ERROR; |
| 194 return; |
| 195 } |
| 196 |
| 197 creds_store_.Deserialize((void*)data); |
| 198 // When we have multiple versions, this is not a fatal error, but a sign |
| 199 // that we need to update (or reinitialize) the db. |
| 200 CHECK_EQ(creds_store_.version, kCredsDbVersion); |
| 201 } else { |
| 202 creds_store_.version = kCredsDbVersion; |
| 203 } |
| 204 |
| 205 db_init_option_ |= CREDENTIALS_DB_INIT_SUCCESS; |
| 206 } |
| 207 |
| 208 void AccountsDbManager::OnAuthorizationsFileReadResponse( |
| 209 const mojo::files::Error error, |
| 210 const mojo::Array<uint8_t> bytes_read) { |
| 211 CHECK(error_ == NONE); |
| 212 |
| 213 if (error != mojo::files::Error::OK) { |
| 214 LOG(ERROR) << "Read() error on auth db: " << error; |
| 215 error_ = AUTHORIZATIONS_DB_READ_ERROR; |
| 216 return; |
| 217 } |
| 218 |
| 219 if (bytes_read.size() != 0) { |
| 220 // Deserialize data from file |
| 221 const char* data = reinterpret_cast<const char*>(&bytes_read[0]); |
| 222 |
| 223 // Validate the file contents before deserializing |
| 224 mojo::internal::BoundsChecker bounds_checker(data, bytes_read.size(), 0); |
| 225 if (internal::Db_Data::Validate(data, &bounds_checker, nullptr) != |
| 226 mojo::internal::ValidationError::NONE) { |
| 227 LOG(ERROR) << "Validation() error on auth db."; |
| 228 error_ = AUTHORIZATIONS_DB_VALIDATE_ERROR; |
| 229 return; |
| 230 } |
| 231 |
| 232 auth_grants_.Deserialize((void*)data); |
| 233 // When we have multiple versions, this is not a fatal error, but a sign |
| 234 // that we need to update (or reinitialize) the db. |
| 235 CHECK_EQ(auth_grants_.version, kAuthDbVersion); |
| 236 } else { |
| 237 auth_grants_.version = kAuthDbVersion; |
| 238 } |
| 239 |
| 240 db_init_option_ |= AUTHORIZATIONS_DB_INIT_SUCCESS; |
| 241 } |
| 242 |
| 243 mojo::String AccountsDbManager::GetAuthorizedUserForApp(mojo::String app_url) { |
| 244 ensureAuthorizationsDbInit(); |
| 245 CHECK(error_ == NONE); |
| 246 |
| 247 if (app_url.is_null()) { |
| 248 return nullptr; |
| 249 } |
| 250 auto it = auth_grants_.last_selected_accounts.find(app_url); |
| 251 if (it == auth_grants_.last_selected_accounts.end()) { |
| 252 return nullptr; |
| 253 } |
| 254 return mojo::String(it.GetValue()); |
| 255 } |
| 256 |
| 257 void AccountsDbManager::UpdateAuthorization(mojo::String app_url, |
| 258 mojo::String username) { |
| 259 ensureAuthorizationsDbInit(); |
| 260 CHECK(error_ == NONE); |
| 261 |
| 262 if (app_url.is_null() || username.is_null()) { |
| 263 return; |
| 264 } |
| 265 auth_grants_.last_selected_accounts[app_url] = username; |
| 266 |
| 267 size_t buf_size = auth_grants_.GetSerializedSize(); |
| 268 auto bytes_to_write = mojo::Array<uint8_t>::New(buf_size); |
| 269 MOJO_CHECK(auth_grants_.Serialize(&bytes_to_write.front(), buf_size)); |
| 270 |
| 271 mojo::files::Whence whence; |
| 272 whence = mojo::files::Whence::FROM_START; |
| 273 auth_db_file_->Write( |
| 274 bytes_to_write.Pass(), 0, whence, |
| 275 [this](mojo::files::Error error, uint32_t num_bytes_written) { |
| 276 this->OnAuthorizationsFileWriteResponse(error, num_bytes_written); |
| 277 }); |
| 278 } |
| 279 |
| 280 void AccountsDbManager::OnAuthorizationsFileWriteResponse( |
| 281 const mojo::files::Error error, |
| 282 const uint32_t num_bytes_written) { |
| 283 CHECK(error_ == NONE); |
| 284 |
| 285 if (mojo::files::Error::OK != error) { |
| 286 LOG(ERROR) << "Write() error on auth db:" << error; |
| 287 error_ = AUTHORIZATIONS_DB_WRITE_ERROR; |
| 288 return; |
| 289 } |
| 290 } |
| 291 |
| 292 } // namespace authentication |
OLD | NEW |