File: trusted_vault_access_token_fetcher_frontend.cc

package info (click to toggle)
chromium 139.0.7258.127-1
  • links: PTS, VCS
  • area: main
  • in suites:
  • size: 6,122,068 kB
  • sloc: cpp: 35,100,771; ansic: 7,163,530; javascript: 4,103,002; python: 1,436,920; asm: 946,517; xml: 746,709; pascal: 187,653; perl: 88,691; sh: 88,436; objc: 79,953; sql: 51,488; cs: 44,583; fortran: 24,137; makefile: 22,147; tcl: 15,277; php: 13,980; yacc: 8,984; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (142 lines) | stat: -rw-r--r-- 5,678 bytes parent folder | download | duplicates (5)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "components/trusted_vault/trusted_vault_access_token_fetcher_frontend.h"

#include <utility>

#include "base/types/expected.h"
#include "components/signin/public/identity_manager/access_token_info.h"
#include "components/signin/public/identity_manager/primary_account_access_token_fetcher.h"
#include "components/trusted_vault/trusted_vault_access_token_fetcher.h"

namespace trusted_vault {

namespace {
const char kCryptAuthOAuth2Scope[] =
    "https://www.googleapis.com/auth/cryptauth";

void FulfillPendingRequests(
    std::vector<TrustedVaultAccessTokenFetcher::TokenCallback> pending_requests,
    TrustedVaultAccessTokenFetcher::AccessTokenInfoOrError
        access_token_or_error) {
  for (TrustedVaultAccessTokenFetcher::TokenCallback& pending_request :
       pending_requests) {
    std::move(pending_request).Run(access_token_or_error);
  }
}

}  // namespace

TrustedVaultAccessTokenFetcherFrontend::TrustedVaultAccessTokenFetcherFrontend(
    signin::IdentityManager* identity_manager)
    : identity_manager_(identity_manager) {
  DCHECK(identity_manager_);
  identity_manager_observation_.Observe(identity_manager_);
  UpdatePrimaryAccountIfNeeded();
}

TrustedVaultAccessTokenFetcherFrontend::
    ~TrustedVaultAccessTokenFetcherFrontend() = default;

base::WeakPtr<TrustedVaultAccessTokenFetcherFrontend>
TrustedVaultAccessTokenFetcherFrontend::GetWeakPtr() {
  return weak_ptr_factory_.GetWeakPtr();
}

void TrustedVaultAccessTokenFetcherFrontend::FetchAccessToken(
    const CoreAccountId& account_id,
    TrustedVaultAccessTokenFetcher::TokenCallback callback) {
  if (account_id != primary_account_) {
    // The requester is likely not aware of a recent change to the primary
    // account yet (this is possible because requests come from another
    // sequence). Run |callback| immediately without access token.
    // Although |account_id| can be in persistent auth error state, it's not
    // relevant here since primary account change is the main reason for
    // returning nullopt, so passing false is fine.
    std::move(callback).Run(base::unexpected(
        TrustedVaultAccessTokenFetcher::FetchingError::kNotPrimaryAccount));
    return;
  }

  pending_requests_.emplace_back(std::move(callback));
  if (ongoing_access_token_fetch_ == nullptr) {
    StartAccessTokenFetch();
  }
}

void TrustedVaultAccessTokenFetcherFrontend::OnPrimaryAccountChanged(
    const signin::PrimaryAccountChangeEvent& event) {
  UpdatePrimaryAccountIfNeeded();
}

void TrustedVaultAccessTokenFetcherFrontend::OnIdentityManagerShutdown(
    signin::IdentityManager* identity_manager) {
  CHECK_EQ(identity_manager, identity_manager_);
  identity_manager_observation_.Reset();
}

void TrustedVaultAccessTokenFetcherFrontend::UpdatePrimaryAccountIfNeeded() {
  CoreAccountInfo primary_account_info =
      identity_manager_->GetPrimaryAccountInfo(signin::ConsentLevel::kSignin);
  if (primary_account_info.account_id == primary_account_) {
    return;
  }

  ongoing_access_token_fetch_ = nullptr;
  primary_account_ = primary_account_info.account_id;

  // Fulfill |pending_requests_| since they belong to the previous
  // |primary_account_|.
  FulfillPendingRequestsAndMaybeDestroySelf(base::unexpected(
      TrustedVaultAccessTokenFetcher::FetchingError::kNotPrimaryAccount));
}

void TrustedVaultAccessTokenFetcherFrontend::StartAccessTokenFetch() {
  DCHECK(!ongoing_access_token_fetch_);
  // Use kWaitUntilAvailable to avoid failed fetches while refresh tokens are
  // still loading. Note, that it doesn't cause infinite waits for persistent
  // auth errors.
  ongoing_access_token_fetch_ = std::make_unique<
      signin::PrimaryAccountAccessTokenFetcher>(
      /*ouath_consumer_name=*/"TrustedVaultAccessTokenFetcherFrontend",
      identity_manager_, signin::ScopeSet{kCryptAuthOAuth2Scope},
      base::BindOnce(
          &TrustedVaultAccessTokenFetcherFrontend::OnAccessTokenFetchCompleted,
          base::Unretained(this)),
      signin::PrimaryAccountAccessTokenFetcher::Mode::kWaitUntilAvailable,
      signin::ConsentLevel::kSignin);
}

void TrustedVaultAccessTokenFetcherFrontend::OnAccessTokenFetchCompleted(
    GoogleServiceAuthError error,
    signin::AccessTokenInfo access_token_info) {
  ongoing_access_token_fetch_ = nullptr;
  if (error.state() == GoogleServiceAuthError::NONE) {
    FulfillPendingRequestsAndMaybeDestroySelf(access_token_info);
  } else if (error.IsPersistentError()) {
    FulfillPendingRequestsAndMaybeDestroySelf(base::unexpected(
        TrustedVaultAccessTokenFetcher::FetchingError::kPersistentAuthError));
  } else {
    FulfillPendingRequestsAndMaybeDestroySelf(base::unexpected(
        TrustedVaultAccessTokenFetcher::FetchingError::kTransientAuthError));
  }
}

void TrustedVaultAccessTokenFetcherFrontend::
    FulfillPendingRequestsAndMaybeDestroySelf(
        TrustedVaultAccessTokenFetcher::AccessTokenInfoOrError
            access_token_or_error) {
  // Move the pending requests to a local variable to avoid UAF in case
  // the callbacks synchronously destroy `this`.
  // TODO(crbug.com/427316421): The cleaner fix would be to make sure that all
  // callbacks run asynchronously (currently it is not the case with
  // EnclaveManager if error happens while fetching access token).
  std::vector<TrustedVaultAccessTokenFetcher::TokenCallback> pending_requests =
      std::move(pending_requests_);
  pending_requests_.clear();
  FulfillPendingRequests(std::move(pending_requests), access_token_or_error);
}

}  // namespace trusted_vault