blob: 6a79b934a70acf8e4feeae08fe32b96bb7cd9c70 [file] [log] [blame]
Vitaly Bukaf08caeb2015-12-02 13:47:48 -08001// Copyright 2015 The Weave Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "src/privet/auth_manager.h"
6
7#include <base/rand_util.h>
8#include <base/strings/string_number_conversions.h>
9
10#include "src/data_encoding.h"
11#include "src/privet/openssl_utils.h"
12#include "src/string_utils.h"
13
Vitaly Bukaa37056e2015-12-09 14:53:39 -080014extern "C" {
15#include "third_party/libuweave/src/macaroon.h"
16}
17
Vitaly Bukaf08caeb2015-12-02 13:47:48 -080018namespace weave {
19namespace privet {
20
21namespace {
22
23const char kTokenDelimeter[] = ":";
Vitaly Bukaa37056e2015-12-09 14:53:39 -080024const size_t kCaveatBuffetSize = 32;
25const size_t kMaxMacaroonSize = 1024;
Vitaly Bukaf08caeb2015-12-02 13:47:48 -080026
27// Returns "scope:id:time".
28std::string CreateTokenData(const UserInfo& user_info, const base::Time& time) {
29 return base::IntToString(static_cast<int>(user_info.scope())) +
30 kTokenDelimeter + base::Uint64ToString(user_info.user_id()) +
31 kTokenDelimeter + base::Int64ToString(time.ToTimeT());
32}
33
34// Splits string of "scope:id:time" format.
35UserInfo SplitTokenData(const std::string& token, base::Time* time) {
36 const UserInfo kNone;
37 auto parts = Split(token, kTokenDelimeter, false, false);
38 if (parts.size() != 3)
39 return kNone;
40 int scope = 0;
41 if (!base::StringToInt(parts[0], &scope) ||
42 scope < static_cast<int>(AuthScope::kNone) ||
43 scope > static_cast<int>(AuthScope::kOwner)) {
44 return kNone;
45 }
46
47 uint64_t id{0};
48 if (!base::StringToUint64(parts[1], &id))
49 return kNone;
50
51 int64_t timestamp{0};
52 if (!base::StringToInt64(parts[2], &timestamp))
53 return kNone;
54 *time = base::Time::FromTimeT(timestamp);
55 return UserInfo{static_cast<AuthScope>(scope), id};
56}
57
Vitaly Bukaa37056e2015-12-09 14:53:39 -080058class Caveat {
59 public:
60 Caveat(UwMacaroonCaveatType type, uint32_t value) {
61 CHECK(uw_macaroon_caveat_create_with_uint_(type, value, buffer,
62 sizeof(buffer), &caveat));
63 }
64
65 const UwMacaroonCaveat& GetCaveat() const { return caveat; }
66
67 private:
68 UwMacaroonCaveat caveat;
69 uint8_t buffer[kCaveatBuffetSize];
70
71 DISALLOW_COPY_AND_ASSIGN(Caveat);
72};
73
Vitaly Bukaf08caeb2015-12-02 13:47:48 -080074} // namespace
75
76AuthManager::AuthManager(const std::vector<uint8_t>& secret,
Vitaly Buka41aa8092015-12-09 20:04:34 -080077 const std::vector<uint8_t>& certificate_fingerprint,
78 base::Clock* clock)
79 : clock_{clock ? clock : &default_clock_},
80 secret_{secret},
81 certificate_fingerprint_{certificate_fingerprint} {
Vitaly Bukaf08caeb2015-12-02 13:47:48 -080082 if (secret_.size() != kSha256OutputSize) {
83 secret_.resize(kSha256OutputSize);
84 base::RandBytes(secret_.data(), secret_.size());
85 }
86}
87
88AuthManager::~AuthManager() {}
89
90// Returns "[hmac]scope:id:time".
Vitaly Buka41aa8092015-12-09 20:04:34 -080091std::vector<uint8_t> AuthManager::CreateAccessToken(const UserInfo& user_info) {
92 std::string data_str{CreateTokenData(user_info, Now())};
Vitaly Bukaf08caeb2015-12-02 13:47:48 -080093 std::vector<uint8_t> data{data_str.begin(), data_str.end()};
94 std::vector<uint8_t> hash{HmacSha256(secret_, data)};
95 hash.insert(hash.end(), data.begin(), data.end());
96 return hash;
97}
98
99// Parses "base64([hmac]scope:id:time)".
100UserInfo AuthManager::ParseAccessToken(const std::vector<uint8_t>& token,
101 base::Time* time) const {
102 if (token.size() <= kSha256OutputSize)
103 return UserInfo{};
104 std::vector<uint8_t> hash(token.begin(), token.begin() + kSha256OutputSize);
105 std::vector<uint8_t> data(token.begin() + kSha256OutputSize, token.end());
106 if (hash != HmacSha256(secret_, data))
107 return UserInfo{};
108 return SplitTokenData(std::string(data.begin(), data.end()), time);
109}
110
Vitaly Buka47743a32015-12-10 14:59:11 -0800111std::vector<uint8_t> AuthManager::GetRootClientAuthToken() const {
Vitaly Bukaa37056e2015-12-09 14:53:39 -0800112 Caveat scope{kUwMacaroonCaveatTypeScope, kUwMacaroonCaveatScopeTypeOwner};
113 Caveat issued{kUwMacaroonCaveatTypeIssued,
Vitaly Buka41aa8092015-12-09 20:04:34 -0800114 static_cast<uint32_t>(Now().ToTimeT())};
Vitaly Bukaa37056e2015-12-09 14:53:39 -0800115
116 UwMacaroonCaveat caveats[] = {
117 scope.GetCaveat(), issued.GetCaveat(),
118 };
119
120 UwMacaroon macaroon{};
121 CHECK(uw_macaroon_new_from_root_key_(
122 &macaroon, secret_.data(), secret_.size(), caveats, arraysize(caveats)));
123
124 std::vector<uint8_t> token(kMaxMacaroonSize);
125 size_t len = 0;
126 CHECK(uw_macaroon_dump_(&macaroon, token.data(), token.size(), &len));
127 token.resize(len);
128 return token;
129}
130
Vitaly Buka41aa8092015-12-09 20:04:34 -0800131base::Time AuthManager::Now() const {
132 return clock_->Now();
133}
134
Vitaly Bukaf08caeb2015-12-02 13:47:48 -0800135} // namespace privet
136} // namespace weave