diff options
author | antrim@chromium.org <antrim@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-07-09 21:22:51 +0000 |
---|---|---|
committer | antrim@chromium.org <antrim@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-07-09 21:22:51 +0000 |
commit | 4c40e06ed86c6512ddaa958fdb649d96c2a69286 (patch) | |
tree | 8f4ffe49ea74b0324a7a1846cf97d5d4ae0044da /chromeos/login | |
parent | 8854626b2d073c6f2d80a182088121e156e86c5c (diff) | |
download | chromium_src-4c40e06ed86c6512ddaa958fdb649d96c2a69286.zip chromium_src-4c40e06ed86c6512ddaa958fdb649d96c2a69286.tar.gz chromium_src-4c40e06ed86c6512ddaa958fdb649d96c2a69286.tar.bz2 |
[Athena] Extract Chrome OS authentication stack
Move Key/User context
BUG=387613
TBR=stevenjb@chromium.org
TBR=davemoore@chromium.org
TBR=darin@chromium.org
Review URL: https://codereview.chromium.org/378513005
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@282126 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chromeos/login')
-rw-r--r-- | chromeos/login/DEPS | 4 | ||||
-rw-r--r-- | chromeos/login/auth/key.cc | 114 | ||||
-rw-r--r-- | chromeos/login/auth/key.h | 54 | ||||
-rw-r--r-- | chromeos/login/auth/key_unittest.cc | 47 | ||||
-rw-r--r-- | chromeos/login/auth/user_context.cc | 129 | ||||
-rw-r--r-- | chromeos/login/auth/user_context.h | 74 | ||||
-rw-r--r-- | chromeos/login/user_names.cc | 31 | ||||
-rw-r--r-- | chromeos/login/user_names.h | 45 |
8 files changed, 498 insertions, 0 deletions
diff --git a/chromeos/login/DEPS b/chromeos/login/DEPS new file mode 100644 index 0000000..85bd5c2 --- /dev/null +++ b/chromeos/login/DEPS @@ -0,0 +1,4 @@ +include_rules = [ + "+components/user_manager", + "+google_apis", +] diff --git a/chromeos/login/auth/key.cc b/chromeos/login/auth/key.cc new file mode 100644 index 0000000..099659b --- /dev/null +++ b/chromeos/login/auth/key.cc @@ -0,0 +1,114 @@ +// Copyright 2014 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 "chromeos/login/auth/key.h" + +#include "base/base64.h" +#include "base/logging.h" +#include "base/memory/scoped_ptr.h" +#include "base/strings/string_number_conversions.h" +#include "base/strings/string_util.h" +#include "crypto/sha2.h" +#include "crypto/symmetric_key.h" + +namespace chromeos { + +namespace { + +// Parameters for the transformation to KEY_TYPE_SALTED_AES256_1234. +const int kNumIterations = 1234; +const int kKeySizeInBits = 256; + +} // namespace + +Key::Key() : key_type_(KEY_TYPE_PASSWORD_PLAIN) { +} + +Key::Key(const Key& other) + : key_type_(other.key_type_), + salt_(other.salt_), + secret_(other.secret_), + label_(other.label_) { +} + +Key::Key(const std::string& plain_text_password) + : key_type_(KEY_TYPE_PASSWORD_PLAIN), secret_(plain_text_password) { +} + +Key::Key(KeyType key_type, const std::string& salt, const std::string& secret) + : key_type_(key_type), salt_(salt), secret_(secret) { +} + +Key::~Key() { +} + +bool Key::operator==(const Key& other) const { + return other.key_type_ == key_type_ && other.salt_ == salt_ && + other.secret_ == secret_ && other.label_ == label_; +} + +Key::KeyType Key::GetKeyType() const { + return key_type_; +} + +const std::string& Key::GetSecret() const { + return secret_; +} + +const std::string& Key::GetLabel() const { + return label_; +} + +void Key::SetLabel(const std::string& label) { + label_ = label; +} + +void Key::ClearSecret() { + secret_.clear(); +} + +void Key::Transform(KeyType target_key_type, const std::string& salt) { + if (key_type_ != KEY_TYPE_PASSWORD_PLAIN) { + NOTREACHED(); + return; + } + + switch (target_key_type) { + case KEY_TYPE_SALTED_SHA256_TOP_HALF: { + // TODO(stevenjb/nkostylev): Handle empty salt gracefully. + CHECK(!salt.empty()); + char hash[crypto::kSHA256Length]; + crypto::SHA256HashString(salt + secret_, &hash, sizeof(hash)); + + // Keep only the first half of the hash for 'weak' hashing so that the + // plain text secret cannot be reconstructed even if the hashing is + // reversed. + secret_ = StringToLowerASCII(base::HexEncode( + reinterpret_cast<const void*>(hash), sizeof(hash) / 2)); + break; + } + case KEY_TYPE_SALTED_PBKDF2_AES256_1234: { + scoped_ptr<crypto::SymmetricKey> key( + crypto::SymmetricKey::DeriveKeyFromPassword(crypto::SymmetricKey::AES, + secret_, + salt, + kNumIterations, + kKeySizeInBits)); + std::string raw_secret; + key->GetRawKey(&raw_secret); + base::Base64Encode(raw_secret, &secret_); + break; + } + default: + // The resulting key will be sent to cryptohomed. It should always be + // hashed. If hashing fails, crash instead of sending a plain-text key. + CHECK(false); + return; + } + + key_type_ = target_key_type; + salt_ = salt; +} + +} // namespace chromeos diff --git a/chromeos/login/auth/key.h b/chromeos/login/auth/key.h new file mode 100644 index 0000000..8aee6dd --- /dev/null +++ b/chromeos/login/auth/key.h @@ -0,0 +1,54 @@ +// Copyright 2014 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. + +#ifndef CHROMEOS_LOGIN_AUTH_KEY_H_ +#define CHROMEOS_LOGIN_AUTH_KEY_H_ + +#include <string> + +#include "chromeos/chromeos_export.h" + +namespace chromeos { + +// Key for user authentication. The class supports hashing of plain text +// passwords to generate keys as well as the use of pre-hashed keys. +class CHROMEOS_EXPORT Key { + public: + enum KeyType { + // Plain text password. + KEY_TYPE_PASSWORD_PLAIN, + // SHA256 of salt + password, first half only, lower-case hex encoded. + KEY_TYPE_SALTED_SHA256_TOP_HALF, + // PBKDF2 with 256 bit AES and 1234 iterations, base64 encoded. + KEY_TYPE_SALTED_PBKDF2_AES256_1234, + }; + + Key(); + Key(const Key& other); + explicit Key(const std::string& plain_text_password); + Key(KeyType key_type, const std::string& salt, const std::string& secret); + ~Key(); + + bool operator==(const Key& other) const; + + KeyType GetKeyType() const; + const std::string& GetSecret() const; + const std::string& GetLabel() const; + + void SetLabel(const std::string& label); + + void ClearSecret(); + + void Transform(KeyType target_key_type, const std::string& salt); + + private: + KeyType key_type_; + std::string salt_; + std::string secret_; + std::string label_; +}; + +} // namespace chromeos + +#endif // CHROMEOS_LOGIN_AUTH_KEY_H_ diff --git a/chromeos/login/auth/key_unittest.cc b/chromeos/login/auth/key_unittest.cc new file mode 100644 index 0000000..76e38cb --- /dev/null +++ b/chromeos/login/auth/key_unittest.cc @@ -0,0 +1,47 @@ +// Copyright 2014 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 "chromeos/login/auth/key.h" + +#include "testing/gtest/include/gtest/gtest.h" + +namespace chromeos { + +namespace { + +const char kPassword[] = "password"; +const char kLabel[] = "label"; +const char kSalt[] = + "deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef"; + +} // namespace + +TEST(KeyTest, ClearSecret) { + Key key(kPassword); + key.SetLabel(kLabel); + EXPECT_EQ(Key::KEY_TYPE_PASSWORD_PLAIN, key.GetKeyType()); + EXPECT_EQ(kPassword, key.GetSecret()); + EXPECT_EQ(kLabel, key.GetLabel()); + + key.ClearSecret(); + EXPECT_EQ(Key::KEY_TYPE_PASSWORD_PLAIN, key.GetKeyType()); + EXPECT_TRUE(key.GetSecret().empty()); + EXPECT_EQ(kLabel, key.GetLabel()); +} + +TEST(KeyTest, TransformToSaltedSHA256TopHalf) { + Key key(kPassword); + key.Transform(Key::KEY_TYPE_SALTED_SHA256_TOP_HALF, kSalt); + EXPECT_EQ(Key::KEY_TYPE_SALTED_SHA256_TOP_HALF, key.GetKeyType()); + EXPECT_EQ("5b01941771e47fa408380aa675703f4f", key.GetSecret()); +} + +TEST(KeyTest, TransformToSaltedAES2561234) { + Key key(kPassword); + key.Transform(Key::KEY_TYPE_SALTED_PBKDF2_AES256_1234, kSalt); + EXPECT_EQ(Key::KEY_TYPE_SALTED_PBKDF2_AES256_1234, key.GetKeyType()); + EXPECT_EQ("GUkNnvqoULf/cXbZscVUnANmLBB0ovjGZsj1sKzP5BE=", key.GetSecret()); +} + +} // namespace chromeos diff --git a/chromeos/login/auth/user_context.cc b/chromeos/login/auth/user_context.cc new file mode 100644 index 0000000..78f12bc --- /dev/null +++ b/chromeos/login/auth/user_context.cc @@ -0,0 +1,129 @@ +// Copyright 2014 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 "chromeos/login/auth/user_context.h" +#include "chromeos/login/user_names.h" + +namespace chromeos { + +UserContext::UserContext() + : is_using_oauth_(true), + auth_flow_(AUTH_FLOW_OFFLINE), + user_type_(user_manager::USER_TYPE_REGULAR) { +} + +UserContext::UserContext(const UserContext& other) + : user_id_(other.user_id_), + key_(other.key_), + auth_code_(other.auth_code_), + user_id_hash_(other.user_id_hash_), + is_using_oauth_(other.is_using_oauth_), + auth_flow_(other.auth_flow_), + user_type_(other.user_type_) { +} + +UserContext::UserContext(const std::string& user_id) + : user_id_(login::CanonicalizeUserID(user_id)), + is_using_oauth_(true), + auth_flow_(AUTH_FLOW_OFFLINE), + user_type_(user_manager::USER_TYPE_REGULAR) { +} + +UserContext::UserContext(user_manager::UserType user_type, + const std::string& user_id) + : is_using_oauth_(true), + auth_flow_(AUTH_FLOW_OFFLINE), + user_type_(user_type) { + if (user_type_ == user_manager::USER_TYPE_REGULAR) + user_id_ = login::CanonicalizeUserID(user_id); + else + user_id_ = user_id; +} + +UserContext::~UserContext() { +} + +bool UserContext::operator==(const UserContext& context) const { + return context.user_id_ == user_id_ && context.key_ == key_ && + context.auth_code_ == auth_code_ && + context.user_id_hash_ == user_id_hash_ && + context.is_using_oauth_ == is_using_oauth_ && + context.auth_flow_ == auth_flow_ && context.user_type_ == user_type_; +} + +bool UserContext::operator!=(const UserContext& context) const { + return !(*this == context); +} + +const std::string& UserContext::GetUserID() const { + return user_id_; +} + +const Key* UserContext::GetKey() const { + return &key_; +} + +Key* UserContext::GetKey() { + return &key_; +} + +const std::string& UserContext::GetAuthCode() const { + return auth_code_; +} + +const std::string& UserContext::GetUserIDHash() const { + return user_id_hash_; +} + +bool UserContext::IsUsingOAuth() const { + return is_using_oauth_; +} + +UserContext::AuthFlow UserContext::GetAuthFlow() const { + return auth_flow_; +} + +user_manager::UserType UserContext::GetUserType() const { + return user_type_; +} + +bool UserContext::HasCredentials() const { + return (!user_id_.empty() && !key_.GetSecret().empty()) || + !auth_code_.empty(); +} + +void UserContext::SetUserID(const std::string& user_id) { + user_id_ = login::CanonicalizeUserID(user_id); +} + +void UserContext::SetKey(const Key& key) { + key_ = key; +} + +void UserContext::SetAuthCode(const std::string& auth_code) { + auth_code_ = auth_code; +} + +void UserContext::SetUserIDHash(const std::string& user_id_hash) { + user_id_hash_ = user_id_hash; +} + +void UserContext::SetIsUsingOAuth(bool is_using_oauth) { + is_using_oauth_ = is_using_oauth; +} + +void UserContext::SetAuthFlow(AuthFlow auth_flow) { + auth_flow_ = auth_flow; +} + +void UserContext::SetUserType(user_manager::UserType user_type) { + user_type_ = user_type; +} + +void UserContext::ClearSecrets() { + key_.ClearSecret(); + auth_code_.clear(); +} + +} // namespace chromeos diff --git a/chromeos/login/auth/user_context.h b/chromeos/login/auth/user_context.h new file mode 100644 index 0000000..8382495 --- /dev/null +++ b/chromeos/login/auth/user_context.h @@ -0,0 +1,74 @@ +// Copyright 2014 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. + +#ifndef CHROMEOS_LOGIN_AUTH_USER_CONTEXT_H_ +#define CHROMEOS_LOGIN_AUTH_USER_CONTEXT_H_ + +#include <string> + +#include "chromeos/chromeos_export.h" +#include "chromeos/login/auth/key.h" +#include "components/user_manager/user_type.h" + +namespace chromeos { + +// Information that is passed around while authentication is in progress. The +// credentials may consist of a |user_id_|, |key_| pair or a GAIA |auth_code_|. +// The |user_id_hash_| is used to locate the user's home directory +// mount point for the user. It is set when the mount has been completed. +class CHROMEOS_EXPORT UserContext { + public: + // The authentication flow used during sign-in. + enum AuthFlow { + // Online authentication against GAIA. GAIA did not redirect to a SAML IdP. + AUTH_FLOW_GAIA_WITHOUT_SAML, + // Online authentication against GAIA. GAIA redirected to a SAML IdP. + AUTH_FLOW_GAIA_WITH_SAML, + // Offline authentication against a cached key. + AUTH_FLOW_OFFLINE + }; + + UserContext(); + UserContext(const UserContext& other); + explicit UserContext(const std::string& user_id); + UserContext(user_manager::UserType user_type, const std::string& user_id); + ~UserContext(); + + bool operator==(const UserContext& context) const; + bool operator!=(const UserContext& context) const; + + const std::string& GetUserID() const; + const Key* GetKey() const; + Key* GetKey(); + const std::string& GetAuthCode() const; + const std::string& GetUserIDHash() const; + bool IsUsingOAuth() const; + AuthFlow GetAuthFlow() const; + user_manager::UserType GetUserType() const; + + bool HasCredentials() const; + + void SetUserID(const std::string& user_id); + void SetKey(const Key& key); + void SetAuthCode(const std::string& auth_code); + void SetUserIDHash(const std::string& user_id_hash); + void SetIsUsingOAuth(bool is_using_oauth); + void SetAuthFlow(AuthFlow auth_flow); + void SetUserType(user_manager::UserType user_type); + + void ClearSecrets(); + + private: + std::string user_id_; + Key key_; + std::string auth_code_; + std::string user_id_hash_; + bool is_using_oauth_; + AuthFlow auth_flow_; + user_manager::UserType user_type_; +}; + +} // namespace chromeos + +#endif // CHROMEOS_LOGIN_AUTH_USER_CONTEXT_H_ diff --git a/chromeos/login/user_names.cc b/chromeos/login/user_names.cc new file mode 100644 index 0000000..f8964f9 --- /dev/null +++ b/chromeos/login/user_names.cc @@ -0,0 +1,31 @@ +// Copyright 2014 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 "chromeos/login/user_names.h" + +#include "google_apis/gaia/gaia_auth_util.h" + +namespace chromeos { + +namespace login { + +const char* kStubUser = "stub-user@example.com"; + +const char* kSignInUser = "sign-in-user-id"; + +// Should match cros constant in platform/libchromeos/chromeos/cryptohome.h +const char* kGuestUserName = "$guest"; + +const char* kLocallyManagedUserDomain = "locally-managed.localhost"; + +const char* kRetailModeUserName = "demouser@"; + +std::string CanonicalizeUserID(const std::string& user_id) { + if (user_id == chromeos::login::kGuestUserName) + return user_id; + return gaia::CanonicalizeEmail(user_id); +} + +} // namespace login + +} // namespace chromeos diff --git a/chromeos/login/user_names.h b/chromeos/login/user_names.h new file mode 100644 index 0000000..4c296f7 --- /dev/null +++ b/chromeos/login/user_names.h @@ -0,0 +1,45 @@ +// Copyright 2014 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. + +#ifndef CHROMEOS_LOGIN_USER_NAMES_H_ +#define CHROMEOS_LOGIN_USER_NAMES_H_ + +#include <string> + +#include "chromeos/chromeos_export.h" + +namespace chromeos { + +namespace login { + +// Username for stub login when not running on ChromeOS. +CHROMEOS_EXPORT extern const char* kStubUser; + +// Username for the login screen. It is only used to identify login screen +// tries to set default wallpaper. It is not a real user. +CHROMEOS_EXPORT extern const char* kSignInUser; + +// Magic e-mail addresses are bad. They exist here because some code already +// depends on them and it is hard to figure out what. Any user types added in +// the future should be identified by a new |UserType|, not a new magic e-mail +// address. +// Username for Guest session user. +CHROMEOS_EXPORT extern const char* kGuestUserName; + +// Domain that is used for all locally managed users. +CHROMEOS_EXPORT extern const char* kLocallyManagedUserDomain; + +// The retail mode user has a magic, domainless e-mail address. +CHROMEOS_EXPORT extern const char* kRetailModeUserName; + +// Canonicalizes a GAIA user ID, accounting for the legacy guest mode user ID +// which does trips up gaia::CanonicalizeEmail() because it does not contain an +// @ symbol. +CHROMEOS_EXPORT std::string CanonicalizeUserID(const std::string& user_id); + +} // namespace login + +} // namespace chromeos + +#endif // CHROMEOS_LOGIN_USER_NAMES_H_ |