Add AuthManager::CreateAccessTokenFromAuth
In case of local auth client passes Macaroon token and device exchanges
that for access token.
BUG=25768507
Change-Id: Ibf126d9ef470cf7843deed6b0b954c99aa64e78d
Reviewed-on: https://weave-review.googlesource.com/2065
Reviewed-by: Vitaly Buka <vitalybuka@google.com>
diff --git a/src/privet/auth_manager.cc b/src/privet/auth_manager.cc
index 61f5a09..8df7e13 100644
--- a/src/privet/auth_manager.cc
+++ b/src/privet/auth_manager.cc
@@ -4,6 +4,7 @@
#include "src/privet/auth_manager.h"
+#include <base/guid.h>
#include <base/rand_util.h>
#include <base/strings/string_number_conversions.h>
@@ -211,13 +212,13 @@
bool AuthManager::ConfirmClientAuthToken(const std::vector<uint8_t>& token,
ErrorPtr* error) {
// Cover case when caller sent confirm twice.
- if (pending_claims_.empty() && IsValidAuthToken(token))
- return true;
+ if (pending_claims_.empty())
+ return IsValidAuthToken(token, error);
auto claim =
std::find_if(pending_claims_.begin(), pending_claims_.end(),
[&token](const decltype(pending_claims_)::value_type& auth) {
- return auth.first->IsValidAuthToken(token);
+ return auth.first->IsValidAuthToken(token, nullptr);
});
if (claim == pending_claims_.end()) {
Error::AddTo(error, FROM_HERE, errors::kDomain, errors::kNotFound,
@@ -256,17 +257,55 @@
return clock_->Now();
}
-bool AuthManager::IsValidAuthToken(const std::vector<uint8_t>& token) const {
+bool AuthManager::IsValidAuthToken(const std::vector<uint8_t>& token,
+ ErrorPtr* error) const {
std::vector<uint8_t> buffer(kMaxMacaroonSize);
UwMacaroon macaroon{};
if (!uw_macaroon_load_(token.data(), token.size(), buffer.data(),
buffer.size(), &macaroon)) {
+ Error::AddTo(error, FROM_HERE, errors::kDomain, errors::kInvalidAuthCode,
+ "Invalid token format");
return false;
}
CHECK_EQ(kSha256OutputSize, auth_secret_.size());
- return uw_macaroon_verify_(&macaroon, auth_secret_.data(),
- auth_secret_.size());
+ if (!uw_macaroon_verify_(&macaroon, auth_secret_.data(),
+ auth_secret_.size())) {
+ Error::AddTo(error, FROM_HERE, errors::kDomain, errors::kInvalidAuthCode,
+ "Invalid token signature");
+ return false;
+ }
+ return true;
+}
+
+bool AuthManager::CreateAccessTokenFromAuth(
+ const std::vector<uint8_t>& auth_token,
+ base::TimeDelta ttl,
+ std::vector<uint8_t>* access_token,
+ AuthScope* access_token_scope,
+ base::TimeDelta* access_token_ttl,
+ ErrorPtr* error) const {
+ // TODO(vitalybuka): implement token validation.
+ if (!IsValidAuthToken(auth_token, error))
+ return false;
+
+ if (!access_token)
+ return true;
+
+ // TODO(vitalybuka): User and scope must be parsed from auth_token.
+ UserInfo info{config_ ? config_->GetSettings().local_anonymous_access_role
+ : AuthScope::kViewer,
+ base::GenerateGUID()};
+
+ // TODO(vitalybuka): TTL also should be reduced in accordance with auth_token.
+ *access_token = CreateAccessToken(info, ttl);
+
+ if (access_token_scope)
+ *access_token_scope = info.scope();
+
+ if (access_token_ttl)
+ *access_token_ttl = ttl;
+ return true;
}
std::vector<uint8_t> AuthManager::CreateSessionId() {
diff --git a/src/privet/auth_manager.h b/src/privet/auth_manager.h
index 00d6e32..6a403b4 100644
--- a/src/privet/auth_manager.h
+++ b/src/privet/auth_manager.h
@@ -55,7 +55,14 @@
ErrorPtr* error);
std::vector<uint8_t> GetRootClientAuthToken() const;
- bool IsValidAuthToken(const std::vector<uint8_t>& token) const;
+ bool IsValidAuthToken(const std::vector<uint8_t>& token,
+ ErrorPtr* error) const;
+ bool CreateAccessTokenFromAuth(const std::vector<uint8_t>& auth_token,
+ base::TimeDelta ttl,
+ std::vector<uint8_t>* access_token,
+ AuthScope* access_token_scope,
+ base::TimeDelta* access_token_ttl,
+ ErrorPtr* error) const;
void SetAuthSecret(const std::vector<uint8_t>& secret,
RootClientTokenOwner owner);
diff --git a/src/privet/auth_manager_unittest.cc b/src/privet/auth_manager_unittest.cc
index 137e046..ce142c0 100644
--- a/src/privet/auth_manager_unittest.cc
+++ b/src/privet/auth_manager_unittest.cc
@@ -122,7 +122,6 @@
auto token = auth.CreateAccessToken(UserInfo{AuthScope::kUser, "5"},
base::TimeDelta::FromSeconds(i));
- base::Time time2;
UserInfo user_info;
EXPECT_FALSE(auth_.ParseAccessToken(token, &user_info, nullptr));
EXPECT_TRUE(auth.ParseAccessToken(token, &user_info, nullptr));
@@ -159,14 +158,14 @@
}
TEST_F(AuthManagerTest, IsValidAuthToken) {
- EXPECT_TRUE(auth_.IsValidAuthToken(auth_.GetRootClientAuthToken()));
+ EXPECT_TRUE(auth_.IsValidAuthToken(auth_.GetRootClientAuthToken(), nullptr));
// Multiple attempts with random secrets.
for (size_t i = 0; i < 1000; ++i) {
AuthManager auth{{}, {}, {}, &clock_};
auto token = auth.GetRootClientAuthToken();
- EXPECT_FALSE(auth_.IsValidAuthToken(token));
- EXPECT_TRUE(auth.IsValidAuthToken(token));
+ EXPECT_FALSE(auth_.IsValidAuthToken(token, nullptr));
+ EXPECT_TRUE(auth.IsValidAuthToken(token, nullptr));
}
}
@@ -211,12 +210,12 @@
TEST_F(AuthManagerClaimTest, NormalClaim) {
auto token =
auth_.ClaimRootClientAuthToken(RootClientTokenOwner::kCloud, nullptr);
- EXPECT_FALSE(auth_.IsValidAuthToken(token));
+ EXPECT_FALSE(auth_.IsValidAuthToken(token, nullptr));
EXPECT_EQ(RootClientTokenOwner::kNone,
config_.GetSettings().root_client_token_owner);
EXPECT_TRUE(auth_.ConfirmClientAuthToken(token, nullptr));
- EXPECT_TRUE(auth_.IsValidAuthToken(token));
+ EXPECT_TRUE(auth_.IsValidAuthToken(token, nullptr));
EXPECT_EQ(RootClientTokenOwner::kCloud,
config_.GetSettings().root_client_token_owner);
}
@@ -245,5 +244,18 @@
EXPECT_FALSE(auth_.ConfirmClientAuthToken(token, nullptr));
}
+TEST_F(AuthManagerClaimTest, CreateAccessTokenFromAuth) {
+ std::vector<uint8_t> access_token;
+ AuthScope scope;
+ base::TimeDelta ttl;
+ EXPECT_TRUE(auth_.CreateAccessTokenFromAuth(
+ auth_.GetRootClientAuthToken(), base::TimeDelta::FromDays(1),
+ &access_token, &scope, &ttl, nullptr));
+ UserInfo user_info;
+ EXPECT_TRUE(auth_.ParseAccessToken(access_token, &user_info, nullptr));
+ EXPECT_EQ(scope, user_info.scope());
+ EXPECT_FALSE(user_info.user_id().empty());
+}
+
} // namespace privet
} // namespace weave
diff --git a/src/privet/security_manager.cc b/src/privet/security_manager.cc
index bc8dc4f..caed476 100644
--- a/src/privet/security_manager.cc
+++ b/src/privet/security_manager.cc
@@ -111,23 +111,50 @@
ClosePendingSession(pending_sessions_.begin()->first);
}
-bool SecurityManager::CreateAccessToken(AuthType auth_type,
- const std::string& auth_code,
- AuthScope desired_scope,
- std::string* access_token,
- AuthScope* access_token_scope,
- base::TimeDelta* access_token_ttl,
- ErrorPtr* error) {
+bool SecurityManager::CreateAccessTokenImpl(AuthType auth_type,
+ AuthScope desired_scope,
+ std::vector<uint8_t>* access_token,
+ AuthScope* access_token_scope,
+ base::TimeDelta* access_token_ttl) {
+ UserInfo user_info{desired_scope,
+ std::to_string(static_cast<int>(auth_type)) + "/" +
+ std::to_string(++last_user_id_)};
+
+ const base::TimeDelta kTtl =
+ base::TimeDelta::FromSeconds(kAccessTokenExpirationSeconds);
+
+ if (access_token)
+ *access_token = auth_manager_->CreateAccessToken(user_info, kTtl);
+
+ if (access_token_scope)
+ *access_token_scope = user_info.scope();
+
+ if (access_token_ttl)
+ *access_token_ttl = kTtl;
+
+ return true;
+}
+
+bool SecurityManager::CreateAccessTokenImpl(
+ AuthType auth_type,
+ const std::vector<uint8_t>& auth_code,
+ AuthScope desired_scope,
+ std::vector<uint8_t>* access_token,
+ AuthScope* access_token_scope,
+ base::TimeDelta* access_token_ttl,
+ ErrorPtr* error) {
auto disabled_mode = [](ErrorPtr* error) {
Error::AddTo(error, FROM_HERE, errors::kDomain, errors::kInvalidAuthMode,
"Mode is not available");
return false;
};
+
switch (auth_type) {
case AuthType::kAnonymous:
if (!auth_manager_->IsAnonymousAuthSupported())
return disabled_mode(error);
- break;
+ return CreateAccessTokenImpl(auth_type, desired_scope, access_token,
+ access_token_scope, access_token_ttl);
case AuthType::kPairing:
if (!auth_manager_->IsPairingAuthSupported())
return disabled_mode(error);
@@ -136,34 +163,45 @@
errors::kInvalidAuthCode, "Invalid authCode");
return false;
}
- break;
+ return CreateAccessTokenImpl(auth_type, desired_scope, access_token,
+ access_token_scope, access_token_ttl);
case AuthType::kLocal:
if (!auth_manager_->IsLocalAuthSupported())
return disabled_mode(error);
- NOTIMPLEMENTED();
- // no break to fall back to default.
- default:
- Error::AddTo(error, FROM_HERE, errors::kDomain, errors::kInvalidAuthMode,
- "Unsupported auth mode");
- return false;
+ const base::TimeDelta kTtl =
+ base::TimeDelta::FromSeconds(kAccessTokenExpirationSeconds);
+ return auth_manager_->CreateAccessTokenFromAuth(
+ auth_code, kTtl, access_token, access_token_scope, access_token_ttl,
+ error);
}
- UserInfo user_info{desired_scope,
- std::to_string(static_cast<int>(auth_type)) + "/" +
- std::to_string(++last_user_id_)};
- base::TimeDelta ttl =
- base::TimeDelta::FromSeconds(kAccessTokenExpirationSeconds);
+ Error::AddTo(error, FROM_HERE, errors::kDomain, errors::kInvalidAuthMode,
+ "Unsupported auth mode");
+ return false;
+}
- if (access_token) {
- *access_token =
- Base64Encode(auth_manager_->CreateAccessToken(user_info, ttl));
+bool SecurityManager::CreateAccessToken(AuthType auth_type,
+ const std::string& auth_code,
+ AuthScope desired_scope,
+ std::string* access_token,
+ AuthScope* access_token_scope,
+ base::TimeDelta* access_token_ttl,
+ ErrorPtr* error) {
+ std::vector<uint8_t> auth_decoded;
+ if (auth_type != AuthType::kAnonymous &&
+ !Base64Decode(auth_code, &auth_decoded)) {
+ return false;
}
- if (access_token_scope)
- *access_token_scope = user_info.scope();
+ std::vector<uint8_t> access_token_decoded;
+ if (!CreateAccessTokenImpl(auth_type, auth_decoded, desired_scope,
+ &access_token_decoded, access_token_scope,
+ access_token_ttl, error)) {
+ return false;
+ }
- if (access_token_ttl)
- *access_token_ttl = ttl;
+ if (access_token)
+ *access_token = Base64Encode(access_token_decoded);
return true;
}
@@ -224,18 +262,15 @@
return auth_manager_->ConfirmClientAuthToken(token_decoded, error);
}
-bool SecurityManager::IsValidPairingCode(const std::string& auth_code) const {
+bool SecurityManager::IsValidPairingCode(
+ const std::vector<uint8_t>& auth_code) const {
if (is_security_disabled_)
return true;
- std::vector<uint8_t> auth_decoded;
- if (!Base64Decode(auth_code, &auth_decoded))
- return false;
for (const auto& session : confirmed_sessions_) {
const std::string& key = session.second->GetKey();
const std::string& id = session.first;
- if (auth_decoded ==
- HmacSha256(std::vector<uint8_t>(key.begin(), key.end()),
- std::vector<uint8_t>(id.begin(), id.end()))) {
+ if (auth_code == HmacSha256(std::vector<uint8_t>(key.begin(), key.end()),
+ std::vector<uint8_t>(id.begin(), id.end()))) {
pairing_attemts_ = 0;
block_pairing_until_ = base::Time{};
return true;
diff --git a/src/privet/security_manager.h b/src/privet/security_manager.h
index 5cb884f..79abf33 100644
--- a/src/privet/security_manager.h
+++ b/src/privet/security_manager.h
@@ -64,8 +64,8 @@
const std::string& auth_code,
AuthScope desired_scope,
std::string* access_token,
- AuthScope* granted_scope,
- base::TimeDelta* ttl,
+ AuthScope* access_token_scope,
+ base::TimeDelta* access_token_ttl,
ErrorPtr* error) override;
bool ParseAccessToken(const std::string& token,
UserInfo* user_info,
@@ -94,12 +94,24 @@
const PairingEndListener& on_end);
private:
- bool IsValidPairingCode(const std::string& auth_code) const;
+ bool IsValidPairingCode(const std::vector<uint8_t>& auth_code) const;
FRIEND_TEST_ALL_PREFIXES(SecurityManagerTest, ThrottlePairing);
// Allows limited number of new sessions without successful authorization.
bool CheckIfPairingAllowed(ErrorPtr* error);
bool ClosePendingSession(const std::string& session_id);
bool CloseConfirmedSession(const std::string& session_id);
+ bool CreateAccessTokenImpl(AuthType auth_type,
+ const std::vector<uint8_t>& auth_code,
+ AuthScope desired_scope,
+ std::vector<uint8_t>* access_token,
+ AuthScope* access_token_scope,
+ base::TimeDelta* access_token_ttl,
+ ErrorPtr* error);
+ bool CreateAccessTokenImpl(AuthType auth_type,
+ AuthScope desired_scope,
+ std::vector<uint8_t>* access_token,
+ AuthScope* access_token_scope,
+ base::TimeDelta* access_token_ttl);
AuthManager* auth_manager_{nullptr};