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