| // Copyright 2018 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef CHROME_CREDENTIAL_PROVIDER_GAIACP_GAIA_CREDENTIAL_PROVIDER_H_ |
| #define CHROME_CREDENTIAL_PROVIDER_GAIACP_GAIA_CREDENTIAL_PROVIDER_H_ |
| |
| #include <limits> |
| #include <memory> |
| #include <set> |
| #include <vector> |
| |
| #include "base/strings/string16.h" |
| #include "base/synchronization/lock.h" |
| #include "base/synchronization/waitable_event.h" |
| #include "base/win/scoped_handle.h" |
| #include "chrome/credential_provider/gaiacp/gaia_credential.h" |
| #include "chrome/credential_provider/gaiacp/gaia_credential_provider_i.h" |
| #include "chrome/credential_provider/gaiacp/gaia_resources.h" |
| |
| namespace credential_provider { |
| |
| class BackgroundTokenHandleUpdater; |
| |
| // Event handler that can be notified when a user's access has been revoked, |
| // allowing the credential provider to update the list of available credentials. |
| class ICredentialUpdateEventsHandler { |
| public: |
| virtual ~ICredentialUpdateEventsHandler() = default; |
| virtual void UpdateCredentialsIfNeeded(bool user_access_changed) = 0; |
| }; |
| |
| // Implementation of ICredentialProvider backed by Gaia. |
| class ATL_NO_VTABLE CGaiaCredentialProvider |
| : public CComObjectRootEx<CComMultiThreadModel>, |
| public CComCoClass<CGaiaCredentialProvider, |
| &CLSID_GaiaCredentialProvider>, |
| public IGaiaCredentialProvider, |
| public ICredentialProviderSetUserArray, |
| public ICredentialProvider, |
| public ICredentialUpdateEventsHandler { |
| public: |
| // This COM object is registered with the rgs file. The rgs file is used by |
| // CGaiaCredentialProviderModule class, see latter for details. |
| DECLARE_NO_REGISTRY() |
| |
| CGaiaCredentialProvider(); |
| ~CGaiaCredentialProvider() override; |
| |
| BEGIN_COM_MAP(CGaiaCredentialProvider) |
| COM_INTERFACE_ENTRY(IGaiaCredentialProvider) |
| COM_INTERFACE_ENTRY(ICredentialProviderSetUserArray) |
| COM_INTERFACE_ENTRY(ICredentialProvider) |
| END_COM_MAP() |
| |
| DECLARE_PROTECT_FINAL_CONSTRUCT() |
| |
| HRESULT FinalConstruct(); |
| void FinalRelease(); |
| |
| // ICredentialUpdateEventsHandler: |
| void UpdateCredentialsIfNeeded(bool user_access_changed) override; |
| |
| // Returns true if the given usage scenario is supported by GCPW. Currently |
| // only CPUS_LOGON and CPUS_UNLOCK_WORKSTATION are supported. |
| static bool IsUsageScenarioSupported(CREDENTIAL_PROVIDER_USAGE_SCENARIO cpus); |
| |
| // Returns true if a new user can be added in the current usage scenario. This |
| // function also checks other settings controlled by registry settings to |
| // determine the result of this query. |
| static bool CanNewUsersBeCreated(CREDENTIAL_PROVIDER_USAGE_SCENARIO cpus); |
| |
| private: |
| HRESULT DestroyCredentials(); |
| |
| // Struct to allow passing CComPtr by pointer without the implicit conversion |
| // to ** version of the CComPtr |
| struct ComPtrStorage { |
| ComPtrStorage(); |
| ~ComPtrStorage(); |
| CComPtr<IGaiaCredential> gaia_cred; |
| }; |
| |
| // Class used to store state information for the provider that may be accessed |
| // concurrently. This class is thread safe and ensures that the correct state |
| // can be set / queried at any moment. When modifying the state, the modifying |
| // function will return true to state that the operation was completed |
| // successfully to allow the caller to determine if they need to raise a |
| // credential changed event. |
| class ProviderConcurrentState { |
| public: |
| ProviderConcurrentState(); |
| ~ProviderConcurrentState(); |
| |
| // Checks if a user refresh can be performed on the next call to |
| // |GetCredentialCount|. Normally a user refresh is only needed if |
| // |user_access_changed|, but if an auto logon is pending the refresh will |
| // need to be deferred. In this case a pending refresh is queued and |
| // requested when possible on the next call to RequestUserRefreshIfNeeded. |
| // Returns true if a new credential changed event needs to be fired. |
| bool RequestUserRefreshIfNeeded(bool user_access_changed); |
| |
| // Sets the credential used to auto logon credential. This function will |
| // always set the credential as auto logon has precedence over a user |
| // refresh. If a user refresh was already requested then it will be changed |
| // to a pending refresh request. Returns true if a new credential changed |
| // event needs to be fired. A credential changed event is not always |
| // required if a previous call to RequestUserRefreshIfNeeded was made that |
| // requested a credential changed event. |
| bool SetAutoLogonCredential( |
| const CComPtr<IGaiaCredential>& auto_logon_credential); |
| |
| // Gets the current valid update state of the provider to determnie whether |
| // an auto logon needs to be done or a refresh of the credentials. The two |
| // update states are mutually exclusive. Only one of |
| // |needs_to_refresh_users| and |auto_logon_credential| can be set to a non |
| // default value. |
| void GetUpdatedState(bool* needs_to_refresh_users, |
| ComPtrStorage* auto_logon_credential); |
| |
| // Resets the state of the provider to be default one. On the next call to |
| // GetCredentialCount no auto logon should be performed and no refresh of |
| // credentials should be done. |
| void Reset(); |
| |
| private: |
| void InternalReset(); |
| |
| // Reference to the credential that authenticated the user. |
| CComPtr<IGaiaCredential> auto_logon_credential_; |
| |
| // Set in NotifyUserAccessDenied to notify the main thread that it will need |
| // to update credentials on the next call to GetCredentialCount. This |
| // ensures that |users_| is only accessed on the main thread. This member |
| // can only be accessed on multiple threads if |token_handle_updater_| is |
| // instantiated, which only occurs between a call to Advise and UnAdvise. |
| bool users_need_to_be_refreshed_ = false; |
| |
| // Used to queue up user refresh requests that had to be deferred because |
| // |auto_logon_credential_| has precedence over |
| // |users_need_to_be_refreshed_|. |
| bool pending_users_refresh_needed_ = false; |
| |
| // Locks access to |users_need_to_be_refreshed_| and |
| // |auto_logon_credential_| to prevent races between calls to |
| // OnUserAuthenticated / GetCredentialCount and calls to |
| // NotifyUserAccessDenied. |
| base::Lock state_update_lock_; |
| }; |
| |
| // Functions to create credentials during the processing of SetUserArray. |
| |
| // Creates necessary anonymous credentials given the state of the sign in |
| // screen (currently only whether |showing_other_user| set influences this |
| // behavior. |
| HRESULT CreateAnonymousCredentialIfNeeded(bool showing_other_user); |
| |
| // Creates all the reauth credentials from the users that is returned from |
| // |users|. Fills the |gaia_cred| in |auto_logon_credential| with a reference |
| // to the credential that needs to perform auto logon (if any). |
| HRESULT CreateReauthCredentials(ICredentialProviderUserArray* users, |
| ComPtrStorage* auto_logon_credential); |
| |
| // This function will always add |cred| to |users_| and will also try to check |
| // if the |sid| matches the one set in |set_serialization_sid_| to allow auto |
| // logon of remote connections. Fills the |gaia_cred| in |
| // |auto_logon_credential| with a reference to the credential that needs to |
| // perform auto logon (if any). |
| void AddCredentialAndCheckAutoLogon(const CComPtr<IGaiaCredential>& cred, |
| const base::string16& sid, |
| ComPtrStorage* auto_logon_credential); |
| |
| // Destroys existing credentials and recreates them based on the contents of |
| // |user_array_|. This member must be set via a call to SetUserArray before |
| // RecreateCredentials is called. Fills the |gaia_cred| in |
| // |auto_logon_credential| with a reference to the credential that needs to |
| // perform auto logon (if any). |
| void RecreateCredentials(ComPtrStorage* auto_logon_credential); |
| |
| void ClearTransient(); |
| void CleanupOlderVersions(); |
| |
| // IGaiaCredentialProvider |
| IFACEMETHODIMP GetUsageScenario(DWORD* cpus) override; |
| IFACEMETHODIMP OnUserAuthenticated(IUnknown* credential, |
| BSTR username, |
| BSTR password, |
| BSTR sid, |
| BOOL fire_credentials_changed) override; |
| |
| // ICredentialProviderSetUserArray |
| IFACEMETHODIMP SetUserArray(ICredentialProviderUserArray* users) override; |
| |
| // ICredentialProvider |
| IFACEMETHODIMP SetUsageScenario(CREDENTIAL_PROVIDER_USAGE_SCENARIO cpus, |
| DWORD dwFlags) override; |
| IFACEMETHODIMP SetSerialization( |
| const CREDENTIAL_PROVIDER_CREDENTIAL_SERIALIZATION* pcpcs) override; |
| IFACEMETHODIMP Advise(ICredentialProviderEvents* pcpe, |
| UINT_PTR upAdviseContext) override; |
| IFACEMETHODIMP UnAdvise() override; |
| IFACEMETHODIMP GetFieldDescriptorCount(DWORD* pdwCount) override; |
| IFACEMETHODIMP GetFieldDescriptorAt( |
| DWORD dwIndex, |
| CREDENTIAL_PROVIDER_FIELD_DESCRIPTOR** ppcpfd) override; |
| IFACEMETHODIMP GetCredentialCount(DWORD* pdwCount, |
| DWORD* pdwDefault, |
| BOOL* pbAutoLogonWithDefault) override; |
| IFACEMETHODIMP GetCredentialAt( |
| DWORD dwIndex, |
| ICredentialProviderCredential** ppcpc) override; |
| |
| CREDENTIAL_PROVIDER_USAGE_SCENARIO cpus_ = CPUS_INVALID; |
| DWORD cpus_flags_ = 0; |
| UINT_PTR advise_context_; |
| CComPtr<ICredentialProviderEvents> events_; |
| CComPtr<ICredentialProviderUserArray> user_array_; |
| |
| // List of credentials exposed by this provider. The first is always the |
| // Gaia credential for creating new users. The rest are reauth credentials. |
| std::vector<CComPtr<IGaiaCredential>> users_; |
| |
| // Reference to the credential that authenticated the user. |
| CComPtr<IGaiaCredential> auto_logon_credential_; |
| |
| // Background thread updater of token handles that is created on startup to |
| // ensure that user must sign in through gaia if their token handle becomes |
| // invalid while idle on the sign in screen. The updater will also handle the |
| // situation where the machine becomes unenrolled from MDM during sign in. |
| std::unique_ptr<BackgroundTokenHandleUpdater> token_handle_updater_; |
| |
| // The SID extracted from the serialization information passed into |
| // SetSerialization. This sid is used to determine which credential to try |
| // to auto logon when GetCredentialCount is called. |
| base::string16 set_serialization_sid_; |
| |
| ProviderConcurrentState concurrent_state_; |
| }; |
| |
| // OBJECT_ENTRY_AUTO() contains an extra semicolon. |
| // TODO(thakis): Make -Wextra-semi not warn on semicolons that are from a |
| // macro in a system header, then remove the pragma, https://llvm.org/PR40874 |
| #if defined(__clang__) |
| #pragma clang diagnostic push |
| #pragma clang diagnostic ignored "-Wextra-semi" |
| #endif |
| |
| OBJECT_ENTRY_AUTO(__uuidof(GaiaCredentialProvider), CGaiaCredentialProvider) |
| |
| #if defined(__clang__) |
| #pragma clang diagnostic pop |
| #endif |
| |
| } // namespace credential_provider |
| |
| #endif // CHROME_CREDENTIAL_PROVIDER_GAIACP_GAIA_CREDENTIAL_PROVIDER_H_ |