From 2e9e21aee6806063bdb763ed8278c6f25b66c577 Mon Sep 17 00:00:00 2001 From: Ryan Newington Date: Thu, 17 Oct 2024 07:41:11 +1100 Subject: [PATCH 1/6] Add ReloadUserTiles method and update IsAutoLogon property - Added ReloadUserTiles method to CredentialProviderBase to notify LogonUI of tile modifications. - Introduced private field isAutoLogon in CredentialTile. - Updated IsAutoLogon property in CredentialTile to use a backing field and call ReloadUserTiles on set. - Corrected typo in XML documentation for CreateParentWindowHwnd method. --- .../CredentialProviderBase.cs | 8 ++++++++ src/Lithnet.CredentialProvider/CredentialTile.cs | 14 ++++++++++++-- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/src/Lithnet.CredentialProvider/CredentialProviderBase.cs b/src/Lithnet.CredentialProvider/CredentialProviderBase.cs index 3568fb1..7501830 100644 --- a/src/Lithnet.CredentialProvider/CredentialProviderBase.cs +++ b/src/Lithnet.CredentialProvider/CredentialProviderBase.cs @@ -114,6 +114,14 @@ namespace Lithnet.CredentialProvider /// Gets a value that indicates if the credential provider should show a generic tile. That is, a tile that is not associated with a specific user. /// public abstract bool ShouldIncludeGenericTile(); + + /// + /// Notifies LogonUI that one of more of the tile items has been modified, and should be reloaded + /// + public void ReloadUserTiles() + { + this.NotifyHostOfTileCollectionChange(); + } /// /// Adds additional user tiles to the collection, and notifies LogonUI that new tiles are available diff --git a/src/Lithnet.CredentialProvider/CredentialTile.cs b/src/Lithnet.CredentialProvider/CredentialTile.cs index 9afcac7..f756f59 100644 --- a/src/Lithnet.CredentialProvider/CredentialTile.cs +++ b/src/Lithnet.CredentialProvider/CredentialTile.cs @@ -15,6 +15,7 @@ namespace Lithnet.CredentialProvider private protected ICredentialProviderCredentialEvents2 events2; private protected ControlCollection controls; + private bool isAutoLogon; protected CredentialTile(CredentialProviderBase credentialProvider) { @@ -37,7 +38,16 @@ namespace Lithnet.CredentialProvider /// /// Gets a value that indicates if the user should be automatically logged on when the tile is selected. The tile must also have IsDefault set to true. /// - public bool IsAutoLogon { get; set; } + public bool IsAutoLogon + { + get => this.isAutoLogon; + set + { + this.isAutoLogon = value; + this.CredentialProvider.ReloadUserTiles(); + + } + } /// /// Gets a value indicating if this should be the default time @@ -87,7 +97,7 @@ namespace Lithnet.CredentialProvider /// Gets the HWND of the parent of the credential provider, and notifies LogonUI or CredUI that we need to create a Window /// /// A HWND to the parentobject - /// The method was called before the host has advised that is ready to rpovide events + /// The method was called before the host has advised that is ready to provide events /// The request to obtain the parent window HWND failed public IntPtr CreateParentWindowHwnd() { From 96bff2852a66dab11322f4acc74906e07cb2529d Mon Sep 17 00:00:00 2001 From: Ryan Newington Date: Fri, 18 Oct 2024 10:33:41 +1100 Subject: [PATCH 2/6] Breaking change: Add autoLogon parameter to OnSelected method Modified the `OnSelected` method in the `CredentialTile` class to include an `out` parameter named `autoLogon`, which determines if the logon should proceed immediately. Updated XML documentation to explain the new parameter and its behavior in Windows 10. Adjusted the `SetSelected` method in `CredentialTile.ICredentialProviderCredential` to call the updated `OnSelected` method and set `pbAutoLogon` based on the returned `autoLogon` value. Removed the previous `OnSelected` implementation without parameters. There was confusion between a tile that is configured as a default auto logon tile, and a tile that can be auto logged-on when selecteed. This change clarifies the case of a tile allowing login when selected, without having to press a submit button. The AutoLogon propert of the CredentialTile object is no longer used in this scenario. Implementers must override OnSelected(out bool autoLogon) to automatically logon a tile when selected --- .../CredentialTile.ICredentialProviderCredential.cs | 4 ++-- src/Lithnet.CredentialProvider/CredentialTile.cs | 9 ++++++++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/Lithnet.CredentialProvider/CredentialTile.ICredentialProviderCredential.cs b/src/Lithnet.CredentialProvider/CredentialTile.ICredentialProviderCredential.cs index 81b0362..7b858aa 100644 --- a/src/Lithnet.CredentialProvider/CredentialTile.ICredentialProviderCredential.cs +++ b/src/Lithnet.CredentialProvider/CredentialTile.ICredentialProviderCredential.cs @@ -66,8 +66,8 @@ namespace Lithnet.CredentialProvider { this.logger.LogTrace("SetSelected"); this.IsSelected = true; - pbAutoLogon = this.IsAutoLogon ? 1 : 0; - this.OnSelected(); + this.OnSelected(out bool autoLogon); + pbAutoLogon = autoLogon ? 1 : 0; return HRESULT.S_OK; } catch (Exception ex) diff --git a/src/Lithnet.CredentialProvider/CredentialTile.cs b/src/Lithnet.CredentialProvider/CredentialTile.cs index f756f59..9290143 100644 --- a/src/Lithnet.CredentialProvider/CredentialTile.cs +++ b/src/Lithnet.CredentialProvider/CredentialTile.cs @@ -164,7 +164,14 @@ namespace Lithnet.CredentialProvider /// /// Called when the user selects this tile /// - protected virtual void OnSelected() { } + /// A value that indicates if logon should be performed immediately, without waiting for further user input + /// + /// In Windows 10, if a credential provider wants to automatically log the user on in a situation Windows does not think is appropriate, the system will display a sign in button as a speed bump. One example of this is when a user with an empty password locks the computer or signs out. In that scenario, Windows does not directly log the user back in. + /// + protected virtual void OnSelected(out bool autoLogon) + { + autoLogon = false; + } /// /// Called when a user deselects this tile From 3fe3999e0db4f728d5cd4fe9550a9ad827e34deb Mon Sep 17 00:00:00 2001 From: Ryan Newington Date: Mon, 21 Oct 2024 06:43:05 +1100 Subject: [PATCH 3/6] Refactor default and auto-logon tile handling Refactored `CredentialProviderBase` and `CredentialTile` to improve the handling of default and auto-logon tiles. Key changes include: - Introduced `SetDefaultTile` method with validation and tile refresh. - Refactored `IsAutoLogon` and `IsDefault` properties to be read only properties. - Added `ShouldAutoLogon` method to be called when a tile is selected. --- ...dentialProviderBase.ICredentialProvider.cs | 21 +++++++-------- .../CredentialProviderBase.cs | 24 ++++++++++++++++- ...ntialTile.ICredentialProviderCredential.cs | 4 +-- .../CredentialTile.cs | 27 +++++++++---------- 4 files changed, 47 insertions(+), 29 deletions(-) diff --git a/src/Lithnet.CredentialProvider/CredentialProviderBase.ICredentialProvider.cs b/src/Lithnet.CredentialProvider/CredentialProviderBase.ICredentialProvider.cs index a52a5e7..9d0cd1f 100644 --- a/src/Lithnet.CredentialProvider/CredentialProviderBase.ICredentialProvider.cs +++ b/src/Lithnet.CredentialProvider/CredentialProviderBase.ICredentialProvider.cs @@ -169,23 +169,20 @@ namespace Lithnet.CredentialProvider this.notifyOnTileCollectionChange = true; - var autoLogonTile = this.Tiles.FirstOrDefault(t => t.IsAutoLogon); - var defaultTile = this.Tiles.FirstOrDefault(t => t.IsDefault); + var defaultTile = this.DefaultTile; - uint defaultIndex = CREDENTIAL_PROVIDER_NO_DEFAULT; - if (autoLogonTile != null) + if (defaultTile != null) { - defaultIndex = (uint)this.tiles.IndexOf(autoLogonTile); - } - else if (defaultTile != null) - { - defaultIndex = (uint)this.tiles.IndexOf(defaultTile); + var index = this.tiles.IndexOf(defaultTile); + + if (index >= 0) + { + pdwDefault = (uint)index; + pbAutoLogonWithDefault = this.DefaultTileAutoLogon ? 1 : 0; + } } pdwCount = (uint)this.Tiles.Count; - pdwDefault = defaultIndex; - pbAutoLogonWithDefault = autoLogonTile == null ? 0 : 1; - this.logger.LogTrace($"GetCredentialCount returning pdwCount: {pdwCount}, pdwDefault: {pdwDefault}, pbAutoLogonWithDefault: {pbAutoLogonWithDefault}"); return HRESULT.S_OK; diff --git a/src/Lithnet.CredentialProvider/CredentialProviderBase.cs b/src/Lithnet.CredentialProvider/CredentialProviderBase.cs index 7501830..b1fb490 100644 --- a/src/Lithnet.CredentialProvider/CredentialProviderBase.cs +++ b/src/Lithnet.CredentialProvider/CredentialProviderBase.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Reflection; using System.Runtime.InteropServices; using Lithnet.CredentialProvider.Interop; @@ -114,7 +115,28 @@ namespace Lithnet.CredentialProvider /// Gets a value that indicates if the credential provider should show a generic tile. That is, a tile that is not associated with a specific user. /// public abstract bool ShouldIncludeGenericTile(); - + + protected internal CredentialTile DefaultTile { get; set; } + + protected internal bool DefaultTileAutoLogon { get; set; } + + public void SetDefaultTile(CredentialTile tile, bool autoLogon) + { + if (this.DefaultTile == tile && this.DefaultTileAutoLogon == autoLogon) + { + return; + } + + if (!this.Tiles.Contains(tile)) + { + throw new InvalidOperationException("The default tile must be one of the tiles provided by the credential provider"); + } + + this.DefaultTile = tile; + this.DefaultTileAutoLogon = autoLogon; + this.ReloadUserTiles(); + } + /// /// Notifies LogonUI that one of more of the tile items has been modified, and should be reloaded /// diff --git a/src/Lithnet.CredentialProvider/CredentialTile.ICredentialProviderCredential.cs b/src/Lithnet.CredentialProvider/CredentialTile.ICredentialProviderCredential.cs index 7b858aa..90c348b 100644 --- a/src/Lithnet.CredentialProvider/CredentialTile.ICredentialProviderCredential.cs +++ b/src/Lithnet.CredentialProvider/CredentialTile.ICredentialProviderCredential.cs @@ -66,8 +66,8 @@ namespace Lithnet.CredentialProvider { this.logger.LogTrace("SetSelected"); this.IsSelected = true; - this.OnSelected(out bool autoLogon); - pbAutoLogon = autoLogon ? 1 : 0; + this.OnSelected(); + pbAutoLogon = this.ShouldAutoLogon() ? 1 : 0; return HRESULT.S_OK; } catch (Exception ex) diff --git a/src/Lithnet.CredentialProvider/CredentialTile.cs b/src/Lithnet.CredentialProvider/CredentialTile.cs index 9290143..28d652c 100644 --- a/src/Lithnet.CredentialProvider/CredentialTile.cs +++ b/src/Lithnet.CredentialProvider/CredentialTile.cs @@ -40,19 +40,16 @@ namespace Lithnet.CredentialProvider /// public bool IsAutoLogon { - get => this.isAutoLogon; - set - { - this.isAutoLogon = value; - this.CredentialProvider.ReloadUserTiles(); - - } + get => this.CredentialProvider.DefaultTile == this && this.CredentialProvider.DefaultTileAutoLogon; } /// - /// Gets a value indicating if this should be the default time + /// Gets a value indicating if this should be the default tile /// - public bool IsDefault { get; set; } + public bool IsDefault + { + get => this.CredentialProvider.DefaultTile == this; + } /// /// Gets the current usage scenario @@ -164,14 +161,16 @@ namespace Lithnet.CredentialProvider /// /// Called when the user selects this tile /// - /// A value that indicates if logon should be performed immediately, without waiting for further user input + protected virtual void OnSelected() { } + + /// + /// Called after a tiles is selected to determine if the user should be automatically logged on + /// + /// True, if a logon should be immediately attempted /// /// In Windows 10, if a credential provider wants to automatically log the user on in a situation Windows does not think is appropriate, the system will display a sign in button as a speed bump. One example of this is when a user with an empty password locks the computer or signs out. In that scenario, Windows does not directly log the user back in. /// - protected virtual void OnSelected(out bool autoLogon) - { - autoLogon = false; - } + protected virtual bool ShouldAutoLogon() => false; /// /// Called when a user deselects this tile From b82ae53c1d8b4b0ed6bf2ac1f4095d5a2325be83 Mon Sep 17 00:00:00 2001 From: Ryan Newington Date: Mon, 21 Oct 2024 06:45:48 +1100 Subject: [PATCH 4/6] Renamed properties --- src/Lithnet.CredentialProvider/CredentialTile.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Lithnet.CredentialProvider/CredentialTile.cs b/src/Lithnet.CredentialProvider/CredentialTile.cs index 28d652c..4cd1edc 100644 --- a/src/Lithnet.CredentialProvider/CredentialTile.cs +++ b/src/Lithnet.CredentialProvider/CredentialTile.cs @@ -38,7 +38,7 @@ namespace Lithnet.CredentialProvider /// /// Gets a value that indicates if the user should be automatically logged on when the tile is selected. The tile must also have IsDefault set to true. /// - public bool IsAutoLogon + public bool IsDefaultTileAutoLogon { get => this.CredentialProvider.DefaultTile == this && this.CredentialProvider.DefaultTileAutoLogon; } @@ -46,7 +46,7 @@ namespace Lithnet.CredentialProvider /// /// Gets a value indicating if this should be the default tile /// - public bool IsDefault + public bool IsDefaultTile { get => this.CredentialProvider.DefaultTile == this; } From eff21705921efa6449208300dfd660e2bf81bc31 Mon Sep 17 00:00:00 2001 From: Ryan Newington Date: Mon, 21 Oct 2024 06:48:44 +1100 Subject: [PATCH 5/6] Update method name --- .../CredentialTile.ICredentialProviderCredential.cs | 2 +- src/Lithnet.CredentialProvider/CredentialTile.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Lithnet.CredentialProvider/CredentialTile.ICredentialProviderCredential.cs b/src/Lithnet.CredentialProvider/CredentialTile.ICredentialProviderCredential.cs index 90c348b..247a9f6 100644 --- a/src/Lithnet.CredentialProvider/CredentialTile.ICredentialProviderCredential.cs +++ b/src/Lithnet.CredentialProvider/CredentialTile.ICredentialProviderCredential.cs @@ -67,7 +67,7 @@ namespace Lithnet.CredentialProvider this.logger.LogTrace("SetSelected"); this.IsSelected = true; this.OnSelected(); - pbAutoLogon = this.ShouldAutoLogon() ? 1 : 0; + pbAutoLogon = this.OnSelectedShouldAutoLogon() ? 1 : 0; return HRESULT.S_OK; } catch (Exception ex) diff --git a/src/Lithnet.CredentialProvider/CredentialTile.cs b/src/Lithnet.CredentialProvider/CredentialTile.cs index 4cd1edc..ab5de5e 100644 --- a/src/Lithnet.CredentialProvider/CredentialTile.cs +++ b/src/Lithnet.CredentialProvider/CredentialTile.cs @@ -170,7 +170,7 @@ namespace Lithnet.CredentialProvider /// /// In Windows 10, if a credential provider wants to automatically log the user on in a situation Windows does not think is appropriate, the system will display a sign in button as a speed bump. One example of this is when a user with an empty password locks the computer or signs out. In that scenario, Windows does not directly log the user back in. /// - protected virtual bool ShouldAutoLogon() => false; + protected virtual bool OnSelectedShouldAutoLogon() => false; /// /// Called when a user deselects this tile From 536cdf0e71100aabfa11370fa4b1577f3b3432ab Mon Sep 17 00:00:00 2001 From: Ryan Newington Date: Tue, 22 Oct 2024 07:48:16 +1100 Subject: [PATCH 6/6] Remove unused field --- src/Lithnet.CredentialProvider/CredentialTile.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Lithnet.CredentialProvider/CredentialTile.cs b/src/Lithnet.CredentialProvider/CredentialTile.cs index ab5de5e..2252f47 100644 --- a/src/Lithnet.CredentialProvider/CredentialTile.cs +++ b/src/Lithnet.CredentialProvider/CredentialTile.cs @@ -13,9 +13,7 @@ namespace Lithnet.CredentialProvider private protected readonly ICredentialProviderLogger logger; private protected ICredentialProviderCredentialEvents events; private protected ICredentialProviderCredentialEvents2 events2; - private protected ControlCollection controls; - private bool isAutoLogon; protected CredentialTile(CredentialProviderBase credentialProvider) {