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",