Add ClaimRootClientAuthToken and ConfirmRootClientAuthToken

Claim* call will create temporarily secret and set that as primary after
Confirm* is called.

Local client needs to be able to claim control of unclaimed device.
Device should be claimed no more than once, so if Claim was called and
client didn't not get response, we will have locked account. Confirm* is
used as that confirmation.

BUG=25766815

Change-Id: Id744f98788abe70a42b32c4a6d796e7ff74c3936
Reviewed-on: https://weave-review.googlesource.com/1947
Reviewed-by: Alex Vakulenko <avakulenko@google.com>
diff --git a/src/privet/auth_manager.cc b/src/privet/auth_manager.cc
index 0364a87..1862d62 100644
--- a/src/privet/auth_manager.cc
+++ b/src/privet/auth_manager.cc
@@ -23,6 +23,7 @@
 const char kTokenDelimeter[] = ":";
 const size_t kCaveatBuffetSize = 32;
 const size_t kMaxMacaroonSize = 1024;
+const size_t kMaxPendingClaims = 10;
 
 // Returns "scope:id:time".
 std::string CreateTokenData(const UserInfo& user_info, const base::Time& time) {
@@ -109,6 +110,32 @@
   return SplitTokenData(std::string(data.begin(), data.end()), time);
 }
 
+std::vector<uint8_t> AuthManager::ClaimRootClientAuthToken() {
+  pending_claims_.push_back(
+      std::unique_ptr<AuthManager>{new AuthManager{{}, {}}});
+  if (pending_claims_.size() > kMaxPendingClaims)
+    pending_claims_.pop_front();
+  return pending_claims_.back()->GetRootClientAuthToken();
+}
+
+bool AuthManager::ConfirmRootClientAuthToken(
+    const std::vector<uint8_t>& token) {
+  // Cover case when caller sent confirm twice.
+  if (pending_claims_.empty() && IsValidAuthToken(token))
+    return true;
+
+  auto claim = std::find_if(pending_claims_.begin(), pending_claims_.end(),
+                            [&token](const std::unique_ptr<AuthManager>& auth) {
+                              return auth->IsValidAuthToken(token);
+                            });
+  if (claim == pending_claims_.end())
+    return false;
+
+  secret_ = (*claim)->GetSecret();
+  pending_claims_.clear();
+  return true;
+}
+
 std::vector<uint8_t> AuthManager::GetRootClientAuthToken() const {
   Caveat scope{kUwMacaroonCaveatTypeScope, kUwMacaroonCaveatScopeTypeOwner};
   Caveat issued{kUwMacaroonCaveatTypeIssued,
diff --git a/src/privet/auth_manager.h b/src/privet/auth_manager.h
index dfdd6b3..f1b6c8b 100644
--- a/src/privet/auth_manager.h
+++ b/src/privet/auth_manager.h
@@ -5,6 +5,7 @@
 #ifndef LIBWEAVE_SRC_PRIVET_AUTH_MANAGER_H_
 #define LIBWEAVE_SRC_PRIVET_AUTH_MANAGER_H_
 
+#include <deque>
 #include <string>
 #include <vector>
 
@@ -32,12 +33,16 @@
   const std::vector<uint8_t>& GetCertificateFingerprint() const {
     return certificate_fingerprint_;
   }
-  std::vector<uint8_t> GetRootClientAuthToken() const;
 
   base::Time Now() const;
 
+  std::vector<uint8_t> GetRootClientAuthToken() const;
+
   bool IsValidAuthToken(const std::vector<uint8_t>& token) const;
 
+  std::vector<uint8_t> ClaimRootClientAuthToken();
+  bool ConfirmRootClientAuthToken(const std::vector<uint8_t>& token);
+
  private:
   base::DefaultClock default_clock_;
   base::Clock* clock_{nullptr};
@@ -45,6 +50,8 @@
   std::vector<uint8_t> secret_;
   std::vector<uint8_t> certificate_fingerprint_;
 
+  std::deque<std::unique_ptr<AuthManager>> pending_claims_;
+
   DISALLOW_COPY_AND_ASSIGN(AuthManager);
 };
 
diff --git a/src/privet/auth_manager_unittest.cc b/src/privet/auth_manager_unittest.cc
index 72e7afd..ee50e08 100644
--- a/src/privet/auth_manager_unittest.cc
+++ b/src/privet/auth_manager_unittest.cc
@@ -146,5 +146,33 @@
   }
 }
 
+TEST_F(AuthManagerTest, ClaimRootClientAuthToken) {
+  auto token = auth_.ClaimRootClientAuthToken();
+  EXPECT_FALSE(auth_.IsValidAuthToken(token));
+
+  EXPECT_TRUE(auth_.ConfirmRootClientAuthToken(token));
+  EXPECT_TRUE(auth_.IsValidAuthToken(token));
+}
+
+TEST_F(AuthManagerTest, ClaimRootClientAuthTokenDoubleConfirm) {
+  auto token = auth_.ClaimRootClientAuthToken();
+  EXPECT_TRUE(auth_.ConfirmRootClientAuthToken(token));
+  EXPECT_TRUE(auth_.ConfirmRootClientAuthToken(token));
+}
+
+TEST_F(AuthManagerTest, DoubleClaimRootClientAuthToken) {
+  auto token1 = auth_.ClaimRootClientAuthToken();
+  auto token2 = auth_.ClaimRootClientAuthToken();
+  EXPECT_TRUE(auth_.ConfirmRootClientAuthToken(token1));
+  EXPECT_FALSE(auth_.ConfirmRootClientAuthToken(token2));
+}
+
+TEST_F(AuthManagerTest, ClaimRootClientAuthTokenOverflow) {
+  auto token = auth_.ClaimRootClientAuthToken();
+  for (size_t i = 0; i < 100; ++i)
+    auth_.ClaimRootClientAuthToken();
+  EXPECT_FALSE(auth_.ConfirmRootClientAuthToken(token));
+}
+
 }  // namespace privet
 }  // namespace weave