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