1 // 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 <algorithm>
8 
9 #include <base/guid.h>
10 #include <base/rand_util.h>
11 #include <base/strings/string_number_conversions.h>
12 
13 #include "src/config.h"
14 #include "src/data_encoding.h"
15 #include "src/privet/constants.h"
16 #include "src/privet/openssl_utils.h"
17 #include "src/string_utils.h"
18 
19 extern "C" {
20 #include "third_party/libuweave/src/macaroon.h"
21 #include "third_party/libuweave/src/macaroon_caveat_internal.h"
22 }
23 
24 namespace weave {
25 namespace privet {
26 
27 namespace {
28 
29 const time_t kJ2000ToTimeT = 946684800;
30 const size_t kMaxMacaroonSize = 1024;
31 const size_t kMaxPendingClaims = 10;
32 const char kInvalidTokenError[] = "invalid_token";
33 const int kSessionIdTtlMinutes = 1;
34 
ToJ2000Time(const base::Time & time)35 uint32_t ToJ2000Time(const base::Time& time) {
36   return std::max(time.ToTimeT(), kJ2000ToTimeT) - kJ2000ToTimeT;
37 }
38 
FromJ2000Time(uint32_t time)39 base::Time FromJ2000Time(uint32_t time) {
40   return base::Time::FromTimeT(time + kJ2000ToTimeT);
41 }
42 
43 template <class T>
AppendToArray(T value,std::vector<uint8_t> * array)44 void AppendToArray(T value, std::vector<uint8_t>* array) {
45   auto begin = reinterpret_cast<const uint8_t*>(&value);
46   array->insert(array->end(), begin, begin + sizeof(value));
47 }
48 
49 class Caveat {
50  public:
Caveat(UwMacaroonCaveatType type,size_t str_len)51   Caveat(UwMacaroonCaveatType type, size_t str_len)
52       : buffer_(uw_macaroon_caveat_creation_get_buffsize_(type, str_len)) {
53     CHECK(!buffer_.empty());
54   }
GetCaveat() const55   const UwMacaroonCaveat& GetCaveat() const { return caveat_; }
56 
57  protected:
58   UwMacaroonCaveat caveat_{};
59   std::vector<uint8_t> buffer_;
60 
61   DISALLOW_COPY_AND_ASSIGN(Caveat);
62 };
63 
64 class ScopeCaveat : public Caveat {
65  public:
ScopeCaveat(UwMacaroonCaveatScopeType scope)66   explicit ScopeCaveat(UwMacaroonCaveatScopeType scope)
67       : Caveat(kUwMacaroonCaveatTypeScope, 0) {
68     CHECK(uw_macaroon_caveat_create_scope_(scope, buffer_.data(),
69                                            buffer_.size(), &caveat_));
70   }
71 
72   DISALLOW_COPY_AND_ASSIGN(ScopeCaveat);
73 };
74 
75 class TimestampCaveat : public Caveat {
76  public:
TimestampCaveat(const base::Time & timestamp)77   explicit TimestampCaveat(const base::Time& timestamp)
78       : Caveat(kUwMacaroonCaveatTypeDelegationTimestamp, 0) {
79     CHECK(uw_macaroon_caveat_create_delegation_timestamp_(
80         ToJ2000Time(timestamp), buffer_.data(), buffer_.size(), &caveat_));
81   }
82 
83   DISALLOW_COPY_AND_ASSIGN(TimestampCaveat);
84 };
85 
86 class ExpirationCaveat : public Caveat {
87  public:
ExpirationCaveat(const base::Time & timestamp)88   explicit ExpirationCaveat(const base::Time& timestamp)
89       : Caveat(kUwMacaroonCaveatTypeExpirationAbsolute, 0) {
90     CHECK(uw_macaroon_caveat_create_expiration_absolute_(
91         ToJ2000Time(timestamp), buffer_.data(), buffer_.size(), &caveat_));
92   }
93 
94   DISALLOW_COPY_AND_ASSIGN(ExpirationCaveat);
95 };
96 
97 class UserIdCaveat : public Caveat {
98  public:
UserIdCaveat(const std::vector<uint8_t> & id)99   explicit UserIdCaveat(const std::vector<uint8_t>& id)
100       : Caveat(kUwMacaroonCaveatTypeDelegateeUser, id.size()) {
101     CHECK(uw_macaroon_caveat_create_delegatee_user_(
102         id.data(), id.size(), buffer_.data(), buffer_.size(), &caveat_));
103   }
104 
105   DISALLOW_COPY_AND_ASSIGN(UserIdCaveat);
106 };
107 
108 class AppIdCaveat : public Caveat {
109  public:
AppIdCaveat(const std::vector<uint8_t> & id)110   explicit AppIdCaveat(const std::vector<uint8_t>& id)
111       : Caveat(kUwMacaroonCaveatTypeDelegateeApp, id.size()) {
112     CHECK(uw_macaroon_caveat_create_delegatee_app_(
113         id.data(), id.size(), buffer_.data(), buffer_.size(), &caveat_));
114   }
115 
116   DISALLOW_COPY_AND_ASSIGN(AppIdCaveat);
117 };
118 
119 class ServiceCaveat : public Caveat {
120  public:
ServiceCaveat(const std::string & id)121   explicit ServiceCaveat(const std::string& id)
122       : Caveat(kUwMacaroonCaveatTypeDelegateeService, id.size()) {
123     CHECK(uw_macaroon_caveat_create_delegatee_service_(
124         reinterpret_cast<const uint8_t*>(id.data()), id.size(), buffer_.data(),
125         buffer_.size(), &caveat_));
126   }
127 
128   DISALLOW_COPY_AND_ASSIGN(ServiceCaveat);
129 };
130 
131 class SessionIdCaveat : public Caveat {
132  public:
SessionIdCaveat(const std::string & id)133   explicit SessionIdCaveat(const std::string& id)
134       : Caveat(kUwMacaroonCaveatTypeLanSessionID, id.size()) {
135     CHECK(uw_macaroon_caveat_create_lan_session_id_(
136         reinterpret_cast<const uint8_t*>(id.data()), id.size(), buffer_.data(),
137         buffer_.size(), &caveat_));
138   }
139 
140   DISALLOW_COPY_AND_ASSIGN(SessionIdCaveat);
141 };
142 
143 class ClientAuthTokenCaveat : public Caveat {
144  public:
ClientAuthTokenCaveat()145   ClientAuthTokenCaveat()
146       : Caveat(kUwMacaroonCaveatTypeClientAuthorizationTokenV1, 0) {
147     CHECK(uw_macaroon_caveat_create_client_authorization_token_(
148         nullptr, 0, buffer_.data(), buffer_.size(), &caveat_));
149   }
150 
151   DISALLOW_COPY_AND_ASSIGN(ClientAuthTokenCaveat);
152 };
153 
CreateSecret()154 std::vector<uint8_t> CreateSecret() {
155   std::vector<uint8_t> secret(kSha256OutputSize);
156   base::RandBytes(secret.data(), secret.size());
157   return secret;
158 }
159 
IsClaimAllowed(RootClientTokenOwner curret,RootClientTokenOwner claimer)160 bool IsClaimAllowed(RootClientTokenOwner curret, RootClientTokenOwner claimer) {
161   return claimer > curret || claimer == RootClientTokenOwner::kCloud;
162 }
163 
CreateMacaroonToken(const std::vector<uint8_t> & secret,const base::Time & time,const std::vector<const UwMacaroonCaveat * > & caveats)164 std::vector<uint8_t> CreateMacaroonToken(
165     const std::vector<uint8_t>& secret,
166     const base::Time& time,
167     const std::vector<const UwMacaroonCaveat*>& caveats) {
168   CHECK_EQ(kSha256OutputSize, secret.size());
169 
170   UwMacaroonContext context{};
171   CHECK(uw_macaroon_context_create_(ToJ2000Time(time), nullptr, 0, &context));
172 
173   UwMacaroon macaroon{};
174   CHECK(uw_macaroon_create_from_root_key_(&macaroon, secret.data(),
175                                           secret.size(), &context,
176                                           caveats.data(), caveats.size()));
177 
178   std::vector<uint8_t> serialized_token(kMaxMacaroonSize);
179   size_t len = 0;
180   CHECK(uw_macaroon_serialize_(&macaroon, serialized_token.data(),
181                                serialized_token.size(), &len));
182   serialized_token.resize(len);
183 
184   return serialized_token;
185 }
186 
ExtendMacaroonToken(const UwMacaroon & macaroon,const base::Time & time,const std::vector<const UwMacaroonCaveat * > & caveats)187 std::vector<uint8_t> ExtendMacaroonToken(
188     const UwMacaroon& macaroon,
189     const base::Time& time,
190     const std::vector<const UwMacaroonCaveat*>& caveats) {
191   UwMacaroonContext context{};
192   CHECK(uw_macaroon_context_create_(ToJ2000Time(time), nullptr, 0, &context));
193 
194   UwMacaroon prev_macaroon = macaroon;
195   std::vector<uint8_t> prev_buffer(kMaxMacaroonSize);
196   std::vector<uint8_t> new_buffer(kMaxMacaroonSize);
197 
198   for (auto caveat : caveats) {
199     UwMacaroon new_macaroon{};
200     CHECK(uw_macaroon_extend_(&prev_macaroon, &new_macaroon, &context, caveat,
201                               new_buffer.data(), new_buffer.size()));
202     new_buffer.swap(prev_buffer);
203     prev_macaroon = new_macaroon;
204   }
205 
206   std::vector<uint8_t> serialized_token(kMaxMacaroonSize);
207   size_t len = 0;
208   CHECK(uw_macaroon_serialize_(&prev_macaroon, serialized_token.data(),
209                                serialized_token.size(), &len));
210   serialized_token.resize(len);
211 
212   return serialized_token;
213 }
214 
LoadMacaroon(const std::vector<uint8_t> & token,std::vector<uint8_t> * buffer,UwMacaroon * macaroon,ErrorPtr * error)215 bool LoadMacaroon(const std::vector<uint8_t>& token,
216                   std::vector<uint8_t>* buffer,
217                   UwMacaroon* macaroon,
218                   ErrorPtr* error) {
219   buffer->resize(kMaxMacaroonSize);
220   if (!uw_macaroon_deserialize_(token.data(), token.size(), buffer->data(),
221                                 buffer->size(), macaroon)) {
222     return Error::AddTo(error, FROM_HERE, kInvalidTokenError,
223                         "Invalid token format");
224   }
225   return true;
226 }
227 
VerifyMacaroon(const std::vector<uint8_t> & secret,const UwMacaroon & macaroon,const base::Time & time,UwMacaroonValidationResult * result,ErrorPtr * error)228 bool VerifyMacaroon(const std::vector<uint8_t>& secret,
229                     const UwMacaroon& macaroon,
230                     const base::Time& time,
231                     UwMacaroonValidationResult* result,
232                     ErrorPtr* error) {
233   CHECK_EQ(kSha256OutputSize, secret.size());
234   UwMacaroonContext context = {};
235   CHECK(uw_macaroon_context_create_(ToJ2000Time(time), nullptr, 0, &context));
236 
237   if (!uw_macaroon_validate_(&macaroon, secret.data(), secret.size(), &context,
238                              result)) {
239     return Error::AddTo(error, FROM_HERE, "invalid_token",
240                         "Invalid token signature");
241   }
242   return true;
243 }
244 
ToMacaroonScope(AuthScope scope)245 UwMacaroonCaveatScopeType ToMacaroonScope(AuthScope scope) {
246   switch (scope) {
247     case AuthScope::kViewer:
248       return kUwMacaroonCaveatScopeTypeViewer;
249     case AuthScope::kUser:
250       return kUwMacaroonCaveatScopeTypeUser;
251     case AuthScope::kManager:
252       return kUwMacaroonCaveatScopeTypeManager;
253     case AuthScope::kOwner:
254       return kUwMacaroonCaveatScopeTypeOwner;
255     default:
256       NOTREACHED() << EnumToString(scope);
257   }
258   return kUwMacaroonCaveatScopeTypeViewer;
259 }
260 
FromMacaroonScope(uint32_t scope)261 AuthScope FromMacaroonScope(uint32_t scope) {
262   if (scope <= kUwMacaroonCaveatScopeTypeOwner)
263     return AuthScope::kOwner;
264   if (scope <= kUwMacaroonCaveatScopeTypeManager)
265     return AuthScope::kManager;
266   if (scope <= kUwMacaroonCaveatScopeTypeUser)
267     return AuthScope::kUser;
268   if (scope <= kUwMacaroonCaveatScopeTypeViewer)
269     return AuthScope::kViewer;
270   return AuthScope::kNone;
271 }
272 
273 }  // namespace
274 
AuthManager(Config * config,const std::vector<uint8_t> & certificate_fingerprint)275 AuthManager::AuthManager(Config* config,
276                          const std::vector<uint8_t>& certificate_fingerprint)
277     : config_{config},
278       certificate_fingerprint_{certificate_fingerprint},
279       access_secret_{CreateSecret()} {
280   if (config_) {
281     SetAuthSecret(config_->GetSettings().secret,
282                   config_->GetSettings().root_client_token_owner);
283   } else {
284     SetAuthSecret({}, RootClientTokenOwner::kNone);
285   }
286 }
287 
AuthManager(const std::vector<uint8_t> & auth_secret,const std::vector<uint8_t> & certificate_fingerprint,const std::vector<uint8_t> & access_secret,base::Clock * clock)288 AuthManager::AuthManager(const std::vector<uint8_t>& auth_secret,
289                          const std::vector<uint8_t>& certificate_fingerprint,
290                          const std::vector<uint8_t>& access_secret,
291                          base::Clock* clock)
292     : AuthManager(nullptr, certificate_fingerprint) {
293   access_secret_ = access_secret.size() == kSha256OutputSize ? access_secret
294                                                              : CreateSecret();
295   SetAuthSecret(auth_secret, RootClientTokenOwner::kNone);
296   if (clock)
297     clock_ = clock;
298 }
299 
SetAuthSecret(const std::vector<uint8_t> & secret,RootClientTokenOwner owner)300 void AuthManager::SetAuthSecret(const std::vector<uint8_t>& secret,
301                                 RootClientTokenOwner owner) {
302   auth_secret_ = secret;
303 
304   if (auth_secret_.size() != kSha256OutputSize) {
305     auth_secret_ = CreateSecret();
306     owner = RootClientTokenOwner::kNone;
307   }
308 
309   if (!config_ || (config_->GetSettings().secret == auth_secret_ &&
310                    config_->GetSettings().root_client_token_owner == owner)) {
311     return;
312   }
313 
314   Config::Transaction change{config_};
315   change.set_secret(secret);
316   change.set_root_client_token_owner(owner);
317   change.Commit();
318 }
319 
~AuthManager()320 AuthManager::~AuthManager() {}
321 
CreateAccessToken(const UserInfo & user_info,base::TimeDelta ttl) const322 std::vector<uint8_t> AuthManager::CreateAccessToken(const UserInfo& user_info,
323                                                     base::TimeDelta ttl) const {
324   const base::Time now = Now();
325   TimestampCaveat issued{now};
326   ScopeCaveat scope{ToMacaroonScope(user_info.scope())};
327   // Macaroons have no caveats for auth type. So we just append the type to the
328   // user ID.
329   std::vector<uint8_t> id_with_type{user_info.id().user};
330   id_with_type.push_back(static_cast<uint8_t>(user_info.id().type));
331   UserIdCaveat user{id_with_type};
332   AppIdCaveat app{user_info.id().app};
333   ExpirationCaveat expiration{now + ttl};
334   return CreateMacaroonToken(
335       access_secret_, now,
336       {
337 
338           &issued.GetCaveat(), &scope.GetCaveat(), &user.GetCaveat(),
339           &app.GetCaveat(), &expiration.GetCaveat(),
340       });
341 }
342 
ParseAccessToken(const std::vector<uint8_t> & token,UserInfo * user_info,ErrorPtr * error) const343 bool AuthManager::ParseAccessToken(const std::vector<uint8_t>& token,
344                                    UserInfo* user_info,
345                                    ErrorPtr* error) const {
346   std::vector<uint8_t> buffer;
347   UwMacaroon macaroon{};
348 
349   UwMacaroonValidationResult result{};
350   const base::Time now = Now();
351   if (!LoadMacaroon(token, &buffer, &macaroon, error) ||
352       macaroon.num_caveats != 5 ||
353       !VerifyMacaroon(access_secret_, macaroon, now, &result, error)) {
354     return Error::AddTo(error, FROM_HERE, errors::kInvalidAuthorization,
355                         "Invalid token");
356   }
357 
358   AuthScope auth_scope{FromMacaroonScope(result.granted_scope)};
359   if (auth_scope == AuthScope::kNone) {
360     return Error::AddTo(error, FROM_HERE, errors::kInvalidAuthorization,
361                         "Invalid token data");
362   }
363 
364   // If token is valid and token was not extended, it should has precisely this
365   // values.
366   CHECK_GE(FromJ2000Time(result.expiration_time), now);
367   CHECK_EQ(2u, result.num_delegatees);
368   CHECK_EQ(kUwMacaroonDelegateeTypeUser, result.delegatees[0].type);
369   CHECK_EQ(kUwMacaroonDelegateeTypeApp, result.delegatees[1].type);
370   CHECK_GT(result.delegatees[0].id_len, 1u);
371   std::vector<uint8_t> user_id{
372       result.delegatees[0].id,
373       result.delegatees[0].id + result.delegatees[0].id_len};
374   // Last byte is used for type. See |CreateAccessToken|.
375   AuthType type = static_cast<AuthType>(user_id.back());
376   user_id.pop_back();
377 
378   std::vector<uint8_t> app_id{
379       result.delegatees[1].id,
380       result.delegatees[1].id + result.delegatees[1].id_len};
381   if (user_info)
382     *user_info = UserInfo{auth_scope, UserAppId{type, user_id, app_id}};
383 
384   return true;
385 }
386 
ClaimRootClientAuthToken(RootClientTokenOwner owner,ErrorPtr * error)387 std::vector<uint8_t> AuthManager::ClaimRootClientAuthToken(
388     RootClientTokenOwner owner,
389     ErrorPtr* error) {
390   CHECK(RootClientTokenOwner::kNone != owner);
391   if (config_) {
392     auto current = config_->GetSettings().root_client_token_owner;
393     if (!IsClaimAllowed(current, owner)) {
394       Error::AddToPrintf(error, FROM_HERE, errors::kAlreadyClaimed,
395                          "Device already claimed by '%s'",
396                          EnumToString(current).c_str());
397       return {};
398     }
399   };
400 
401   pending_claims_.push_back(std::make_pair(
402       std::unique_ptr<AuthManager>{new AuthManager{nullptr, {}}}, owner));
403   if (pending_claims_.size() > kMaxPendingClaims)
404     pending_claims_.pop_front();
405   return pending_claims_.back().first->GetRootClientAuthToken(owner);
406 }
407 
ConfirmClientAuthToken(const std::vector<uint8_t> & token,ErrorPtr * error)408 bool AuthManager::ConfirmClientAuthToken(const std::vector<uint8_t>& token,
409                                          ErrorPtr* error) {
410   // Cover case when caller sent confirm twice.
411   if (pending_claims_.empty())
412     return IsValidAuthToken(token, error);
413 
414   auto claim =
415       std::find_if(pending_claims_.begin(), pending_claims_.end(),
416                    [&token](const decltype(pending_claims_)::value_type& auth) {
417                      return auth.first->IsValidAuthToken(token, nullptr);
418                    });
419   if (claim == pending_claims_.end()) {
420     return Error::AddTo(error, FROM_HERE, errors::kNotFound, "Unknown claim");
421   }
422 
423   SetAuthSecret(claim->first->GetAuthSecret(), claim->second);
424   pending_claims_.clear();
425   return true;
426 }
427 
GetRootClientAuthToken(RootClientTokenOwner owner) const428 std::vector<uint8_t> AuthManager::GetRootClientAuthToken(
429     RootClientTokenOwner owner) const {
430   CHECK(RootClientTokenOwner::kNone != owner);
431   ClientAuthTokenCaveat auth_token;
432   const base::Time now = Now();
433   TimestampCaveat issued{now};
434 
435   ServiceCaveat client{owner == RootClientTokenOwner::kCloud ? "google.com"
436                                                              : ""};
437   return CreateMacaroonToken(
438       auth_secret_, now,
439       {
440           &auth_token.GetCaveat(), &issued.GetCaveat(), &client.GetCaveat(),
441       });
442 }
443 
Now() const444 base::Time AuthManager::Now() const {
445   return clock_->Now();
446 }
447 
IsValidAuthToken(const std::vector<uint8_t> & token,ErrorPtr * error) const448 bool AuthManager::IsValidAuthToken(const std::vector<uint8_t>& token,
449                                    ErrorPtr* error) const {
450   std::vector<uint8_t> buffer;
451   UwMacaroon macaroon{};
452   UwMacaroonValidationResult result{};
453   if (!LoadMacaroon(token, &buffer, &macaroon, error) ||
454       !VerifyMacaroon(auth_secret_, macaroon, Now(), &result, error)) {
455     return Error::AddTo(error, FROM_HERE, errors::kInvalidAuthCode,
456                         "Invalid token");
457   }
458   return true;
459 }
460 
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) const461 bool AuthManager::CreateAccessTokenFromAuth(
462     const std::vector<uint8_t>& auth_token,
463     base::TimeDelta ttl,
464     std::vector<uint8_t>* access_token,
465     AuthScope* access_token_scope,
466     base::TimeDelta* access_token_ttl,
467     ErrorPtr* error) const {
468   std::vector<uint8_t> buffer;
469   UwMacaroon macaroon{};
470   UwMacaroonValidationResult result{};
471   const base::Time now = Now();
472   if (!LoadMacaroon(auth_token, &buffer, &macaroon, error) ||
473       !VerifyMacaroon(auth_secret_, macaroon, now, &result, error)) {
474     return Error::AddTo(error, FROM_HERE, errors::kInvalidAuthCode,
475                         "Invalid token");
476   }
477 
478   AuthScope auth_scope{FromMacaroonScope(result.granted_scope)};
479   if (auth_scope == AuthScope::kNone) {
480     return Error::AddTo(error, FROM_HERE, errors::kInvalidAuthCode,
481                         "Invalid token data");
482   }
483 
484   // TODO: Integrate black list checks.
485   auto delegates_rbegin = std::reverse_iterator<const UwMacaroonDelegateeInfo*>(
486       result.delegatees + result.num_delegatees);
487   auto delegates_rend =
488       std::reverse_iterator<const UwMacaroonDelegateeInfo*>(result.delegatees);
489   auto last_user_id =
490       std::find_if(delegates_rbegin, delegates_rend,
491                    [](const UwMacaroonDelegateeInfo& delegatee) {
492                      return delegatee.type == kUwMacaroonDelegateeTypeUser;
493                    });
494   auto last_app_id =
495       std::find_if(delegates_rbegin, delegates_rend,
496                    [](const UwMacaroonDelegateeInfo& delegatee) {
497                      return delegatee.type == kUwMacaroonDelegateeTypeApp;
498                    });
499 
500   if (last_user_id == delegates_rend || !last_user_id->id_len) {
501     return Error::AddTo(error, FROM_HERE, errors::kInvalidAuthCode,
502                         "User ID is missing");
503   }
504 
505   const char* session_id = reinterpret_cast<const char*>(result.lan_session_id);
506   if (!IsValidSessionId({session_id, session_id + result.lan_session_id_len})) {
507     return Error::AddTo(error, FROM_HERE, errors::kInvalidAuthCode,
508                         "Invalid session id");
509   }
510 
511   CHECK_GE(FromJ2000Time(result.expiration_time), now);
512 
513   if (!access_token)
514     return true;
515 
516   std::vector<uint8_t> user_id{last_user_id->id,
517                                last_user_id->id + last_user_id->id_len};
518   std::vector<uint8_t> app_id;
519   if (last_app_id != delegates_rend)
520     app_id.assign(last_app_id->id, last_app_id->id + last_app_id->id_len);
521 
522   UserInfo info{auth_scope, {AuthType::kLocal, user_id, app_id}};
523 
524   ttl = std::min(ttl, FromJ2000Time(result.expiration_time) - now);
525   *access_token = CreateAccessToken(info, ttl);
526 
527   if (access_token_scope)
528     *access_token_scope = info.scope();
529 
530   if (access_token_ttl)
531     *access_token_ttl = ttl;
532   return true;
533 }
534 
CreateSessionId() const535 std::string AuthManager::CreateSessionId() const {
536   return std::to_string(ToJ2000Time(Now())) + ":" +
537          std::to_string(++session_counter_);
538 }
539 
IsValidSessionId(const std::string & session_id) const540 bool AuthManager::IsValidSessionId(const std::string& session_id) const {
541   base::Time ssid_time = FromJ2000Time(std::atoi(session_id.c_str()));
542   return Now() - base::TimeDelta::FromMinutes(kSessionIdTtlMinutes) <=
543              ssid_time &&
544          ssid_time <= Now();
545 }
546 
DelegateToUser(const std::vector<uint8_t> & token,base::TimeDelta ttl,const UserInfo & user_info) const547 std::vector<uint8_t> AuthManager::DelegateToUser(
548     const std::vector<uint8_t>& token,
549     base::TimeDelta ttl,
550     const UserInfo& user_info) const {
551   std::vector<uint8_t> buffer;
552   UwMacaroon macaroon{};
553   CHECK(LoadMacaroon(token, &buffer, &macaroon, nullptr));
554 
555   const base::Time now = Now();
556   TimestampCaveat issued{now};
557   ExpirationCaveat expiration{now + ttl};
558   ScopeCaveat scope{ToMacaroonScope(user_info.scope())};
559   UserIdCaveat user{user_info.id().user};
560   AppIdCaveat app{user_info.id().app};
561   SessionIdCaveat session{CreateSessionId()};
562 
563   std::vector<const UwMacaroonCaveat*> caveats{
564       &issued.GetCaveat(), &expiration.GetCaveat(), &scope.GetCaveat(),
565       &user.GetCaveat(),
566   };
567 
568   if (!user_info.id().app.empty())
569     caveats.push_back(&app.GetCaveat());
570 
571   caveats.push_back(&session.GetCaveat());
572 
573   return ExtendMacaroonToken(macaroon, now, caveats);
574 }
575 
576 }  // namespace privet
577 }  // namespace weave
578