chromium/chrome/browser/ash/printing/oauth2/authorization_zone_impl.h

// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef CHROME_BROWSER_ASH_PRINTING_OAUTH2_AUTHORIZATION_ZONE_IMPL_H_
#define CHROME_BROWSER_ASH_PRINTING_OAUTH2_AUTHORIZATION_ZONE_IMPL_H_

#include <list>
#include <map>
#include <memory>
#include <string>

#include "base/containers/flat_set.h"
#include "base/memory/scoped_refptr.h"
#include "chrome/browser/ash/printing/oauth2/authorization_server_data.h"
#include "chrome/browser/ash/printing/oauth2/authorization_zone.h"
#include "chrome/browser/ash/printing/oauth2/status_code.h"
#include "chromeos/printing/uri.h"
#include "url/gurl.h"

namespace network {
class SharedURLLoaderFactory;
}  // namespace network

namespace ash {
namespace printing {
namespace oauth2 {

class AuthorizationServerSession;
class ClientIdsDatabase;
class IppEndpointTokenFetcher;

// The class AuthorizationZoneImpl implements functionality described in
// AuthorizationZone interface.
//
class AuthorizationZoneImpl : public AuthorizationZone {
 public:
  // `client_ids_database` cannot be nullptr and must outlive this object.
  AuthorizationZoneImpl(
      scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
      const GURL& authorization_server_uri,
      ClientIdsDatabase* client_ids_database);

  AuthorizationZoneImpl(const AuthorizationZoneImpl&) = delete;
  AuthorizationZoneImpl& operator=(const AuthorizationZoneImpl&) = delete;
  ~AuthorizationZoneImpl() override;

  // AuthorizationZone interface.
  void InitAuthorization(const std::string& scope,
                         StatusCallback callback) override;
  void FinishAuthorization(const GURL& redirect_url,
                           StatusCallback callback) override;
  void GetEndpointAccessToken(const chromeos::Uri& ipp_endpoint,
                              const std::string& scope,
                              StatusCallback callback) override;
  void MarkEndpointAccessTokenAsExpired(
      const chromeos::Uri& ipp_endpoint,
      const std::string& endpoint_access_token) override;
  void MarkAuthorizationZoneAsUntrusted() override;

 private:
  // This method processes (and removes) all elements from
  // `waiting_authorizations_` by initiating authorization procedures for them.
  void AuthorizationProcedure();

  // Callback for AuthorizationServerData::Initialize().
  void OnInitializeCallback(StatusCode status, std::string data);

  // Callback for AuthorizationServerSession::SendFirstTokenRequest() and
  // AuthorizationServerSession::SendNextTokenRequest().
  void OnSendTokenRequestCallback(AuthorizationServerSession* session,
                                  StatusCode status,
                                  std::string data);

  // Callback for IppEndpointTokenFetcher::SendTokenExchangeRequest(...).
  void OnTokenExchangeRequestCallback(const chromeos::Uri& ipp_endpoint,
                                      StatusCode status,
                                      std::string data);

  // Executes all callbacks from the waitlist of `ipp_endpoint`. Also, removes
  // `ipp_endpoint` when `status` != StatusCode::kOK.
  void ResultForIppEndpoint(const chromeos::Uri& ipp_endpoint,
                            StatusCode status,
                            std::string data);

  // This callback is added to the waitlist of AuthorizationSession when
  // `ipp_endpoint` must wait for the access token from it.
  void OnAccessTokenForEndpointCallback(const chromeos::Uri& ipp_endpoint,
                                        StatusCode status,
                                        std::string data);

  // Tries to find OAuth session for given IPP Endpoint and send Token Exchange
  // request to obtain an endpoint access token.
  void AttemptTokenExchange(IppEndpointTokenFetcher* it_endpoint);

  // Finds an element in `pending_authorizations_` with given `state` and remove
  // it. Returns false if such element does not exists. Otherwise, returns true
  // and returns the content of the element in the last two parameters.
  bool FindAndRemovePendingAuthorization(const std::string& state,
                                         base::flat_set<std::string>& scopes,
                                         std::string& code_verifier);

  // Represents started authorization procedure waiting for opening
  // communication with the server. This object is created when
  // InitAuthorization() is called and its callback does not return yet.
  struct WaitingAuthorization {
    WaitingAuthorization(base::flat_set<std::string>&& scopes,
                         StatusCallback callback);
    WaitingAuthorization(const WaitingAuthorization&) = delete;
    WaitingAuthorization& operator=(const WaitingAuthorization&) = delete;
    ~WaitingAuthorization();
    base::flat_set<std::string> scopes;
    StatusCallback callback;
  };

  // Represents started authorization procedure. This object is created when
  // InitAuthorization() is called and is destroyed in the corresponding
  // FinishAuthorization() call.
  struct PendingAuthorization {
    PendingAuthorization(base::flat_set<std::string>&& scopes,
                         std::string&& state,
                         std::string&& code_verifier);
    PendingAuthorization(const PendingAuthorization&) = delete;
    PendingAuthorization& operator=(const PendingAuthorization&) = delete;
    ~PendingAuthorization();
    base::flat_set<std::string> scopes;
    // Values used in the current authorization process.
    std::string state;
    std::string code_verifier;
  };

  // Holds basic parameters of the Authorization Server.
  AuthorizationServerData server_data_;

  // List of InitAuthorization() calls being processed.
  std::list<WaitingAuthorization> waiting_authorizations_;

  // List of completed InitAuthorization() calls waiting for the corresponding
  // FinishAuthorization() call.
  std::list<PendingAuthorization> pending_authorizations_;

  // List of active OAuth2 sessions.
  std::list<std::unique_ptr<AuthorizationServerSession>> sessions_;

  // List of IPP Endpoints for which an endpoint access token was requested.
  std::map<chromeos::Uri, std::unique_ptr<IppEndpointTokenFetcher>>
      ipp_endpoints_;

  scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_;
};

}  // namespace oauth2
}  // namespace printing
}  // namespace ash

#endif  // CHROME_BROWSER_ASH_PRINTING_OAUTH2_AUTHORIZATION_ZONE_IMPL_H_