Change interface of ClaimRootClientAuthToken and ConfirmAuthToken

Add RootClientTokenOwner argument to check if this owner can claim
device.
Add ErrorPtr to return error in privet response.

BUG=25766815

Change-Id: I508c934e23092514e37b1f4790f0f1e693583ae1
Reviewed-on: https://weave-review.googlesource.com/1939
Reviewed-by: Alex Vakulenko <avakulenko@google.com>
diff --git a/src/device_registration_info.cc b/src/device_registration_info.cc
index f52c292..59a49b2 100644
--- a/src/device_registration_info.cc
+++ b/src/device_registration_info.cc
@@ -933,11 +933,20 @@
 void DeviceRegistrationInfo::SendAuthInfo() {
   if (!auth_manager_ || auth_info_update_inprogress_)
     return;
+
+  if (GetSettings().root_client_token_owner == RootClientTokenOwner::kCloud) {
+    // Avoid re-claiming if device is already claimed by the Cloud. Cloud is
+    // allowed to re-claim device at any time. However this will invalidate all
+    // issued tokens.
+    return;
+  }
+
   auth_info_update_inprogress_ = true;
 
+  std::vector<uint8_t> token = auth_manager_->ClaimRootClientAuthToken(
+      RootClientTokenOwner::kCloud, nullptr);
+  CHECK(!token.empty());
   std::string id = GetSettings().device_id;
-  std::vector<uint8_t> token =
-      auth_manager_->ClaimRootClientAuthToken(RootClientTokenOwner::kCloud);
   std::string token_base64 = Base64Encode(token);
   std::string fingerprint =
       Base64Encode(auth_manager_->GetCertificateFingerprint());
@@ -962,7 +971,7 @@
   CHECK(auth_info_update_inprogress_);
   auth_info_update_inprogress_ = false;
 
-  if (!error && auth_manager_->ConfirmAuthToken(token))
+  if (!error && auth_manager_->ConfirmAuthToken(token, nullptr))
     return;
 
   task_runner_->PostDelayedTask(
@@ -1328,6 +1337,9 @@
   connected_to_cloud_ = false;
 
   LOG(INFO) << "Device is unregistered from the cloud. Deleting credentials";
+  if (auth_manager_)
+    auth_manager_->SetSecret({}, RootClientTokenOwner::kNone);
+
   Config::Transaction change{config_};
   // Keep cloud_id to switch to detect kInvalidCredentials after restart.
   change.set_robot_account("");
diff --git a/src/privet/auth_manager.cc b/src/privet/auth_manager.cc
index fa1d685..f38b854 100644
--- a/src/privet/auth_manager.cc
+++ b/src/privet/auth_manager.cc
@@ -146,7 +146,8 @@
 }
 
 std::vector<uint8_t> AuthManager::ClaimRootClientAuthToken(
-    RootClientTokenOwner owner) {
+    RootClientTokenOwner owner,
+    ErrorPtr* error) {
   pending_claims_.push_back(std::make_pair(
       std::unique_ptr<AuthManager>{new AuthManager{nullptr, {}}}, owner));
   if (pending_claims_.size() > kMaxPendingClaims)
@@ -154,7 +155,8 @@
   return pending_claims_.back().first->GetRootClientAuthToken();
 }
 
-bool AuthManager::ConfirmAuthToken(const std::vector<uint8_t>& token) {
+bool AuthManager::ConfirmAuthToken(const std::vector<uint8_t>& token,
+                                   ErrorPtr* error) {
   // Cover case when caller sent confirm twice.
   if (pending_claims_.empty() && IsValidAuthToken(token))
     return true;
diff --git a/src/privet/auth_manager.h b/src/privet/auth_manager.h
index 62a1606..ce406ce 100644
--- a/src/privet/auth_manager.h
+++ b/src/privet/auth_manager.h
@@ -44,16 +44,17 @@
 
   base::Time Now() const;
 
-  std::vector<uint8_t> ClaimRootClientAuthToken(RootClientTokenOwner owner);
-  bool ConfirmAuthToken(const std::vector<uint8_t>& token);
+  std::vector<uint8_t> ClaimRootClientAuthToken(RootClientTokenOwner owner,
+                                                ErrorPtr* error);
+  bool ConfirmAuthToken(const std::vector<uint8_t>& token, ErrorPtr* error);
 
   std::vector<uint8_t> GetRootClientAuthToken() const;
   bool IsValidAuthToken(const std::vector<uint8_t>& token) const;
 
- private:
   void SetSecret(const std::vector<uint8_t>& secret,
                  RootClientTokenOwner owner);
 
+ private:
   Config* config_{nullptr};
   base::DefaultClock default_clock_;
   base::Clock* clock_{&default_clock_};
diff --git a/src/privet/auth_manager_unittest.cc b/src/privet/auth_manager_unittest.cc
index 4dd753b..7b4aae4 100644
--- a/src/privet/auth_manager_unittest.cc
+++ b/src/privet/auth_manager_unittest.cc
@@ -148,31 +148,36 @@
 }
 
 TEST_F(AuthManagerTest, ClaimRootClientAuthToken) {
-  auto token = auth_.ClaimRootClientAuthToken(RootClientTokenOwner::kCloud);
+  auto token =
+      auth_.ClaimRootClientAuthToken(RootClientTokenOwner::kCloud, nullptr);
   EXPECT_FALSE(auth_.IsValidAuthToken(token));
 
-  EXPECT_TRUE(auth_.ConfirmAuthToken(token));
+  EXPECT_TRUE(auth_.ConfirmAuthToken(token, nullptr));
   EXPECT_TRUE(auth_.IsValidAuthToken(token));
 }
 
 TEST_F(AuthManagerTest, ClaimRootClientAuthTokenDoubleConfirm) {
-  auto token = auth_.ClaimRootClientAuthToken(RootClientTokenOwner::kCloud);
-  EXPECT_TRUE(auth_.ConfirmAuthToken(token));
-  EXPECT_TRUE(auth_.ConfirmAuthToken(token));
+  auto token =
+      auth_.ClaimRootClientAuthToken(RootClientTokenOwner::kCloud, nullptr);
+  EXPECT_TRUE(auth_.ConfirmAuthToken(token, nullptr));
+  EXPECT_TRUE(auth_.ConfirmAuthToken(token, nullptr));
 }
 
 TEST_F(AuthManagerTest, DoubleClaimRootClientAuthToken) {
-  auto token1 = auth_.ClaimRootClientAuthToken(RootClientTokenOwner::kCloud);
-  auto token2 = auth_.ClaimRootClientAuthToken(RootClientTokenOwner::kCloud);
-  EXPECT_TRUE(auth_.ConfirmAuthToken(token1));
-  EXPECT_FALSE(auth_.ConfirmAuthToken(token2));
+  auto token1 =
+      auth_.ClaimRootClientAuthToken(RootClientTokenOwner::kCloud, nullptr);
+  auto token2 =
+      auth_.ClaimRootClientAuthToken(RootClientTokenOwner::kCloud, nullptr);
+  EXPECT_TRUE(auth_.ConfirmAuthToken(token1, nullptr));
+  EXPECT_FALSE(auth_.ConfirmAuthToken(token2, nullptr));
 }
 
 TEST_F(AuthManagerTest, ClaimRootClientAuthTokenOverflow) {
-  auto token = auth_.ClaimRootClientAuthToken(RootClientTokenOwner::kCloud);
+  auto token =
+      auth_.ClaimRootClientAuthToken(RootClientTokenOwner::kCloud, nullptr);
   for (size_t i = 0; i < 100; ++i)
-    auth_.ClaimRootClientAuthToken(RootClientTokenOwner::kCloud);
-  EXPECT_FALSE(auth_.ConfirmAuthToken(token));
+    auth_.ClaimRootClientAuthToken(RootClientTokenOwner::kCloud, nullptr);
+  EXPECT_FALSE(auth_.ConfirmAuthToken(token, nullptr));
 }
 
 }  // namespace privet
diff --git a/src/privet/mock_delegates.h b/src/privet/mock_delegates.h
index 6762481..9ae94a8 100644
--- a/src/privet/mock_delegates.h
+++ b/src/privet/mock_delegates.h
@@ -13,6 +13,7 @@
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
 
+#include "src/config.h"
 #include "src/privet/cloud_delegate.h"
 #include "src/privet/device_delegate.h"
 #include "src/privet/security_delegate.h"
@@ -24,6 +25,7 @@
 using testing::SetArgPointee;
 
 namespace weave {
+
 namespace privet {
 
 ACTION_TEMPLATE(RunCallback,
@@ -64,8 +66,8 @@
                      UserInfo(const std::string&, base::Time*));
   MOCK_CONST_METHOD0(GetPairingTypes, std::set<PairingType>());
   MOCK_CONST_METHOD0(GetCryptoTypes, std::set<CryptoType>());
-  MOCK_METHOD0(ClaimRootClientAuthToken, std::string());
-  MOCK_METHOD1(ConfirmAuthToken, bool(const std::string& token));
+  MOCK_METHOD1(ClaimRootClientAuthToken, std::string(ErrorPtr*));
+  MOCK_METHOD2(ConfirmAuthToken, bool(const std::string&, ErrorPtr*));
   MOCK_CONST_METHOD1(IsValidPairingCode, bool(const std::string&));
   MOCK_METHOD5(
       StartPairing,
@@ -82,7 +84,7 @@
     EXPECT_CALL(*this, CreateAccessToken(_))
         .WillRepeatedly(Return("GuestAccessToken"));
 
-    EXPECT_CALL(*this, ClaimRootClientAuthToken())
+    EXPECT_CALL(*this, ClaimRootClientAuthToken(_))
         .WillRepeatedly(Return("RootClientAuthToken"));
 
     EXPECT_CALL(*this, ParseAccessToken(_, _))
diff --git a/src/privet/security_delegate.h b/src/privet/security_delegate.h
index 3446c48..adc582d 100644
--- a/src/privet/security_delegate.h
+++ b/src/privet/security_delegate.h
@@ -35,11 +35,11 @@
   virtual std::set<CryptoType> GetCryptoTypes() const = 0;
 
   // Returns Root Client Authorization Token.
-  virtual std::string ClaimRootClientAuthToken() = 0;
+  virtual std::string ClaimRootClientAuthToken(ErrorPtr* error) = 0;
 
   // Confirms pending pending token claim or checks that token is valid for the
   // active secret.
-  virtual bool ConfirmAuthToken(const std::string& token) = 0;
+  virtual bool ConfirmAuthToken(const std::string& token, ErrorPtr* error) = 0;
 
   // Returns true if |auth_code| provided by client is valid. Client should
   // obtain |auth_code| during pairing process.
diff --git a/src/privet/security_manager.cc b/src/privet/security_manager.cc
index 5fa41be..5bb35cc 100644
--- a/src/privet/security_manager.cc
+++ b/src/privet/security_manager.cc
@@ -135,16 +135,21 @@
   return result;
 }
 
-std::string SecurityManager::ClaimRootClientAuthToken() {
-  return Base64Encode(
-      auth_manager_->ClaimRootClientAuthToken(RootClientTokenOwner::kClient));
+std::string SecurityManager::ClaimRootClientAuthToken(ErrorPtr* error) {
+  return Base64Encode(auth_manager_->ClaimRootClientAuthToken(
+      RootClientTokenOwner::kClient, error));
 }
 
-bool SecurityManager::ConfirmAuthToken(const std::string& token) {
+bool SecurityManager::ConfirmAuthToken(const std::string& token,
+                                       ErrorPtr* error) {
   std::vector<uint8_t> token_decoded;
-  if (!Base64Decode(token, &token_decoded))
+  if (!Base64Decode(token, &token_decoded)) {
+    Error::AddToPrintf(error, FROM_HERE, errors::kDomain,
+                       errors::kInvalidFormat,
+                       "Invalid auth token string: '%s'", token.c_str());
     return false;
-  return auth_manager_->ConfirmAuthToken(token_decoded);
+  }
+  return auth_manager_->ConfirmAuthToken(token_decoded, error);
 }
 
 bool SecurityManager::IsValidPairingCode(const std::string& auth_code) const {
diff --git a/src/privet/security_manager.h b/src/privet/security_manager.h
index 5d9b75a..3ee6ac7 100644
--- a/src/privet/security_manager.h
+++ b/src/privet/security_manager.h
@@ -65,8 +65,8 @@
                             base::Time* time) const override;
   std::set<PairingType> GetPairingTypes() const override;
   std::set<CryptoType> GetCryptoTypes() const override;
-  std::string ClaimRootClientAuthToken() override;
-  bool ConfirmAuthToken(const std::string& token) override;
+  std::string ClaimRootClientAuthToken(ErrorPtr* error) override;
+  bool ConfirmAuthToken(const std::string& token, ErrorPtr* error) override;
   bool IsValidPairingCode(const std::string& auth_code) const override;
 
   bool StartPairing(PairingType mode,