aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorVitaly Buka <vitalybuka@google.com>2015-12-17 20:57:01 -0800
committerVitaly Buka <vitalybuka@google.com>2015-12-21 19:25:33 +0000
commitfd2ef6869df7fdd2eb32e17bd7854df478b1f031 (patch)
treed167887273643e2f14dff79d2c49c44419c2aa43 /src
parent29bd07079198a78c59f2d8964d66e98ca0613c68 (diff)
downloadlibweave-fd2ef6869df7fdd2eb32e17bd7854df478b1f031.tar.gz
Move most of auth logic into SecurityDelegate::CreateAccessToken
With local auth we will need to extract most of information from macaroon auth code. BUG=25768507 Change-Id: If7b31a1ba9a081dfae0cf8e9df6c8ed27bfe79c4 Reviewed-on: https://weave-review.googlesource.com/2049 Reviewed-by: Vitaly Buka <vitalybuka@google.com>
Diffstat (limited to 'src')
-rw-r--r--src/privet/mock_delegates.h17
-rw-r--r--src/privet/privet_handler.cc73
-rw-r--r--src/privet/privet_handler.h1
-rw-r--r--src/privet/privet_handler_unittest.cc20
-rw-r--r--src/privet/security_delegate.h9
-rw-r--r--src/privet/security_manager.cc44
-rw-r--r--src/privet/security_manager.h10
-rw-r--r--src/privet/security_manager_unittest.cc26
8 files changed, 132 insertions, 68 deletions
diff --git a/src/privet/mock_delegates.h b/src/privet/mock_delegates.h
index bc7ec93..1586846 100644
--- a/src/privet/mock_delegates.h
+++ b/src/privet/mock_delegates.h
@@ -62,8 +62,14 @@ class MockDeviceDelegate : public DeviceDelegate {
class MockSecurityDelegate : public SecurityDelegate {
public:
- MOCK_CONST_METHOD2(CreateAccessToken,
- std::string(const UserInfo&, base::TimeDelta));
+ MOCK_METHOD7(CreateAccessToken,
+ bool(AuthType,
+ const std::string&,
+ AuthScope,
+ std::string*,
+ AuthScope*,
+ base::TimeDelta*,
+ ErrorPtr*));
MOCK_CONST_METHOD3(ParseAccessToken,
bool(const std::string&, UserInfo*, ErrorPtr*));
MOCK_CONST_METHOD0(GetPairingTypes, std::set<PairingType>());
@@ -84,8 +90,11 @@ class MockSecurityDelegate : public SecurityDelegate {
MOCK_METHOD0(CreateSessionId, std::string());
MockSecurityDelegate() {
- EXPECT_CALL(*this, CreateAccessToken(_, _))
- .WillRepeatedly(Return("GuestAccessToken"));
+ EXPECT_CALL(*this, CreateAccessToken(_, _, _, _, _, _, _))
+ .WillRepeatedly(DoAll(
+ SetArgPointee<3>("GuestAccessToken"),
+ SetArgPointee<4>(AuthScope::kViewer),
+ SetArgPointee<5>(base::TimeDelta::FromSeconds(15)), Return(true)));
EXPECT_CALL(*this, ClaimRootClientAuthToken(_))
.WillRepeatedly(Return("RootClientAuthToken"));
diff --git a/src/privet/privet_handler.cc b/src/privet/privet_handler.cc
index b55053d..ef0c54e 100644
--- a/src/privet/privet_handler.cc
+++ b/src/privet/privet_handler.cc
@@ -116,8 +116,6 @@ const char kWaitTimeoutKey[] = "waitTimeout";
const char kInvalidParamValueFormat[] = "Invalid parameter: '%s'='%s'";
-const int kAccessTokenExpirationSeconds = 3600;
-
template <class Container>
std::unique_ptr<base::ListValue> ToValue(const Container& list) {
std::unique_ptr<base::ListValue> value_list(new base::ListValue());
@@ -151,14 +149,6 @@ struct {
{errors::kAlreadyClaimed, http::kDenied},
};
-AuthScope AuthScopeFromString(const std::string& scope, AuthScope auto_scope) {
- if (scope == kAuthScopeAutoValue)
- return auto_scope;
- AuthScope scope_id = AuthScope::kNone;
- StringToEnum(scope, &scope_id);
- return scope_id;
-}
-
std::string GetAuthTokenFromAuthHeader(const std::string& auth_header) {
return SplitAtFirst(auth_header, " ", true).second;
}
@@ -684,58 +674,49 @@ void PrivetHandler::HandleAuth(const base::DictionaryValue& input,
return ReturnError(*error, callback);
}
- std::string auth_code;
- input.GetString(kAuthCodeKey, &auth_code);
+ AuthScope desired_scope = AuthScope::kOwner;
+ AuthScope acceptable_scope = AuthScope::kViewer;
- AuthScope max_auth_scope = AuthScope::kNone;
- switch (auth_type) {
- case AuthType::kAnonymous:
- max_auth_scope = GetAnonymousMaxScope(*cloud_, wifi_);
- break;
- case AuthType::kPairing:
- if (!security_->IsValidPairingCode(auth_code)) {
- Error::AddToPrintf(&error, FROM_HERE, errors::kDomain,
- errors::kInvalidAuthCode, kInvalidParamValueFormat,
- kAuthCodeKey, auth_code.c_str());
- return ReturnError(*error, callback);
- }
- max_auth_scope = AuthScope::kOwner;
- break;
- default:
+ std::string requested_scope;
+ input.GetString(kAuthRequestedScopeKey, &requested_scope);
+ if (requested_scope != kAuthScopeAutoValue) {
+ if (!StringToEnum(requested_scope, &desired_scope)) {
Error::AddToPrintf(&error, FROM_HERE, errors::kDomain,
- errors::kInvalidAuthMode, kInvalidParamValueFormat,
- kAuthModeKey, auth_code_type.c_str());
+ errors::kInvalidRequestedScope,
+ kInvalidParamValueFormat, kAuthRequestedScopeKey,
+ requested_scope.c_str());
return ReturnError(*error, callback);
+ }
+ acceptable_scope = std::max(desired_scope, acceptable_scope);
}
- std::string requested_scope;
- input.GetString(kAuthRequestedScopeKey, &requested_scope);
+ if (auth_type == AuthType::kAnonymous)
+ desired_scope = GetAnonymousMaxScope(*cloud_, wifi_);
- AuthScope requested_auth_scope =
- AuthScopeFromString(requested_scope, max_auth_scope);
- if (requested_auth_scope == AuthScope::kNone) {
- Error::AddToPrintf(&error, FROM_HERE, errors::kDomain,
- errors::kInvalidRequestedScope, kInvalidParamValueFormat,
- kAuthRequestedScopeKey, requested_scope.c_str());
+ std::string auth_code;
+ input.GetString(kAuthCodeKey, &auth_code);
+
+ std::string access_token;
+ base::TimeDelta access_token_ttl;
+ AuthScope access_token_scope = AuthScope::kNone;
+ if (!security_->CreateAccessToken(auth_type, auth_code, desired_scope,
+ &access_token, &access_token_scope,
+ &access_token_ttl, &error)) {
return ReturnError(*error, callback);
}
- if (requested_auth_scope > max_auth_scope) {
+ if (access_token_scope < acceptable_scope) {
Error::AddToPrintf(&error, FROM_HERE, errors::kDomain,
errors::kAccessDenied, "Scope '%s' is not allowed",
- EnumToString(requested_auth_scope).c_str());
+ EnumToString(access_token_scope).c_str());
return ReturnError(*error, callback);
}
base::DictionaryValue output;
- output.SetString(
- kAuthAccessTokenKey,
- security_->CreateAccessToken(
- UserInfo{requested_auth_scope, ++last_user_id_},
- base::TimeDelta::FromSeconds(kAccessTokenExpirationSeconds)));
+ output.SetString(kAuthAccessTokenKey, access_token);
output.SetString(kAuthTokenTypeKey, kAuthorizationHeaderPrefix);
- output.SetInteger(kAuthExpiresInKey, kAccessTokenExpirationSeconds);
- output.SetString(kAuthScopeKey, EnumToString(requested_auth_scope));
+ output.SetInteger(kAuthExpiresInKey, access_token_ttl.InSeconds());
+ output.SetString(kAuthScopeKey, EnumToString(access_token_scope));
callback.Run(http::kOk, output);
}
diff --git a/src/privet/privet_handler.h b/src/privet/privet_handler.h
index 646cab2..4eba329 100644
--- a/src/privet/privet_handler.h
+++ b/src/privet/privet_handler.h
@@ -162,7 +162,6 @@ class PrivetHandler : public CloudDelegate::Observer {
std::vector<UpdateRequestParameters> update_requests_;
int last_update_request_id_{0};
- uint64_t last_user_id_{0};
uint64_t state_fingerprint_{1};
uint64_t traits_fingerprint_{1};
uint64_t components_fingerprint_{1};
diff --git a/src/privet/privet_handler_unittest.cc b/src/privet/privet_handler_unittest.cc
index 53f1a05..7c9cf33 100644
--- a/src/privet/privet_handler_unittest.cc
+++ b/src/privet/privet_handler_unittest.cc
@@ -377,8 +377,11 @@ TEST_F(PrivetHandlerTest, AuthErrorAccessDenied) {
}
TEST_F(PrivetHandlerTest, AuthErrorInvalidAuthCode) {
- EXPECT_CALL(security_, IsValidPairingCode("testToken"))
- .WillRepeatedly(Return(false));
+ auto set_error = [](ErrorPtr* error) {
+ Error::AddTo(error, FROM_HERE, errors::kDomain, "invalidAuthCode", "");
+ };
+ EXPECT_CALL(security_, CreateAccessToken(_, "testToken", _, _, _, _, _))
+ .WillRepeatedly(DoAll(WithArgs<6>(Invoke(set_error)), Return(false)));
const char kInput[] = R"({
'mode': 'pairing',
'requestedScope': 'user',
@@ -391,8 +394,8 @@ TEST_F(PrivetHandlerTest, AuthErrorInvalidAuthCode) {
TEST_F(PrivetHandlerTest, AuthAnonymous) {
const char kExpected[] = R"({
'accessToken': 'GuestAccessToken',
- 'expiresIn': 3600,
- 'scope': 'user',
+ 'expiresIn': 15,
+ 'scope': 'viewer',
'tokenType': 'Privet'
})";
EXPECT_JSON_EQ(kExpected,
@@ -403,8 +406,11 @@ TEST_F(PrivetHandlerTest, AuthAnonymous) {
TEST_F(PrivetHandlerTest, AuthPairing) {
EXPECT_CALL(security_, IsValidPairingCode("testToken"))
.WillRepeatedly(Return(true));
- EXPECT_CALL(security_, CreateAccessToken(_, _))
- .WillRepeatedly(Return("OwnerAccessToken"));
+ EXPECT_CALL(security_, CreateAccessToken(_, _, _, _, _, _, _))
+ .WillRepeatedly(DoAll(SetArgPointee<3>("OwnerAccessToken"),
+ SetArgPointee<4>(AuthScope::kOwner),
+ SetArgPointee<5>(base::TimeDelta::FromSeconds(15)),
+ Return(true)));
const char kInput[] = R"({
'mode': 'pairing',
'requestedScope': 'owner',
@@ -412,7 +418,7 @@ TEST_F(PrivetHandlerTest, AuthPairing) {
})";
const char kExpected[] = R"({
'accessToken': 'OwnerAccessToken',
- 'expiresIn': 3600,
+ 'expiresIn': 15,
'scope': 'owner',
'tokenType': 'Privet'
})";
diff --git a/src/privet/security_delegate.h b/src/privet/security_delegate.h
index fdf9a84..c07b782 100644
--- a/src/privet/security_delegate.h
+++ b/src/privet/security_delegate.h
@@ -22,8 +22,13 @@ class SecurityDelegate {
virtual ~SecurityDelegate() {}
// Creates access token for the given scope, user id and |time|.
- virtual std::string CreateAccessToken(const UserInfo& user_info,
- base::TimeDelta ttl) const = 0;
+ virtual bool CreateAccessToken(AuthType auth_type,
+ const std::string& auth_code,
+ AuthScope desired_scope,
+ std::string* access_token,
+ AuthScope* granted_scope,
+ base::TimeDelta* ttl,
+ ErrorPtr* error) = 0;
// Validates |token| and returns scope, user id parsed from that.
virtual bool ParseAccessToken(const std::string& token,
diff --git a/src/privet/security_manager.cc b/src/privet/security_manager.cc
index d2b7b35..b30bb04 100644
--- a/src/privet/security_manager.cc
+++ b/src/privet/security_manager.cc
@@ -36,6 +36,8 @@ const int kPairingExpirationTimeMinutes = 5;
const int kMaxAllowedPairingAttemts = 3;
const int kPairingBlockingTimeMinutes = 1;
+const int kAccessTokenExpirationSeconds = 3600;
+
class Spakep224Exchanger : public SecurityManager::KeyExchanger {
public:
explicit Spakep224Exchanger(const std::string& password)
@@ -109,9 +111,45 @@ SecurityManager::~SecurityManager() {
ClosePendingSession(pending_sessions_.begin()->first);
}
-std::string SecurityManager::CreateAccessToken(const UserInfo& user_info,
- base::TimeDelta ttl) const {
- return Base64Encode(auth_manager_->CreateAccessToken(user_info, ttl));
+bool SecurityManager::CreateAccessToken(AuthType auth_type,
+ const std::string& auth_code,
+ AuthScope desired_scope,
+ std::string* access_token,
+ AuthScope* access_token_scope,
+ base::TimeDelta* access_token_ttl,
+ ErrorPtr* error) {
+ switch (auth_type) {
+ case AuthType::kAnonymous:
+ break;
+ case AuthType::kPairing:
+ if (!IsValidPairingCode(auth_code)) {
+ Error::AddTo(error, FROM_HERE, errors::kDomain,
+ errors::kInvalidAuthCode, "Invalid authCode");
+ return false;
+ }
+ break;
+ default:
+ Error::AddToPrintf(error, FROM_HERE, errors::kDomain,
+ errors::kInvalidAuthMode, "Unsupported auth mode");
+ return false;
+ }
+
+ UserInfo user_info{desired_scope, ++last_user_id_};
+ base::TimeDelta ttl =
+ base::TimeDelta::FromSeconds(kAccessTokenExpirationSeconds);
+
+ if (access_token) {
+ *access_token =
+ Base64Encode(auth_manager_->CreateAccessToken(user_info, ttl));
+ }
+
+ if (access_token_scope)
+ *access_token_scope = user_info.scope();
+
+ if (access_token_ttl)
+ *access_token_ttl = ttl;
+
+ return true;
}
bool SecurityManager::ParseAccessToken(const std::string& token,
diff --git a/src/privet/security_manager.h b/src/privet/security_manager.h
index f65f7bd..beb7955 100644
--- a/src/privet/security_manager.h
+++ b/src/privet/security_manager.h
@@ -60,8 +60,13 @@ class SecurityManager : public SecurityDelegate {
~SecurityManager() override;
// SecurityDelegate methods
- std::string CreateAccessToken(const UserInfo& user_info,
- base::TimeDelta ttl) const override;
+ bool CreateAccessToken(AuthType auth_type,
+ const std::string& auth_code,
+ AuthScope desired_scope,
+ std::string* access_token,
+ AuthScope* granted_scope,
+ base::TimeDelta* ttl,
+ ErrorPtr* error) override;
bool ParseAccessToken(const std::string& token,
UserInfo* user_info,
ErrorPtr* error) const override;
@@ -109,6 +114,7 @@ class SecurityManager : public SecurityDelegate {
mutable base::Time block_pairing_until_;
PairingStartListener on_start_;
PairingEndListener on_end_;
+ uint64_t last_user_id_{0};
base::WeakPtrFactory<SecurityManager> weak_ptr_factory_{this};
diff --git a/src/privet/security_manager_unittest.cc b/src/privet/security_manager_unittest.cc
index f48ec7f..6fc6b4c 100644
--- a/src/privet/security_manager_unittest.cc
+++ b/src/privet/security_manager_unittest.cc
@@ -97,6 +97,19 @@ class SecurityManagerTest : public testing::Test {
std::string auth_code_base64{Base64Encode(auth_code)};
EXPECT_TRUE(security_.IsValidPairingCode(auth_code_base64));
+
+ std::string token;
+ AuthScope scope;
+ base::TimeDelta ttl;
+ EXPECT_TRUE(security_.CreateAccessToken(AuthType::kPairing,
+ auth_code_base64, AuthScope::kOwner,
+ &token, &scope, &ttl, nullptr));
+ EXPECT_EQ(AuthScope::kOwner, scope);
+ EXPECT_EQ(base::TimeDelta::FromHours(1), ttl);
+
+ UserInfo info;
+ EXPECT_TRUE(security_.ParseAccessToken(token, &info, nullptr));
+ EXPECT_EQ(AuthScope::kOwner, info.scope());
}
const base::Time time_ = base::Time::FromTimeT(1410000000);
@@ -119,9 +132,16 @@ class SecurityManagerTest : public testing::Test {
};
TEST_F(SecurityManagerTest, CreateAccessToken) {
- EXPECT_EQ("TV18I+N7cDPah7Nq6o7pl5H7DjDu5nCDf/cbdE4FZFEyOjc6MTQxMDAwMDA2MA==",
- security_.CreateAccessToken(UserInfo{AuthScope::kUser, 7},
- base::TimeDelta::FromMinutes(1)));
+ std::string token;
+ AuthScope scope;
+ base::TimeDelta ttl;
+ EXPECT_TRUE(security_.CreateAccessToken(AuthType::kAnonymous, "",
+ AuthScope::kUser, &token, &scope,
+ &ttl, nullptr));
+ EXPECT_EQ("Cfz+qcndz8/Mo3ytgYlD7zn8qImkkdPsJVUNBmSOiXwyOjE6MTQxMDAwMzYwMA==",
+ token);
+ EXPECT_EQ(AuthScope::kUser, scope);
+ EXPECT_EQ(base::TimeDelta::FromHours(1), ttl);
}
TEST_F(SecurityManagerTest, ParseAccessToken) {