![](https://github.com/lithnet/miis-powershell/wiki/images/logo-ex-small.png) # Windows Credential Provider ![](https://img.shields.io/nuget/vpre/lithnet.credentialprovider?label=Current%20prerelease)![](https://img.shields.io/nuget/v/Lithnet.CredentialProvider?label=Current%20release) ![](https://img.shields.io/nuget/dt/lithnet.credentialprovider) A library for creating secure Windows Credential Providers in .NET, without the COM complications. The Lithnet Credential Provider for Windows provides an easy way to create a credential provider, without having to implement the COM components. The COM components are still there, but abstracted away into a fully managed implementation. ## Getting started * Create a new Class Library project. You can use .NET Framework 4.7.2 or later, or .NET 8.0, 9.0, or 10.0. You must build an x64 or x86 binary. You cannot use AnyCPU. * Install the package from nuget `Install-Package Lithnet.CredentialProvider` * Modify the `csproj` file and set `RegisterForComInterop` to `false` ```xml net472 false x64 ``` * If you are using .NET 8.0, 9.0, or 10.0, you must also set `EnableComHosting` to `true`. ```xml net8.0-windows false x64 true ``` * Create a new class an inherit from `CredentialProviderBase`, as shown below, replacing the `ProgId` and `Guid` values with ones of your own ```cs [ComVisible(true)] [ClassInterface(ClassInterfaceType.None)] [ProgId("MyCredentialProvider")] [Guid("00000000-0000-0000-0000-000000000000")] public class MyCredentialProvider : CredentialProviderBase { } ``` * Override the `IsUsageScenarioSupported` method, to specify which scenarios you want to support with your credential provider ```cs public override bool IsUsageScenarioSupported(UsageScenario cpus, CredUIWinFlags dwFlags) { switch (cpus) { case UsageScenario.Logon: case UsageScenario.UnlockWorkstation: case UsageScenario.CredUI: case UsageScenario.ChangePassword: return true; default: return false; } } ``` * Override the `GetControls` method, and provide the controls to render your UI. You can conditionally render based on the current scenario ```cs public override IEnumerable GetControls(UsageScenario cpus) { yield return new CredentialProviderLabelControl("CredProviderLabel", "My first credential provider"); var infoLabel = new SmallLabelControl("InfoLabel", "Enter your username and password please!"); infoLabel.State = FieldState.DisplayInSelectedTile; yield return infoLabel; yield return new TextboxControl("UsernameField", "Username"); var password = new SecurePasswordTextboxControl("PasswordField", "Password"); yield return password; if (cpus == UsageScenario.ChangePassword) { var confirmPassword = new SecurePasswordTextboxControl("ConfirmPasswordField", "Confirm password"); yield return confirmPassword; yield return new SubmitButtonControl("SubmitButton", "Submit", confirmPassword); } else { yield return new SubmitButtonControl("SubmitButton", "Submit", password); } } ``` * Windows will ask for the tiles to show. You can determine if you want to show a generic tile (that is, a tile not associated with a user), or a user-specific tile. Windows will provide the list of known users for you to create tiles for. ```cs public override bool ShouldIncludeUserTile(CredentialProviderUser user) { return true; } public override bool ShouldIncludeGenericTile() { return true; } public override CredentialTile CreateGenericTile() { return new MyTile(this); } public override CredentialTile2 CreateUserTile(CredentialProviderUser user) { return new MyTile(this, user); } ``` * Create your tile class. Inherit from `CredentialTile2` if you want to create personalized tiles supported by Windows 8 and later, or `CredentialTile` if you only want to implement a generic tile. Use `CredentialTile3` when an image must preserve transparency. Grab the instances of your controls in the `Initialize` method, so you can attach to their properties to read and respond to value changes. Finally, override the `GetCredentials` method, which is called when the user clicks the submit button. ```cs public class MyTile : CredentialTile2 { private TextboxControl UsernameControl; private SecurePasswordTextboxControl PasswordControl; private SecurePasswordTextboxControl PasswordConfirmControl; public MyTile(CredentialProviderBase credentialProvider) : base(credentialProvider) { } public MyTile(CredentialProviderBase credentialProvider, CredentialProviderUser user) : base(credentialProvider, user) { } public string Username { get => UsernameControl.Text; set => UsernameControl.Text = value; } public SecureString Password { get => PasswordControl.Password; set => PasswordControl.Password = value; } public SecureString ConfirmPassword { get => PasswordConfirmControl.Password; set => PasswordConfirmControl.Password = value; } public override void Initialize() { if (UsageScenario == UsageScenario.ChangePassword) { this.PasswordConfirmControl = this.Controls.GetControl("ConfirmPasswordField"); } this.PasswordControl = this.Controls.GetControl("PasswordField"); this.UsernameControl = this.Controls.GetControl("UsernameField"); Username = this.User?.QualifiedUserName; } protected override CredentialResponseBase GetCredentials() { string username; string domain; if (Username.Contains("\\")) { domain = Username.Split('\\')[0]; username = Username.Split('\\')[1]; } else { username = Username; domain = Environment.MachineName; } var spassword = Controls.GetControl("PasswordField").Password; return new CredentialResponseSecure() { IsSuccess = true, Password = spassword, Domain = domain, Username = username }; } } ``` * Build your project and you have a functional credential provider! ## Bitmap transparency `CredentialProviderLogoControl` and `UserTileControl` both accept a `Bitmap`. The tile base class controls how Windows receives images that contain transparent or partially transparent pixels. | Tile base class | Image behaviour | |-----------------|-----------------| | `CredentialTile` | Renders transparency against the control's `BackgroundColor`. | | `CredentialTile2` | Renders transparency against the control's `BackgroundColor`. | | `CredentialTile3` | Preserves the image's alpha channel and ignores `BackgroundColor`. | Existing providers that inherit from `CredentialTile` or `CredentialTile2` keep their current behaviour. The default `BackgroundColor` is `#464646`. To preserve transparency, inherit your tile class from `CredentialTile3` and provide a `Bitmap` with an alpha channel. The library selects the image representation required by Windows, so your provider does not need to handle that conversion. ```cs public class MyTile : CredentialTile3 { public MyTile(CredentialProviderBase credentialProvider) : base(credentialProvider) { } public MyTile(CredentialProviderBase credentialProvider, CredentialProviderUser user) : base(credentialProvider, user) { } } public override IEnumerable GetControls(UsageScenario cpus) { Bitmap image = LoadTransparentBitmap(); yield return new UserTileControl("UserTile", "User tile image", image); yield return new CredentialProviderLogoControl("ProviderLogo", "Credential provider logo", image); } ``` ## Installing the credential provider You can use the traditional methods of registering a credential provider (regasm, regsvr32, create registry keys etc), but we've provided a PowerShell module to automatically register your credential provider with a single command. ```powershell Install-Module Lithnet.CredentialProvider.Management Register-CredentialProvider -File C:\path-to-your-provider.dll ``` You can disable, enable, and uninstall the provider with the following commands ```powershell Disable-CredentialProvider -File "C:\path-to-your-provider.dll" Enable-CredentialProvider -File "C:\path-to-your-provider.dll" Unregister-CredentialProvider -File "C:\path-to-your-provider.dll" ``` Once the credential provider is registered, you can use the `Invoke-CredUI` cmdlet provided as part of the module, to bring up CredUI window and render your credential provider. ## How can I contribute to the project? * Found an issue and want us to fix it? [Log it](https://github.com/lithnet/windows-credential-provider/issues) * Want to fix an issue yourself or add functionality? Clone the project and submit a pull request ## Enteprise support Enterprise support is not currently offered for this product. ## Keep up to date * [Visit our blog](http://blog.lithnet.io) * [Follow us on twitter](https://twitter.com/lithnet_io)![](http://twitter.com/favicon.ico)