chromium/chromeos/ash/components/osauth/impl/auth_hub_attempt_handler.h

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

#ifndef CHROMEOS_ASH_COMPONENTS_OSAUTH_IMPL_AUTH_HUB_ATTEMPT_HANDLER_H_
#define CHROMEOS_ASH_COMPONENTS_OSAUTH_IMPL_AUTH_HUB_ATTEMPT_HANDLER_H_

#include <optional>

#include "base/callback_list.h"
#include "base/component_export.h"
#include "base/containers/flat_map.h"
#include "base/functional/callback.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "chromeos/ash/components/osauth/impl/auth_hub_common.h"
#include "chromeos/ash/components/osauth/public/auth_factor_engine.h"
#include "chromeos/ash/components/osauth/public/auth_factor_status_consumer.h"
#include "chromeos/ash/components/osauth/public/common_types.h"

namespace ash {

// This class handles all post-initialization interaction with
// `AuthFactorEngine`s during single authentication flow (specified by
// AuthAttemptVector).
// It combines events from individual `AuthFactorEngine`s, calculates
// resulting factor's status, and notifies `AuthFactorStatusConsumer`
// upon all changes.
// This class also enables/disables `AuthFactorEngine`s according to
// their status/parallel authentication attempts; it also tracks
// overall authentication success.
//
// This class is re-created every time owning `AuthHub` starts new,
// user authentication attempt.

class COMPONENT_EXPORT(CHROMEOS_ASH_COMPONENTS_OSAUTH) AuthHubAttemptHandler
    : public AuthFactorEngine::FactorEngineObserver,
      public AuthHubConnector {
 public:
  // Interface to interact with owning AuthHub:
  class COMPONENT_EXPORT(CHROMEOS_ASH_COMPONENTS_OSAUTH) Owner {
   public:
    virtual ~Owner();
    virtual void UpdateFactorUiCache(const AuthAttemptVector& attempt,
                                     AuthFactorsSet configured_factors) = 0;
    virtual void OnAuthenticationSuccess(const AuthAttemptVector& attempt,
                                         AshAuthFactor factor) = 0;
    virtual void OnFactorAttemptFailed(const AuthAttemptVector& attempt,
                                       AshAuthFactor factor) = 0;
  };

  AuthHubAttemptHandler(Owner* owner,
                        const AuthAttemptVector& attempt,
                        const AuthEnginesMap& engines,
                        AuthFactorsSet expected_factors);
  ~AuthHubAttemptHandler() override;

  AuthHubConnector* GetConnector();
  void SetConsumer(raw_ptr<AuthFactorStatusConsumer> consumer);

  // Returns true if there is an ongoing factor attempt.
  bool HasOngoingAttempt() const;

  // Waits for the result of ongoing factor attempt, and calls
  // `callback`, without re-enabling engines.
  void PrepareForShutdown(base::OnceClosure callback);

  // This method is called by owning AuthHub once VectorLifecycle
  // starts all auth engines.
  // This method notifies StatusConsumer about finalized factors list,
  // notifies Owner if cache needs to be updated,
  // and enables all applicable factors to handle authentication attempts.
  void OnFactorsChecked(AuthFactorsSet available_factors,
                        AuthFactorsSet failed_factors);

  // AuthFactorEngine::FactorEngineObserver:
  void OnFactorPresenceChecked(AshAuthFactor factor,
                               bool factor_present) override;
  void OnFactorAttempt(AshAuthFactor factor) override;
  void OnFactorAttemptResult(AshAuthFactor factor, bool success) override;
  void OnPolicyChanged(AshAuthFactor factor) override;
  void OnLockoutChanged(AshAuthFactor factor) override;
  void OnFactorSpecificRestrictionsChanged(AshAuthFactor factor) override;
  void OnCriticalError(AshAuthFactor factor) override;
  void OnFactorCustomSignal(AshAuthFactor factor) override;
  // AuthHubConnector:
  AuthFactorEngine* GetEngine(AshAuthFactor factor) override;

 private:
  // See also a comment for `AuthFactorState`.
  struct FactorAttemptState {
    // Factor is considered failed, no updates / auth attempts
    // should happen for the factor.
    bool engine_failed = false;
    // Reasons for disabling factor:
    bool disabled_by_policy = false;
    bool locked_out = false;
    bool factor_specific_restricted = false;
    // Up-to date usage value for the engine, might not be propagated to
    // engine yet.
    AuthFactorEngine::UsageAllowed intended_usage =
        AuthFactorEngine::UsageAllowed::kDisabled;
    // Latest value propagated to the engine.
    AuthFactorEngine::UsageAllowed engine_usage =
        AuthFactorEngine::UsageAllowed::kDisabled;

    // Up-to date state of the factor, might be not reported to
    // `AuthFactorStatusConsumer` yet.
    AuthFactorState internal_state = AuthFactorState::kCheckingForPresence;
    // Latest value reported to 'AuthFactorStatusConsumer'.
    AuthFactorState reported_state = AuthFactorState::kCheckingForPresence;
  };

  void FillAllStatusValues(AshAuthFactor factor, FactorAttemptState& state);
  void CalculateFactorState(AshAuthFactor factor, FactorAttemptState& state);
  void PropagateEnginesEnabledStatus();
  void PropagateStatusUpdates();
  void UpdateAllFactorStates();

  // TODO(b/271248452): Those `raw_ptr`s are currently dangling due to a problem
  // with the destruction order. Something causes those ptrs to be freed before
  // the execution reaches the destruction of this class. Likely a higher level
  // component in the ownership graph has the objects pointed to below and the
  // current class as downstream dependencies.
  raw_ptr<Owner, DanglingUntriaged> owner_;
  raw_ptr<AuthFactorStatusConsumer, DanglingUntriaged> status_consumer_;

  AuthAttemptVector attempt_;
  AuthEnginesMap engines_;
  AuthFactorsSet initial_factors_;

  AuthFactorsSet available_factors_;

  base::flat_map<AshAuthFactor, FactorAttemptState> factor_state_;

  std::optional<AshAuthFactor> ongoing_attempt_factor_;
  bool authenticated_ = false;

  bool shutting_down_ = false;

  base::OnceCallbackList<void(void)> shutdown_callbacks_;

  base::WeakPtrFactory<AuthHubAttemptHandler> weak_factory_{this};
};

}  // namespace ash

#endif  // CHROMEOS_ASH_COMPONENTS_OSAUTH_IMPL_AUTH_HUB_ATTEMPT_HANDLER_H_