blob: 38dfd80f65faaf095f1aedb38478128b4e1b63ac [file] [log] [blame]
// 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 IOS_CHROME_BROWSER_SIGNIN_MODEL_SYSTEM_IDENTITY_MANAGER_H_
#define IOS_CHROME_BROWSER_SIGNIN_MODEL_SYSTEM_IDENTITY_MANAGER_H_
#import <UIKit/UIKit.h>
#include <map>
#include <optional>
#include <set>
#include <string>
#include <vector>
#include "base/functional/callback.h"
#include "base/observer_list.h"
#include "base/sequence_checker.h"
#include "base/time/time.h"
#include "base/types/expected.h"
#include "ios/chrome/browser/signin/model/capabilities_types.h"
#include "ios/chrome/browser/signin/model/system_identity_manager_observer.h"
@protocol RefreshAccessTokenError;
@protocol SystemIdentity;
@protocol SystemIdentityInteractionManager;
class SystemIdentityManagerObserver;
// SystemIdentityManager is Chrome's interface to the iOS shared authentication
// library: It provides access to accounts on the device and information about
// them, independent of whether or not the user is signed in to Chrome, and
// whether the accounts were added through Chrome or through some other Google
// app. It also allows adding accounts to the device via
// `SystemIdentityInteractionManager`, and displaying some account-related UIs.
class SystemIdentityManager {
public:
using CapabilityResult = SystemIdentityCapabilityResult;
// Value returned by IdentityIteratorCallback.
enum class IteratorResult {
kContinueIteration,
kInterruptIteration,
};
// Value representing an OAuth access token.
struct AccessTokenInfo {
// The access token itself.
std::string token;
// The time at which this access token will expire. This will be set to the
// NULL time value of `base::Time()` when no expiration time is available.
base::Time expiration_time;
};
// Struct to hold all the parameters needed to present a dialog like
// WebAndAppSettingDetails, AccountDetails or LinkedServicesSettingsDetails.
struct PresentDialogConfiguration {
public:
// Identity to use for the dialog to present.
id<SystemIdentity> identity;
// View controller who present the dialog.
UIViewController* view_controller;
// Whether the presentation should be animated or not.
bool animated;
// Completion block that will be called once the dialog is dismissed.
base::OnceClosure dismissal_completion;
PresentDialogConfiguration();
~PresentDialogConfiguration();
PresentDialogConfiguration(PresentDialogConfiguration&&);
PresentDialogConfiguration(const PresentDialogConfiguration&) = delete;
PresentDialogConfiguration& operator=(const PresentDialogConfiguration&) =
delete;
};
// Callback invoked for each id<SystemIdentity> when iterating over them
// with `IterateOverIdentities()`. The returned value can be used to stop
// the iteration prematurely.
using IdentityIteratorCallback =
base::RepeatingCallback<IteratorResult(id<SystemIdentity>)>;
// Callback returned when presenting an account detail view. This callback
// can be invoked to dismiss the view (with animation if `animated` is true).
using DismissViewCallback = base::OnceCallback<void(bool animated)>;
// Callback invoked when the `ForgetIdentity()` operation completes.
using ForgetIdentityCallback = base::OnceCallback<void(NSError*)>;
// Callback invoked when the `GetAccessToken()` operation completes.
using AccessTokenCallback =
base::OnceCallback<void(std::optional<AccessTokenInfo>, NSError*)>;
// Callback invoked when the `GetHostedDomain()` operation completes.
using HostedDomainCallback = base::OnceCallback<void(NSString*, NSError*)>;
// Callback invoked when the `FetchTokenAuthURL()` operation completes.
using AuthenticatedURLCallback = base::OnceCallback<void(NSURL*, NSError*)>;
// Callback invoked when `IsSubjectToParentalControls()` operations complete.
using FetchCapabilityCallback = base::OnceCallback<void(CapabilityResult)>;
// Callback invoked when the `FetchCapabilitie()` operation completes.
using FetchCapabilitiesCallback =
base::OnceCallback<void(std::map<std::string, CapabilityResult>)>;
// Callback invoked when `HandleMDMNotification` completes. Is is invoked
// with a boolean indicating whether the device is blocked or not.
using HandleMDMCallback = base::OnceCallback<void(bool)>;
SystemIdentityManager();
SystemIdentityManager(const SystemIdentityManager&) = delete;
SystemIdentityManager& operator=(const SystemIdentityManager&) = delete;
virtual ~SystemIdentityManager();
// Asynchronously returns the value of the account capability that determines
// whether parental controls should be applied to `identity`.
//
// This is a wrapper around `FetchCapabilities()`.
void IsSubjectToParentalControls(id<SystemIdentity> identity,
FetchCapabilityCallback callback);
// Adds/removes observers.
void AddObserver(SystemIdentityManagerObserver* observer);
void RemoveObserver(SystemIdentityManagerObserver* observer);
// Presents a new Account Details view and returns a callback that can be
// used to dismiss the view (can be ignored if not needed).
// * `identity` is the identity used to present the view.
// * `view_controller` is the view used to present the details.
// * `animated` controls whether the view is presented with an animation.
// * `dismissal_completion` is called once the dialog is dismissed.
DismissViewCallback PresentAccountDetailsController(
id<SystemIdentity> identity,
UIViewController* view_controller,
bool animated,
base::OnceClosure dismissal_completion);
// Presents a new Web and App Setting Details view and returns a callback
// that can be used to dismiss the view (can be ignore if not needed).
// * `identity` is the identity used to present the view.
// * `view_controller` is the view used to present the details.
// * `animated` controls whether the view is presented with an animation.
// * `dismissal_completion` is called once the dialog is dismissed.
DismissViewCallback PresentWebAndAppSettingDetailsController(
id<SystemIdentity> identity,
UIViewController* view_controller,
bool animated,
base::OnceClosure dismissal_completion);
// Presents a new Linked Services Settings Details view and returns a callback
// that can be used to dismiss the view (can be ignore if not needed).
// * `identity` is the identity used to present the view.
// * `view_controller` is the view used to present the details.
// * `animated` controls whether the view is presented with an animation.
// * `dismissal_completion` is called once the dialog is dismissed.
DismissViewCallback PresentLinkedServicesSettingsDetailsController(
id<SystemIdentity> identity,
UIViewController* view_controller,
bool animated,
base::OnceClosure dismissal_completion);
// Returns whether signin is supported by the provider.
virtual bool IsSigninSupported() = 0;
// Handles open URL authentication callback. Should be called within
// `-[UISceneDelegate application:openURLContexts:]` context. Returns
// whether one the URLs was actually handled.
virtual bool HandleSessionOpenURLContexts(
UIScene* scene,
NSSet<UIOpenURLContext*>* url_contexts) = 0;
// Discards scene session data. Should be called within
// `-[UIApplicationDelegate application:didDiscardSceneSessions:]`.
virtual void ApplicationDidDiscardSceneSessions(
NSSet<UISceneSession*>* scene_sessions) = 0;
// Dismisses all the dialogs created by the abstracted flows.
virtual void DismissDialogs() = 0;
// Creates a new SystemIdentityInteractionManager instance.
virtual id<SystemIdentityInteractionManager> CreateInteractionManager() = 0;
// Iterates over all known identities, sortted by the ordering used in
// account manager, which is typically based on the keychain ordering
// of the accounts.
virtual void IterateOverIdentities(IdentityIteratorCallback callback) = 0;
// Asynchronously forgets `identity` and logs the user out. The callback
// is invoked on the calling sequence when the operation completes.
virtual void ForgetIdentity(id<SystemIdentity> identity,
ForgetIdentityCallback callback) = 0;
// Returns true if the identity was removed by calling `ForgetIdentity()`.
// Returns false If the identity was not removed or disappeared without
// calling `ForgetIdentity()`.
virtual bool IdentityRemovedByUser(NSString* gaia_id) = 0;
// Asynchronously retrieves access tokens for `identity` with `scopes`. The
// callback is invoked on the calling sequence when the operation completes.
// Uses the default client id and client secret.
virtual void GetAccessToken(id<SystemIdentity> identity,
const std::set<std::string>& scopes,
AccessTokenCallback callback) = 0;
// Asynchronously retrieves access tokens for `identity` with `scopes`. The
// callback is invoked on the calling sequence when the operation completes.
virtual void GetAccessToken(id<SystemIdentity> identity,
const std::string& client_id,
const std::set<std::string>& scopes,
AccessTokenCallback callback) = 0;
// Asynchronously fetches the avatar for `identity` from the network and
// store it in the cache. The image can be large to avoid pixelation on
// high resolution devices. Observers will be notified when the avatar is
// available by the `OnIdentityUpdated()` method.
virtual void FetchAvatarForIdentity(id<SystemIdentity> identity) = 0;
// Synchronously returns the last cached avatar for `identity`. Should be
// preceded by a call to `FetchAvatarForIdentity()` to populate the cache.
virtual UIImage* GetCachedAvatarForIdentity(id<SystemIdentity> identity) = 0;
// Asynchronously fetch the identity hosted domain. The callback is invoked
// on the calling sequence when the operation completes.
virtual void GetHostedDomain(id<SystemIdentity> identity,
HostedDomainCallback callback) = 0;
// Returns the hosted domain for `identity` from the cache. Returns:
// + nil if the hosted domain value has not been fetched from the server,
// + an empty string if this is a consumer account (e.g. foo@gmail.com),
// + the hosted domain as a non-empty string otherwise.
virtual NSString* GetCachedHostedDomainForIdentity(
id<SystemIdentity> identity) = 0;
// Asynchronously returns the capabilities for `identity`.
virtual void FetchCapabilities(id<SystemIdentity> identity,
const std::vector<std::string>& names,
FetchCapabilitiesCallback callback) = 0;
// Asynchronously handles a potential MDM (Mobile Device Management) event.
// The callback is invoked on the calling sequence when the operation
// completes.
// Returns YES if the device status is blocked.
virtual bool HandleMDMNotification(
id<SystemIdentity> identity,
NSArray<id<SystemIdentity>>* active_identities,
id<RefreshAccessTokenError> error,
HandleMDMCallback callback) = 0;
// Returns whether the `error` is due to restricted access to the scopes in
// the access token request.
// TODO(crbug.com/425592221): Convert to pure virtual method.
virtual bool IsScopeLimitedError(id<RefreshAccessTokenError> error);
// Returns whether the `error` associated with `identity` is due to MDM
// (Mobile Device Management) or not.
virtual bool IsMDMError(id<SystemIdentity> identity, NSError* error) = 0;
// Asynchronously fetches the token auth URL that can be used to
// authorize a webview for the given identity.
// The callback is invoked on the calling sequence when the operation
// completes.
virtual void FetchTokenAuthURL(id<SystemIdentity> identity,
NSURL* target_url,
AuthenticatedURLCallback callback) = 0;
protected:
// Invokes `OnIdentityListChanged(...)` for all observers.
void FireIdentityListChanged();
// Invokes `OnIdentityUpdated(...)` for all observers.
void FireIdentityUpdated(id<SystemIdentity> identity);
// Invokes OnIdentityRefreshTokenUpdated(...)` for all observers.
void FireIdentityRefreshTokenUpdated(id<SystemIdentity> identity);
// Invokes OnIdentityAccessTokenRefreshFailed(...)` for all observers.
void FireIdentityAccessTokenRefreshFailed(
id<SystemIdentity> identity,
id<RefreshAccessTokenError> error,
const std::set<std::string>& scopes);
// Presents a new Account Details view and returns a callback that can be
// used to dismiss the view (can be ignore if not needed).
virtual DismissViewCallback PresentAccountDetailsController(
PresentDialogConfiguration configuration) = 0;
// Presents a new Web and App Setting Details view and returns a callback
// that can be used to dismiss the view (can be ignore if not needed).
virtual DismissViewCallback PresentWebAndAppSettingDetailsController(
PresentDialogConfiguration configuration) = 0;
// Presents a new Linked Services Settings Details view and returns a callback
// that can be used to dismiss the view (can be ignore if not needed).
virtual DismissViewCallback PresentLinkedServicesSettingsDetailsController(
PresentDialogConfiguration configuration) = 0;
// The SystemIdentityManager is sequence-affine. This is protected to
// allow sub-classes access to the member field for use in DCHECK().
SEQUENCE_CHECKER(sequence_checker_);
private:
// Registered observers.
base::ObserverList<SystemIdentityManagerObserver, true> observers_;
};
#endif // IOS_CHROME_BROWSER_SIGNIN_MODEL_SYSTEM_IDENTITY_MANAGER_H_