Return Root Client Authorization Token using /privet/v3/accessControl/* RCAT is returned in /privet/v3/accessControl/claim results. Then client needs to store token and call /privet/v3/accessControl/confirm with original or derived token. Depending on result of confirm call client may: 1. No error - Start using token 2. Request error - retry confirm step 3. Unknown token - claim access again 4. Already claimed error - to late, someone else claimed device BUG=25766815, 26143922 Change-Id: I9d25004e84210142214e6eb0a23d8e3ae7b57d6a Reviewed-on: https://weave-review.googlesource.com/1885 Reviewed-by: Vitaly Buka <vitalybuka@google.com>
diff --git a/src/privet/mock_delegates.h b/src/privet/mock_delegates.h index f671591..9e647e3 100644 --- a/src/privet/mock_delegates.h +++ b/src/privet/mock_delegates.h
@@ -88,6 +88,9 @@ EXPECT_CALL(*this, ClaimRootClientAuthToken(_)) .WillRepeatedly(Return("RootClientAuthToken")); + EXPECT_CALL(*this, ConfirmAuthToken("DerivedClientAuthToken", _)) + .WillRepeatedly(Return(true)); + EXPECT_CALL(*this, ParseAccessToken(_, _)) .WillRepeatedly(DoAll(SetArgPointee<1>(base::Time::Now()), Return(UserInfo{AuthScope::kViewer, 1234567})));
diff --git a/src/privet/privet_handler.cc b/src/privet/privet_handler.cc index 377888f..d1be61a 100644 --- a/src/privet/privet_handler.cc +++ b/src/privet/privet_handler.cc
@@ -17,6 +17,7 @@ #include <weave/enum_to_string.h> #include <weave/provider/task_runner.h> +#include "src/config.h" #include "src/http_constants.h" #include "src/privet/cloud_delegate.h" #include "src/privet/constants.h" @@ -90,6 +91,7 @@ const char kAuthTokenTypeKey[] = "tokenType"; const char kAuthExpiresInKey[] = "expiresIn"; const char kAuthScopeKey[] = "scope"; +const char kAuthClientTokenKey[] = "clientToken"; const char kAuthorizationHeaderPrefix[] = "Privet"; @@ -413,6 +415,11 @@ AddSecureHandler("/privet/v3/auth", &PrivetHandler::HandleAuth, AuthScope::kNone); + AddSecureHandler("/privet/v3/accessControl/claim", + &PrivetHandler::HandleAccessControlClaim, AuthScope::kOwner); + AddSecureHandler("/privet/v3/accessControl/confirm", + &PrivetHandler::HandleAccessControlConfirm, + AuthScope::kOwner); AddSecureHandler("/privet/v3/setup/start", &PrivetHandler::HandleSetupStart, AuthScope::kOwner); AddSecureHandler("/privet/v3/setup/status", &PrivetHandler::HandleSetupStatus, @@ -742,6 +749,40 @@ callback.Run(http::kOk, output); } +void PrivetHandler::HandleAccessControlClaim(const base::DictionaryValue& input, + const UserInfo& user_info, + const RequestCallback& callback) { + ErrorPtr error; + auto token = security_->ClaimRootClientAuthToken(&error); + if (token.empty()) + return ReturnError(*error, callback); + + base::DictionaryValue output; + output.SetString(kAuthClientTokenKey, token); + callback.Run(http::kOk, output); +} + +void PrivetHandler::HandleAccessControlConfirm( + const base::DictionaryValue& input, + const UserInfo& user_info, + const RequestCallback& callback) { + ErrorPtr error; + + std::string token; + if (!input.GetString(kAuthClientTokenKey, &token)) { + Error::AddToPrintf(&error, FROM_HERE, errors::kDomain, + errors::kInvalidParams, kInvalidParamValueFormat, + kAuthClientTokenKey, token.c_str()); + return ReturnError(*error, callback); + } + + if (!security_->ConfirmAuthToken(token, &error)) + return ReturnError(*error, callback); + + base::DictionaryValue output; + callback.Run(http::kOk, output); +} + void PrivetHandler::HandleSetupStart(const base::DictionaryValue& input, const UserInfo& user_info, const RequestCallback& callback) {
diff --git a/src/privet/privet_handler.h b/src/privet/privet_handler.h index 5241233..646cab2 100644 --- a/src/privet/privet_handler.h +++ b/src/privet/privet_handler.h
@@ -94,6 +94,12 @@ void HandleAuth(const base::DictionaryValue& input, const UserInfo& user_info, const RequestCallback& callback); + void HandleAccessControlClaim(const base::DictionaryValue& input, + const UserInfo& user_info, + const RequestCallback& callback); + void HandleAccessControlConfirm(const base::DictionaryValue& input, + const UserInfo& user_info, + const RequestCallback& callback); void HandleSetupStart(const base::DictionaryValue& input, const UserInfo& user_info, const RequestCallback& callback);
diff --git a/src/privet/privet_handler_unittest.cc b/src/privet/privet_handler_unittest.cc index 5274ba9..ab15493 100644 --- a/src/privet/privet_handler_unittest.cc +++ b/src/privet/privet_handler_unittest.cc
@@ -594,7 +594,18 @@ EXPECT_JSON_EQ(kExpected, HandleRequest("/privet/v3/setup/start", kInput)); } -TEST_F(PrivetHandlerSetupTest, State) { +TEST_F(PrivetHandlerTestWithAuth, ClaimAccessControl) { + EXPECT_JSON_EQ("{'clientToken': 'RootClientAuthToken'}", + HandleRequest("/privet/v3/accessControl/claim", "{}")); +} + +TEST_F(PrivetHandlerTestWithAuth, ConfirmAccessControl) { + EXPECT_JSON_EQ("{}", + HandleRequest("/privet/v3/accessControl/confirm", + "{'clientToken': 'DerivedClientAuthToken'}")); +} + +TEST_F(PrivetHandlerTestWithAuth, State) { EXPECT_JSON_EQ("{'state': {'test': {}}, 'fingerprint': '1'}", HandleRequest("/privet/v3/state", "{}")); @@ -604,7 +615,7 @@ HandleRequest("/privet/v3/state", "{}")); } -TEST_F(PrivetHandlerSetupTest, CommandsDefs) { +TEST_F(PrivetHandlerTestWithAuth, CommandsDefs) { EXPECT_JSON_EQ("{'commands': {'test':{}}, 'fingerprint': '1'}", HandleRequest("/privet/v3/commandDefs", "{}")); @@ -614,7 +625,7 @@ HandleRequest("/privet/v3/commandDefs", "{}")); } -TEST_F(PrivetHandlerSetupTest, Traits) { +TEST_F(PrivetHandlerTestWithAuth, Traits) { EXPECT_JSON_EQ("{'traits': {'test': {}}, 'fingerprint': '1'}", HandleRequest("/privet/v3/traits", "{}")); @@ -624,7 +635,7 @@ HandleRequest("/privet/v3/traits", "{}")); } -TEST_F(PrivetHandlerSetupTest, Components) { +TEST_F(PrivetHandlerTestWithAuth, Components) { EXPECT_JSON_EQ("{'components': {'test': {}}, 'fingerprint': '1'}", HandleRequest("/privet/v3/components", "{}")); @@ -640,7 +651,7 @@ HandleRequest("/privet/v3/components", "{}")); } -TEST_F(PrivetHandlerSetupTest, ComponentsWithFiltersAndPaths) { +TEST_F(PrivetHandlerTestWithAuth, ComponentsWithFiltersAndPaths) { const char kComponents[] = R"({ "comp1": { "traits": ["a", "b"], @@ -778,7 +789,7 @@ "{'path':'comp7', 'filter':['traits', 'components']}")); } -TEST_F(PrivetHandlerSetupTest, CommandsExecute) { +TEST_F(PrivetHandlerTestWithAuth, CommandsExecute) { const char kInput[] = "{'name': 'test'}"; base::DictionaryValue command; LoadTestJson(kInput, &command); @@ -793,7 +804,7 @@ HandleRequest("/privet/v3/commands/execute", kInput)); } -TEST_F(PrivetHandlerSetupTest, CommandsStatus) { +TEST_F(PrivetHandlerTestWithAuth, CommandsStatus) { const char kInput[] = "{'id': '5'}"; base::DictionaryValue command; LoadTestJson(kInput, &command); @@ -819,7 +830,7 @@ HandleRequest("/privet/v3/commands/status", "{'id': '15'}")); } -TEST_F(PrivetHandlerSetupTest, CommandsCancel) { +TEST_F(PrivetHandlerTestWithAuth, CommandsCancel) { const char kExpected[] = "{'id': '5', 'name':'test', 'state':'cancelled'}"; base::DictionaryValue command; LoadTestJson(kExpected, &command); @@ -844,7 +855,7 @@ HandleRequest("/privet/v3/commands/cancel", "{'id': '11'}")); } -TEST_F(PrivetHandlerSetupTest, CommandsList) { +TEST_F(PrivetHandlerTestWithAuth, CommandsList) { const char kExpected[] = R"({ 'commands' : [ {'id':'5', 'state':'cancelled'},
diff --git a/src/privet/security_manager.h b/src/privet/security_manager.h index 3ee6ac7..36dbbf4 100644 --- a/src/privet/security_manager.h +++ b/src/privet/security_manager.h
@@ -85,8 +85,6 @@ void RegisterPairingListeners(const PairingStartListener& on_start, const PairingEndListener& on_end); - const AuthManager* GetAuthManager() const { return auth_manager_; } - private: FRIEND_TEST_ALL_PREFIXES(SecurityManagerTest, ThrottlePairing); // Allows limited number of new sessions without successful authorization.
diff --git a/src/weave_unittest.cc b/src/weave_unittest.cc index 4d1f731..987b0c4 100644 --- a/src/weave_unittest.cc +++ b/src/weave_unittest.cc
@@ -292,6 +292,8 @@ EXPECT_EQ((std::set<std::string>{ // clang-format off "/privet/info", + "/privet/v3/accessControl/claim", + "/privet/v3/accessControl/confirm", "/privet/v3/auth", "/privet/v3/checkForUpdates", "/privet/v3/commandDefs",