Cleans up static loggers

Adds test projects for different frameworks and architectures
Adds registration tool assembly
This commit is contained in:
Ryan Newington
2023-01-29 17:30:37 +11:00
parent 4366b24e63
commit 1205f217b3
46 changed files with 1589 additions and 200 deletions
@@ -0,0 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Lithnet.CredentialProvider" Version="1.0.0-beta.25" />
<PackageReference Include="System.CommandLine" Version="2.0.0-beta4.22272.1" />
<PackageReference Include="System.Reflection.MetadataLoadContext" Version="7.0.0" />
</ItemGroup>
</Project>
@@ -0,0 +1,187 @@
using System;
using System.Collections.Generic;
using System.CommandLine;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
namespace Lithnet.CredentialProvider.RegistrationTool
{
internal static class Program
{
static async Task<int> Main(string[] args)
{
var rootCommand = new RootCommand("Lithnet credential provider registration tool");
var registerCommand = new Command("--register", "Registers the specified credential provider on this system");
registerCommand.AddAlias("-r");
var registerArgument = new Argument<FileInfo>("file name", "The name of the file to register");
registerCommand.AddArgument(registerArgument);
registerCommand.SetHandler((file) => RegisterAssembly(file), registerArgument);
rootCommand.Add(registerCommand);
var unregisterCommand = new Command("--unregister", "Unregisters the specified credential provider on this system");
unregisterCommand.AddAlias("-u");
var unregisterArgument = new Argument<FileInfo>("file name", "The name of the file to register");
unregisterCommand.AddArgument(unregisterArgument);
unregisterCommand.SetHandler((file) => UnregisterAssembly(file), unregisterArgument);
rootCommand.Add(unregisterCommand);
var enableCommand = new Command("--enable", "Enables the specified credential provider on this system");
enableCommand.AddAlias("-e");
var enableFileOption = new Option<FileInfo>("file", "The path to the credential provider to enable");
var enableGuidOption = new Option<Guid>("providerid", "The GUID of the provider to enable");
enableCommand.AddOption(enableFileOption);
enableCommand.AddOption(enableGuidOption);
enableCommand.SetHandler((file) => EnableProviders(file), enableFileOption);
enableCommand.SetHandler((id) => EnableProviders(id), enableGuidOption);
rootCommand.Add(enableCommand);
//var unregisterOption = new Option<FileInfo>(
// name: "--unregister",
// description: "Unregisters the specified file as a credential provider on this system");
//var enableOption = new Option<string>(
// name: "--enable",
// description: "Enables a credential provider on this system");
//var disableOption = new Option<string>(
// name: "--disable",
// description: "Disables a credential provider on this system");
//rootCommand.AddOption(registerOptions);
//rootCommand.AddOption(unregisterOption);
//rootCommand.AddOption(enableOption);
//rootCommand.AddOption(disableOption);
//rootCommand.SetHandler((file) => RegisterAssembly(file), registerOptions);
//rootCommand.SetHandler((file) => UnregisterAssembly(file), unregisterOption);
//rootCommand.SetHandler((file) => EnableProviders(file), enableOption);
//rootCommand.SetHandler((file) => DisableProviders(file), disableOption);
return await rootCommand.InvokeAsync(args);
}
private static void UnregisterAssembly(FileInfo file)
{
var assembly = LoadAssembly(file.FullName);
foreach (var type in GetCredentialProviders(assembly))
{
CredentialProviderRegistrationServices.UnregisterCredentialProvider(type);
Console.WriteLine($"Unregistered credential provider {type.Name}");
}
}
private static void EnableProviders(FileInfo file)
{
var assembly = LoadAssembly(file.FullName);
foreach (var type in GetCredentialProviders(assembly))
{
CredentialProviderRegistrationServices.EnableCredentialProvider(type);
Console.WriteLine($"Enabled credential provider {type.FullName}");
}
}
private static void EnableProviders(Guid id)
{
CredentialProviderRegistrationServices.EnableCredentialProvider(id);
Console.WriteLine($"Enabled credential provider {id}");
}
private static void DisableProviders(FileInfo file)
{
var assembly = LoadAssembly(file.FullName);
foreach (var type in GetCredentialProviders(assembly))
{
CredentialProviderRegistrationServices.DisableCredentialProvider(type);
Console.WriteLine($"Disabled credential provider {type.FullName}");
}
}
private static void DisableProviders(string id)
{
if (Guid.TryParse(id, out var providerId))
{
CredentialProviderRegistrationServices.DisableCredentialProvider(providerId);
Console.WriteLine($"Disabled credential provider {providerId}");
}
var assembly = LoadAssembly(Path.GetFullPath(id));
foreach (var type in GetCredentialProviders(assembly))
{
CredentialProviderRegistrationServices.DisableCredentialProvider(type);
Console.WriteLine($"Disabled credential provider {type.FullName}");
}
}
private static void RegisterAssembly(FileInfo file)
{
var assembly = LoadAssembly(file.FullName);
foreach (var type in GetCredentialProviders(assembly))
{
CredentialProviderRegistrationServices.RegisterCredentialProvider(type);
Console.WriteLine($"Registered credential provider {type.FullName}");
}
}
private static IEnumerable<Type> GetCredentialProviders(Assembly assembly)
{
return assembly.GetExportedTypes().Where(t => t.GetInterfaces().Any(ifn => ifn.Name == "ICredentialProvider") && !t.IsAbstract && !t.IsInterface);
}
private static Assembly LoadAssembly(string assemblyPath)
{
string assemblyBasePath = Path.GetDirectoryName(assemblyPath);
List<string> paths = new List<string>();
paths.AddRange(Directory.GetFiles(Path.GetDirectoryName(assemblyPath)));
paths.Add(typeof(object).Assembly.Location);
paths.AddRange(Directory.GetFiles(RuntimeEnvironment.GetRuntimeDirectory(), "*.dll"));
var resolver = new PathAssemblyResolver(paths);
MetadataLoadContext mlc = new MetadataLoadContext(resolver);
return mlc.LoadFromAssemblyPath(assemblyPath);
//AppDomain.CurrentDomain.ReflectionOnlyAssemblyResolve += (s, args) =>
//{
// var name = new AssemblyName(args.Name);
// string assyPath = Path.Combine(assemblyBasePath, $"{name.Name}.dll");
// Trace.WriteLine($"Request for {args.Name}");
// if (File.Exists(assyPath))
// {
// Trace.WriteLine($"Found at {assyPath}");
// return Assembly.ReflectionOnlyLoadFrom(assyPath);
// }
// assyPath = Path.Combine(RuntimeEnvironment.GetRuntimeDirectory(), $"{name.Name}.dll");
// if (File.Exists(assyPath))
// {
// Trace.WriteLine($"Found at {assyPath}");
// return Assembly.ReflectionOnlyLoadFrom(assyPath);
// }
// Trace.WriteLine($"Assembly {args.Name} not found");
// return null;
//};
//var assembly = Assembly.ReflectionOnlyLoadFrom(assemblyPath);
}
}
}
@@ -0,0 +1,9 @@
{
"profiles": {
"Lithnet.CredentialProvider.RegistrationTool": {
"commandName": "Project",
"commandLineArgs": "--unregister \"D:\\dev\\git\\ryannewington\\CredProvider.NET\\CredProvider.NET\\bin\\Debug\\CredProvider.NET.dll\""
//"commandLineArgs": "--register \"D:\\dev\\git\\lithnet\\windows-credential-provider\\src\\samples\\Lithnet.CredentialProvider.Sample.net6.0.x64\\bin\\Debug\\net6.0-windows\\Lithnet.CredentialProvider.Sample.net6.0.x64.dll\""
}
}
}
@@ -1,35 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net472</TargetFramework>
<RegisterForComInterop>false</RegisterForComInterop>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Lithnet.CredentialProvider" Version="1.0.0-beta.2" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="6.0.0" />
<PackageReference Include="NLog" Version="5.1.1" />
<PackageReference Include="NLog.Extensions.Logging" Version="5.2.1" />
</ItemGroup>
<ItemGroup>
<Reference Include="System.Windows.Forms" />
</ItemGroup>
<ItemGroup>
<Compile Update="Resources.Designer.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Update="Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
</EmbeddedResource>
</ItemGroup>
</Project>
Binary file not shown.

Before

Width:  |  Height:  |  Size: 889 B

@@ -1,99 +0,0 @@
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using Microsoft.Extensions.Logging;
namespace Lithnet.CredentialProvider.Samples
{
[ComVisible(true)]
[ClassInterface(ClassInterfaceType.None)]
[ProgId("Lithnet.CredentialProvider.Samples.TestCredentialProvider")]
[Guid("1A3993B6-EB2B-44BB-A788-7AB1711DFF16")]
public class TestCredentialProvider : CredentialProviderBase
{
private static readonly ILogger logger = Program.LoggerFactory.CreateLogger<TestCredentialProvider>();
public TestCredentialProvider()
{
}
public override ILoggerFactory GetLoggerFactory()
{
return Program.LoggerFactory;
}
public override IEnumerable<ControlBase> GetControls(UsageScenario cpus)
{
var password = new SecurePasswordTextboxControl(TestCredentialProviderControlKeys.Password, "Password");
if (cpus == UsageScenario.ChangePassword)
{
var confirmPassword = new SecurePasswordTextboxControl(TestCredentialProviderControlKeys.ConfirmPassword, "Confirm password");
yield return new TextboxControl(TestCredentialProviderControlKeys.Username, "Username");
yield return password;
yield return confirmPassword;
yield return new SubmitButtonControl(TestCredentialProviderControlKeys.ButtonSubmit, "Submit", confirmPassword);
}
else
{
yield return new CredentialProviderLabelControl(TestCredentialProviderControlKeys.LabelCredentialProvider, "Login with showcase credential provider");
yield return new CredentialProviderLogoControl(TestCredentialProviderControlKeys.ImageCredentialProvider, "Credential provider logo", Resources.TileIcon);
yield return new CredentialProviderLogoControl(TestCredentialProviderControlKeys.ImageUserTile, "User tile image", Resources.TileIcon);
yield return new LargeLabelControl(TestCredentialProviderControlKeys.LabelLargeHeading, "The is our showcase credential provider");
yield return new SmallLabelControl(TestCredentialProviderControlKeys.LabelSmallHeading, "Let's see what we can do");
yield return new CheckboxControl(TestCredentialProviderControlKeys.Checkbox, "A checkbox");
yield return new SmallLabelControl(TestCredentialProviderControlKeys.LabelCheckboxValue, "The check box is currently unchecked");
yield return new CommandLinkControl(TestCredentialProviderControlKeys.CommandLinkCheckboxValue, "Click this link to change the check box value in code behind");
yield return new ComboboxControl(TestCredentialProviderControlKeys.Combobox, "Items to choose from:");
yield return new SmallLabelControl(TestCredentialProviderControlKeys.LabelComboboxSelectedItem, "This is the currently selected item: <none>");
yield return new CommandLinkControl(TestCredentialProviderControlKeys.CommandLinkComboboxAdd, "Add a random item to the combo box");
yield return new CommandLinkControl(TestCredentialProviderControlKeys.CommandLinkComboboxRemove, "Remove the last item from the combo box");
yield return new TextboxControl(TestCredentialProviderControlKeys.Username, "Username");
yield return new CommandLinkControl(TestCredentialProviderControlKeys.CommandLinkUsername, "Click this link to generate a random username");
yield return password;
yield return new SubmitButtonControl(TestCredentialProviderControlKeys.ButtonSubmit, "Submit", password);
}
}
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;
}
}
public override bool ShouldIncludeUserTile(CredentialProviderUser user)
{
return true;
}
public override bool ShouldIncludeGenericTile()
{
return true;
}
public override CredentialProviderCredential1Tile CreateGenericTile()
{
return new TestCredentialProviderTile(this);
}
public override CredentialProviderCredential1Tile CreateUserTile(CredentialProviderUser user)
{
return new TestCredentialProviderTile(this, user);
}
}
}
+42 -6
View File
@@ -5,13 +5,25 @@ VisualStudioVersion = 17.4.33205.214
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Lithnet.CredentialProvider", "Lithnet.CredentialProvider\Lithnet.CredentialProvider.csproj", "{9C07477C-ABB8-4DE5-B69C-3F8719D952C6}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Lithnet.CredentialProvider.Samples", "Lithnet.CredentialProvider.Samples\Lithnet.CredentialProvider.Samples.csproj", "{967DF0EB-F85A-4006-A3BF-0C558753A9DC}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{9E97082E-4E8D-4E8B-A320-40E2A1494C74}"
ProjectSection(SolutionItems) = preProject
.editorconfig = .editorconfig
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Lithnet.CredentialProvider.Sample.net6.0.x64", "samples\Lithnet.CredentialProvider.Sample.net6.0.x64\Lithnet.CredentialProvider.Sample.net6.0.x64.csproj", "{163E16D0-9FF3-40D3-AE96-3F221C922AA3}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Lithnet.CredentialProvider.Sample.net6.0.x86", "samples\Lithnet.CredentialProvider.Sample.net6.0.x86\Lithnet.CredentialProvider.Sample.net6.0.x86.csproj", "{7A8A10F9-7D79-4755-BBDD-77C80FDC58ED}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Lithnet.CredentialProvider.Sample.net472.x64", "samples\Lithnet.CredentialProvider.Sample.net472.x64\Lithnet.CredentialProvider.Sample.net472.x64.csproj", "{F60AC10A-337C-46D9-A2DE-1ED48B4AB301}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Lithnet.CredentialProvider.Sample.net472.x86", "samples\Lithnet.CredentialProvider.Sample.net472.x86\Lithnet.CredentialProvider.Sample.net472.x86.csproj", "{57F2780E-58F1-4A7B-BCB4-A218733273EA}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Lithnet.CredentialProvider.TestApp.x64", "samples\Lithnet.CredentialProvider.TestApp.x64\Lithnet.CredentialProvider.TestApp.x64.csproj", "{5019CCEB-AD78-4688-8C11-89A85C4289CD}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Lithnet.CredentialProvider.TestApp.x86", "samples\Lithnet.CredentialProvider.TestApp.x86\Lithnet.CredentialProvider.TestApp.x86.csproj", "{F39C84F2-60C2-45EB-BC87-0ED095D41C96}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Lithnet.CredentialProvider.RegistrationTool", "Lithnet.CredentialProvider.RegistrationTool\Lithnet.CredentialProvider.RegistrationTool.csproj", "{6A9A22A9-A2BB-4329-A0A5-2539E464CE5F}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -22,10 +34,34 @@ Global
{9C07477C-ABB8-4DE5-B69C-3F8719D952C6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9C07477C-ABB8-4DE5-B69C-3F8719D952C6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9C07477C-ABB8-4DE5-B69C-3F8719D952C6}.Release|Any CPU.Build.0 = Release|Any CPU
{967DF0EB-F85A-4006-A3BF-0C558753A9DC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{967DF0EB-F85A-4006-A3BF-0C558753A9DC}.Debug|Any CPU.Build.0 = Debug|Any CPU
{967DF0EB-F85A-4006-A3BF-0C558753A9DC}.Release|Any CPU.ActiveCfg = Release|Any CPU
{967DF0EB-F85A-4006-A3BF-0C558753A9DC}.Release|Any CPU.Build.0 = Release|Any CPU
{163E16D0-9FF3-40D3-AE96-3F221C922AA3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{163E16D0-9FF3-40D3-AE96-3F221C922AA3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{163E16D0-9FF3-40D3-AE96-3F221C922AA3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{163E16D0-9FF3-40D3-AE96-3F221C922AA3}.Release|Any CPU.Build.0 = Release|Any CPU
{7A8A10F9-7D79-4755-BBDD-77C80FDC58ED}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7A8A10F9-7D79-4755-BBDD-77C80FDC58ED}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7A8A10F9-7D79-4755-BBDD-77C80FDC58ED}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7A8A10F9-7D79-4755-BBDD-77C80FDC58ED}.Release|Any CPU.Build.0 = Release|Any CPU
{F60AC10A-337C-46D9-A2DE-1ED48B4AB301}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F60AC10A-337C-46D9-A2DE-1ED48B4AB301}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F60AC10A-337C-46D9-A2DE-1ED48B4AB301}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F60AC10A-337C-46D9-A2DE-1ED48B4AB301}.Release|Any CPU.Build.0 = Release|Any CPU
{57F2780E-58F1-4A7B-BCB4-A218733273EA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{57F2780E-58F1-4A7B-BCB4-A218733273EA}.Debug|Any CPU.Build.0 = Debug|Any CPU
{57F2780E-58F1-4A7B-BCB4-A218733273EA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{57F2780E-58F1-4A7B-BCB4-A218733273EA}.Release|Any CPU.Build.0 = Release|Any CPU
{5019CCEB-AD78-4688-8C11-89A85C4289CD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{5019CCEB-AD78-4688-8C11-89A85C4289CD}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5019CCEB-AD78-4688-8C11-89A85C4289CD}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5019CCEB-AD78-4688-8C11-89A85C4289CD}.Release|Any CPU.Build.0 = Release|Any CPU
{F39C84F2-60C2-45EB-BC87-0ED095D41C96}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F39C84F2-60C2-45EB-BC87-0ED095D41C96}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F39C84F2-60C2-45EB-BC87-0ED095D41C96}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F39C84F2-60C2-45EB-BC87-0ED095D41C96}.Release|Any CPU.Build.0 = Release|Any CPU
{6A9A22A9-A2BB-4329-A0A5-2539E464CE5F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6A9A22A9-A2BB-4329-A0A5-2539E464CE5F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6A9A22A9-A2BB-4329-A0A5-2539E464CE5F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6A9A22A9-A2BB-4329-A0A5-2539E464CE5F}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -29,7 +29,7 @@ namespace Lithnet.CredentialProvider
this.Key = source.Key;
this.Type = source.Type;
this.FieldTypeGuid = source.FieldTypeGuid;
this.logger = source.logger;
this.state = source.State;
this.interactiveState = source.InteractiveState;
this.label = source.Label;
@@ -54,7 +54,6 @@ namespace Lithnet.CredentialProvider
this.options = FieldOptions.None;
this.Key = key;
this.logger = CredentialProviderBase.LoggerFactory.CreateLogger(this.GetType());
}
internal void AssignCredential(ICredentialProviderCredential credential)
@@ -76,6 +75,11 @@ namespace Lithnet.CredentialProvider
internal ICredentialProviderCredential Credential { get; private set; }
internal void SetLogger(ILoggerFactory loggerFactory)
{
this.logger = loggerFactory.CreateLogger(this.GetType());
}
/// <summary>
/// Gets the unique ID associated with this control
/// </summary>
@@ -13,11 +13,7 @@ namespace Lithnet.CredentialProvider
/// </summary>
public abstract partial class CredentialProviderBase
{
internal static ILoggerFactory LoggerFactory { get; set; } = NullLoggerFactory.Instance;
private readonly ILogger logger;
private readonly ILoggerFactory loggerFactory;
private ICredentialProviderEvents CredentialProviderEvents;
private ICredentialProviderUserArray credentialProviderUsers;
@@ -25,6 +21,8 @@ namespace Lithnet.CredentialProvider
private bool notifyOnTileCollectionChange;
private List<CredentialProviderCredential1Tile> tiles;
internal ILoggerFactory LoggerFactory { get; }
/// <summary>
/// Gets the GUID of the credential provider
/// </summary>
@@ -57,14 +55,10 @@ namespace Lithnet.CredentialProvider
protected CredentialProviderBase()
{
this.loggerFactory = this.GetLoggerFactory();
this.LoggerFactory = this.GetLoggerFactory();
if (CredentialProviderBase.LoggerFactory != this.loggerFactory)
{
CredentialProviderBase.LoggerFactory = this.loggerFactory;
}
this.logger = this.loggerFactory.CreateLogger(this.GetType());
this.logger = this.LoggerFactory.CreateLogger(this.GetType());
var guidAttribute = (GuidAttribute)(this.GetType().GetCustomAttribute(typeof(GuidAttribute)));
if (guidAttribute == null)
@@ -79,7 +73,7 @@ namespace Lithnet.CredentialProvider
/// Gets a logger factory. Override this method and provide an implementation of <c ref="ILoggerFactory"/> to enable credential provider logging
/// </summary>
/// <returns>An ILoggerFactory instance</returns>
public virtual ILoggerFactory GetLoggerFactory() { return NullLoggerFactory.Instance; }
protected virtual ILoggerFactory GetLoggerFactory() { return NullLoggerFactory.Instance; }
/// <summary>
/// Gets a value indicating if the credential provider supports the <c ref="UsageScenario"/> provided by LogonUI or CredUI
@@ -175,6 +169,7 @@ namespace Lithnet.CredentialProvider
foreach (var control in this.GetControls(this.UsageScenario))
{
control.SetLogger(this.LoggerFactory);
this.Controls.Add(control);
}
@@ -205,7 +200,7 @@ namespace Lithnet.CredentialProvider
this.logger.LogTrace($"Got supplied user {i}: with name {user.GetQualifiedUserName()} and SID {sid}");
var credentialProviderUser = new CredentialProviderUser(user);
var credentialProviderUser = new CredentialProviderUser(this.LoggerFactory, user);
users.Add(credentialProviderUser);
if (this.ShouldIncludeUserTile(credentialProviderUser))
@@ -12,7 +12,6 @@ namespace Lithnet.CredentialProvider
public abstract partial class CredentialProviderCredential1Tile
{
private protected readonly ILogger logger;
private protected ICredentialProviderCredentialEvents events;
private protected ICredentialProviderCredentialEvents2 events2;
@@ -21,7 +20,7 @@ namespace Lithnet.CredentialProvider
protected CredentialProviderCredential1Tile(CredentialProviderBase credentialProvider)
{
this.CredentialProvider = credentialProvider;
this.logger = CredentialProviderBase.LoggerFactory.CreateLogger(this.GetType());
this.logger = credentialProvider.LoggerFactory.CreateLogger(this.GetType());
}
internal CredentialProviderBase CredentialProvider { get; }
@@ -206,15 +205,15 @@ namespace Lithnet.CredentialProvider
return response;
}
CredentialSerializer.Logger = this.logger;
var serializer = new CredentialSerializer(this.CredentialProvider.LoggerFactory);
if (credentials is CredentialResponseSecure s)
{
response.SerializedCredentials = CredentialSerializer.GenerateCredentialSerialization(credentials.Domain, credentials.Username, s.Password, this.UsageScenario == UsageScenario.UnlockWorkstation, this.CredentialProvider.CredentialProviderId);
response.SerializedCredentials = serializer.GenerateCredentialSerialization(credentials.Domain, credentials.Username, s.Password, this.UsageScenario == UsageScenario.UnlockWorkstation, this.CredentialProvider.CredentialProviderId);
}
else if (credentials is CredentialResponseInsecure i)
{
response.SerializedCredentials = CredentialSerializer.GenerateCredentialSerialization(credentials.Domain, credentials.Username, i.Password, this.UsageScenario == UsageScenario.UnlockWorkstation, this.CredentialProvider.CredentialProviderId);
response.SerializedCredentials = serializer.GenerateCredentialSerialization(credentials.Domain, credentials.Username, i.Password, this.UsageScenario == UsageScenario.UnlockWorkstation, this.CredentialProvider.CredentialProviderId);
}
else
{
@@ -0,0 +1,233 @@
using System;
using System.IO;
using System.Linq;
using System.Reflection;
using Microsoft.Win32;
namespace Lithnet.CredentialProvider
{
public static class CredentialProviderRegistrationServices
{
public static void DisableCredentialProvider<T>() where T : CredentialProviderBase => DisableCredentialProvider(typeof(T));
public static void UnregisterCredentialProvider<T>() where T : CredentialProviderBase => UnregisterCredentialProvider(typeof(T));
public static void RegisterCredentialProvider<T>() where T : CredentialProviderBase => RegisterCredentialProvider(typeof(T));
public static void EnableCredentialProvider<T>() where T : CredentialProviderBase => EnableCredentialProvider(typeof(T));
public static void UnregisterCredentialProvider(Type type)
{
DeleteCredentialProviderRegistration(type);
if (IsFrameworkType(type))
{
UnregisterFrameworkAssembly(type);
}
else
{
UnregisterNetCoreAssembly(type);
}
}
public static void RegisterCredentialProvider(Type type)
{
CreateCredentialProviderRegistration(type);
if (IsFrameworkType(type))
{
RegisterFrameworkAssembly(type);
}
else
{
RegisterNetCoreAssembly(type);
}
}
public static void DisableCredentialProvider(Type type)
{
var comGuid = GetComGuid(type);
DisableCredentialProvider(comGuid);
}
public static void DisableCredentialProvider(Guid comGuid)
{
var key = Registry.LocalMachine.OpenSubKey($@"SOFTWARE\Microsoft\Windows\CurrentVersion\Authentication\Credential Providers\{comGuid:B}", true);
key?.SetValue("Disabled", 1);
}
public static void EnableCredentialProvider(Guid comGuid)
{
var key = Registry.LocalMachine.OpenSubKey($@"SOFTWARE\Microsoft\Windows\CurrentVersion\Authentication\Credential Providers\{comGuid:B}", true);
key?.SetValue("Disabled", 0);
}
public static void EnableCredentialProvider(Type type)
{
var comGuid = GetComGuid(type);
EnableCredentialProvider(comGuid);
}
private static void CreateCredentialProviderRegistration(Type t)
{
var comGuid = GetComGuid(t);
var typeName = GetTypeFullName(t);
var key = Registry.LocalMachine.CreateSubKey($@"SOFTWARE\Microsoft\Windows\CurrentVersion\Authentication\Credential Providers\{comGuid:B}", true);
key.SetValue(null, typeName);
}
private static void DeleteCredentialProviderRegistration(Type t)
{
var comGuid = GetComGuid(t);
Registry.LocalMachine.DeleteSubKeyTree($@"SOFTWARE\Microsoft\Windows\CurrentVersion\Authentication\Credential Providers\{comGuid:B}", false);
}
private static void RegisterNetCoreAssembly(Type t)
{
var comGuid = GetComGuid(t);
var typeName = GetTypeFullName(t);
var progId = GetComProgId(t);
var assemblyLocation = GetTypeAssemblyLocation(t);
var dir = Path.GetDirectoryName(assemblyLocation);
var assemblyFile = Path.GetFileNameWithoutExtension(assemblyLocation);
var comHostLocation = Path.Combine(dir, assemblyFile + ".comhost.dll");
var rootClsid = Registry.LocalMachine.CreateSubKey($@"Software\Classes\CLSID\{comGuid:B}", true);
rootClsid.SetValue(null, "CoreCLR COMHost Server");
var inprocKey = rootClsid.CreateSubKey("InprocServer32", true);
inprocKey.SetValue(null, comHostLocation);
inprocKey.SetValue("ThreadingModel", "Both");
var progIdKey = rootClsid.CreateSubKey("ProgId", true);
progIdKey.SetValue(null, progId);
var progIdRoot = Registry.LocalMachine.CreateSubKey($@"Software\Classes\{progId}", true);
progIdRoot.SetValue(null, typeName);
var progIdSubKey = progIdRoot.CreateSubKey("CLSID");
progIdSubKey.SetValue(null, comGuid.ToString("B"));
}
private static void UnregisterNetCoreAssembly(Type t)
{
var comGuid = GetComGuid(t);
var progId = GetComProgId(t);
Registry.LocalMachine.DeleteSubKeyTree($@"Software\Classes\CLSID\{comGuid:B}", false);
Registry.LocalMachine.DeleteSubKeyTree($@"Software\Classes\{progId}", false);
}
private static void RegisterFrameworkAssembly(Type t)
{
var comGuid = GetComGuid(t);
var typeName = GetTypeFullName(t);
var progId = GetComProgId(t);
var rootClsid = Registry.LocalMachine.CreateSubKey($@"Software\Classes\CLSID\{comGuid:B}", true);
rootClsid.SetValue(null, typeName);
rootClsid.CreateSubKey("Implemented Categories");
rootClsid.CreateSubKey(@"Implemented Categories\{62C8FE65-4EBB-45e7-B440-6E39B2CDBF29}");
var inprocKey = rootClsid.CreateSubKey("InprocServer32", true);
inprocKey.SetValue(null, "mscoree.dll");
inprocKey.SetValue("ThreadingModel", "Both");
inprocKey.SetValue("Class", typeName);
inprocKey.SetValue("RuntimeVersion", "v4.0.30319");
inprocKey.SetValue("Assembly", GetTypeAssemblyName(t));
inprocKey.SetValue("CodeBase", GetTypeAssemblyLocation(t));
var progIdKey = rootClsid.CreateSubKey("ProgId", true);
progIdKey.SetValue(null, progId);
var progIdRoot = Registry.LocalMachine.CreateSubKey($@"Software\Classes\{progId}", true);
progIdRoot.SetValue(null, typeName);
var progIdSubKey = progIdRoot.CreateSubKey("CLSID");
progIdSubKey.SetValue(null, comGuid.ToString("B"));
}
private static void UnregisterFrameworkAssembly(Type t)
{
var comGuid = GetComGuid(t);
var progId = GetComProgId(t);
Registry.LocalMachine.DeleteSubKeyTree($@"Software\Classes\CLSID\{comGuid:B}", false);
Registry.LocalMachine.DeleteSubKeyTree($@"Software\Classes\{progId}", false);
}
private static string GetTypeAssemblyLocation(Type type)
{
return type.Assembly.Location;
}
private static string GetTypeAssemblyName(Type type)
{
return type.Assembly.FullName;
}
private static string GetTypeClassName(Type type)
{
return type.Name;
}
private static string GetTypeFullName(Type type)
{
return type.FullName;
}
private static Guid GetComGuid(Type type)
{
var typeId = type.GetCustomAttributeValue("GuidAttribute");
if (typeId == null)
{
throw new ArgumentException($"The type {type.Name} does not have the Guid attribute present");
}
return new Guid(typeId);
}
private static string GetComProgId(Type type)
{
var typeId = type.GetCustomAttributeValue("ProgIdAttribute");
if (typeId == null)
{
throw new ArgumentException($"The type {type.Name} does not have the ProgId attribute present");
}
return typeId;
}
private static bool IsFrameworkType(Type type)
{
var framework = type.Assembly.GetCustomAttributeValue("TargetFrameworkAttribute");
return framework.StartsWith(".NETFramework");
}
private static string GetCustomAttributeValue(this Type type, string attributeName)
{
var cads = type.GetCustomAttributesData();
foreach (CustomAttributeData cad in cads.Where(a => a.AttributeType.Name == attributeName))
{
return cad.ConstructorArguments.FirstOrDefault().Value as string;
}
return String.Empty;
}
private static string GetCustomAttributeValue(this Assembly assembly, string attributeName)
{
foreach (CustomAttributeData cad in assembly.GetCustomAttributesData().Where(a => a.AttributeType.Name == attributeName))
{
return cad.ConstructorArguments.FirstOrDefault().Value as string;
}
return String.Empty;
}
}
}
@@ -19,10 +19,10 @@ namespace Lithnet.CredentialProvider
private string logonStatus;
private string providerId;
internal CredentialProviderUser(ICredentialProviderUser user)
internal CredentialProviderUser(ILoggerFactory loggerFactory, ICredentialProviderUser user)
{
this.User = user;
this.logger = CredentialProviderBase.LoggerFactory.CreateLogger<CredentialProviderUser>();
this.logger = loggerFactory.CreateLogger<CredentialProviderUser>();
}
/// <summary>
@@ -3,20 +3,24 @@ using System.Runtime.InteropServices;
using System.Security;
using System.Text;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
namespace Lithnet.CredentialProvider.Interop
{
internal static class CredentialSerializer
internal class CredentialSerializer
{
internal static ILogger Logger { get; set; } = NullLogger.Instance;
private readonly ILogger logger;
public static CredentialSerialization GenerateCredentialSerialization(string domain, string username, SecureString password, bool isWorkstationUnlock, Guid providerId)
public CredentialSerializer(ILoggerFactory loggerFactory)
{
this.logger = loggerFactory.CreateLogger<CredentialSerializer>();
}
public CredentialSerialization GenerateCredentialSerialization(string domain, string username, SecureString password, bool isWorkstationUnlock, Guid providerId)
{
var authPackage = PInvoke.LookupAuthenticationPackage(CredProviderConstants.NEGOSSP_NAME_A);
var pData = SerializeKerbLogon(domain, username, password, isWorkstationUnlock ? KerbLogonSubmitType.WorkstationUnlockLogon : KerbLogonSubmitType.InteractiveLogon, out int size);
var pData = this.SerializeKerbLogon(domain, username, password, isWorkstationUnlock ? KerbLogonSubmitType.WorkstationUnlockLogon : KerbLogonSubmitType.InteractiveLogon, out int size);
Logger.LogTrace($"0x{pData.ToString("X16")} - Serializer: Password got packed into ");
this.logger.LogTrace($"0x{pData.ToString("X16")} - Serializer: Password got packed into ");
return new CredentialSerialization()
{
@@ -27,12 +31,12 @@ namespace Lithnet.CredentialProvider.Interop
};
}
public static CredentialSerialization GenerateCredentialSerialization(string domain, string username, string password, bool isWorkstationUnlock, Guid providerId)
public CredentialSerialization GenerateCredentialSerialization(string domain, string username, string password, bool isWorkstationUnlock, Guid providerId)
{
var authPackage = PInvoke.LookupAuthenticationPackage(CredProviderConstants.NEGOSSP_NAME_A);
var pData = SerializeKerbLogon(domain, username, password, isWorkstationUnlock ? KerbLogonSubmitType.WorkstationUnlockLogon : KerbLogonSubmitType.InteractiveLogon, out int size);
var pData = this.SerializeKerbLogon(domain, username, password, isWorkstationUnlock ? KerbLogonSubmitType.WorkstationUnlockLogon : KerbLogonSubmitType.InteractiveLogon, out int size);
Logger.LogTrace($"0x{pData.ToString("X16")}: Password got packed");
this.logger.LogTrace($"0x{pData.ToString("X16")}: Password got packed");
return new CredentialSerialization()
{
@@ -43,7 +47,7 @@ namespace Lithnet.CredentialProvider.Interop
};
}
private static unsafe IntPtr SerializeKerbLogon(string domain, string username, string password, KerbLogonSubmitType type, out int size)
private unsafe IntPtr SerializeKerbLogon(string domain, string username, string password, KerbLogonSubmitType type, out int size)
{
size = sizeof(KerberosInteractiveUnlockLogon) +
Encoding.Unicode.GetMaxByteCount(domain.Length) +
@@ -86,7 +90,7 @@ namespace Lithnet.CredentialProvider.Interop
return pBuffer;
}
private static unsafe IntPtr SerializeKerbLogon(string domain, string username, SecureString password, KerbLogonSubmitType type, out int size)
private unsafe IntPtr SerializeKerbLogon(string domain, string username, SecureString password, KerbLogonSubmitType type, out int size)
{
size = sizeof(KerberosInteractiveUnlockLogon) +
Encoding.Unicode.GetMaxByteCount(domain.Length) +
@@ -127,24 +131,24 @@ namespace Lithnet.CredentialProvider.Interop
try
{
buff = Marshal.SecureStringToCoTaskMemUnicode(password);
Logger.LogTrace($"0x{buff.ToString("X16")} - Serializer: Unprotected password");
this.logger.LogTrace($"0x{buff.ToString("X16")} - Serializer: Unprotected password");
IntPtr targetPositionToCopyTo = (IntPtr)(buffer + logon->Password.Buffer.ToInt64());
Buffer.MemoryCopy(buff.ToPointer(), targetPositionToCopyTo.ToPointer(), logon->Password.Length, password.Length * sizeof(char));
Logger.LogTrace($"0x{targetPositionToCopyTo.ToString("X16")} - Serializer: Copied unprotected password into LSA string buffer");
this.logger.LogTrace($"0x{targetPositionToCopyTo.ToString("X16")} - Serializer: Copied unprotected password into LSA string buffer");
}
finally
{
if (buff != IntPtr.Zero)
{
Marshal.ZeroFreeCoTaskMemUnicode(buff);
Logger.LogTrace($"0x{buff.ToString("X16")} - Serializer: Freed Unprotected password");
this.logger.LogTrace($"0x{buff.ToString("X16")} - Serializer: Freed Unprotected password");
}
}
Logger.LogTrace($"0x{((IntPtr)buffer).ToString("X16")} - Serializer: Put password");
this.logger.LogTrace($"0x{((IntPtr)buffer).ToString("X16")} - Serializer: Put password");
return pBuffer;
}
@@ -3,7 +3,7 @@ using System.Runtime.InteropServices;
namespace Lithnet.CredentialProvider.Interop
{
[StructLayout(LayoutKind.Sequential, Pack = 8)]
[StructLayout(LayoutKind.Sequential, Pack = 4)]
internal struct FieldDescriptor
{
public uint FieldID;
@@ -6,6 +6,9 @@
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<PlatformTargets>AnyCPU</PlatformTargets>
<Deterministic>true</Deterministic>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<GenerateBindingRedirectsOutputType>true</GenerateBindingRedirectsOutputType>
<LangVersion>9</LangVersion>
</PropertyGroup>
<PropertyGroup>
@@ -14,7 +17,7 @@
<Copyright>Copyright 2023 Lithnet Pty Ltd</Copyright>
<ProductName>Lithnet Windows Credential Provider</ProductName>
<VersionPrefix>1.0.0</VersionPrefix>
<VersionSuffix>beta.3</VersionSuffix>
<VersionSuffix>beta.26</VersionSuffix>
<Authors>Lithnet</Authors>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<AutoIncrementPackageRevision>true</AutoIncrementPackageRevision>
@@ -23,10 +26,12 @@
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<RepositoryUrl>https://github.com/lithnet/windows-credential-provider</RepositoryUrl>
<SupportUrl>https://github.com/lithnet/windows-credential-provider</SupportUrl>
<PackageOutputPath>D:\dev\nuget\packages</PackageOutputPath>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="6.0.0" />
<PackageReference Include="Microsoft.Win32.Registry" Version="5.0.0" />
<PackageReference Include="System.Drawing.Common" Version="6.0.0" Condition="$(TargetFramework) == 'netstandard2.0'" />
</ItemGroup>
</Project>
@@ -0,0 +1,37 @@
using System;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
namespace Lithnet.CredentialProvider.ModuleInit
{
internal static class AssemblyResolver
{
private static string basePath;
[ModuleInitializer]
public static void AttachResolver()
{
Trace.WriteLine("Attaching assembly resolver");
AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;
basePath = Path.GetFullPath(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location));
}
private static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
var name = new AssemblyName(args.Name);
string assyPath = Path.Combine(basePath, $"{name.Name}.dll");
Trace.WriteLine($"Request for {args.Name}");
if (File.Exists(assyPath))
{
Trace.WriteLine($"Found at {assyPath}");
return Assembly.Load(assyPath);
}
Trace.WriteLine($"Assembly {args.Name} not found");
return null;
}
}
}
@@ -0,0 +1,7 @@
namespace System.Runtime.CompilerServices
{
[AttributeUsage(System.AttributeTargets.Method, Inherited = false)]
internal sealed class ModuleInitializerAttribute : Attribute
{
}
}
@@ -1,6 +1,6 @@
namespace Lithnet.CredentialProvider.Samples
{
internal static class TestCredentialProviderControlKeys
internal static class ControlKeys
{
internal const string LabelCredentialProvider = "LabelCredentialProvider";
internal const string ImageCredentialProvider = "ImageCredentialProvider";
@@ -0,0 +1,50 @@
# Using the sample credential provider
## Installing the sample
In order to install and run the sample app, you have to register the COM component
Build the EXE, and from an elevated command prompt, change to the bin folder, and run the following commands
```
SETLOCAL
SET CLSID={4EB911FA-CA18-40EA-86DF-19AFF5D1DA58}
SET BinaryPath=D:\dev\git\lithnet\windows-credential-provider\src\samples\Lithnet.CredentialProvider.Sample.net472.x64\bin\Debug\net472\Lithnet.CredentialProvider.Sample.net472.x64.dll
REM %windir%\Microsoft.NET\Framework64\v4.0.30319\regasm /codebase "Lithnet.CredentialProvider.Sample.net472.x64.dll"
REG ADD "HKLM\SOFTWARE\Classes\CLSID\%CLSID%" /ve /t REG_SZ /f /d "Lithnet.CredentialProvider.Samples.TestCredentialProvider"
REG ADD "HKLM\SOFTWARE\Classes\CLSID\%CLSID%\Implemented Categories\{62C8FE65-4EBB-45e7-B440-6E39B2CDBF29}"
REG ADD "HKLM\SOFTWARE\Classes\CLSID\%CLSID%\InprocServer32" /ve /t /REG_SZ /f /d "mscoree.dll"
REG ADD "HKLM\SOFTWARE\Classes\CLSID\%CLSID%\InprocServer32" /v "ThreadingModel" /t REG_SZ /f /d "Both"
REM REG ADD "HKLM\SOFTWARE\Classes\CLSID\%CLSID%\InprocServer32" /v "Class" /t REG_SZ /f /d "Both"
REG ADD "HKLM\SOFTWARE\Classes\CLSID\%CLSID%\InprocServer32" /v "RuntimeVersion" /t REG_SZ /f /d "v4.0.30319"
REG ADD "HKLM\SOFTWARE\Classes\CLSID\%CLSID%\InprocServer32" /v "CodeBase" /t REG_SZ /f /d "%BinaryPath%"
REG ADD "HKLM\SOFTWARE\Classes\Lithnet.CredentialProvider.Sample.net472.x64" /ve /t REG_SZ /f /d "Lithnet.CredentialProvider.Samples.TestCredentialProvider"
REG ADD "HKLM\SOFTWARE\Classes\Lithnet.CredentialProvider.Sample.net472.x64\CLSID" /ve /t REG_SZ /f /d "%CLSID%"
REG ADD "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Authentication\Credential Providers\%CLSID%" /ve /t REG_SZ /f /d "Lithnet.CredentialProvider.Sample.net472.x64"
```
## Disable the sample
To disable the credential provider, run the following command.
```
REG ADD "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Authentication\Credential Providers\{4eb911fa-ca18-40ea-86df-19aff5d1da58"}" /v "Disabled" /t REG_DWORD /f /d 1
```
## Re-enable the sample
To enable the provider again after disabling it, run the following command.
```
REG ADD "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Authentication\Credential Providers\{4eb911fa-ca18-40ea-86df-19aff5d1da58"}" /v "Disabled" /t REG_DWORD /f /d 0
```
## Uninstalling the sample
To remove the credential provider, run the following command.
```
%windir%\Microsoft.NET\Framework64\v4.0.30319\regasm /u "Lithnet.CredentialProvider.Sample.net472.x64.dll"
REG DELETE "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Authentication\Credential Providers\{4eb911fa-ca18-40ea-86df-19aff5d1da58"}" /f
```
@@ -0,0 +1,36 @@
using Microsoft.Extensions.Logging;
using NLog;
using NLog.Extensions.Logging;
namespace Lithnet.CredentialProvider.Samples
{
internal static class InternalLogger
{
internal static ILoggerFactory LoggerFactory { get; }
static InternalLogger()
{
/*
This sample uses NLog to capture trace events from the provider, but you can use any
logging system compatible with Microsoft.Extensions.Logging;
*/
var config = new NLog.Config.LoggingConfiguration();
var logconsole = new NLog.Targets.ConsoleTarget("logconsole");
/*
Add file based logging if required
*/
var logfile = new NLog.Targets.FileTarget("logfile") { FileName = "c:\\file.txt" };
config.AddRule(NLog.LogLevel.Trace, NLog.LogLevel.Fatal, logfile);
config.AddRule(NLog.LogLevel.Trace, NLog.LogLevel.Fatal, logconsole);
LogManager.Configuration = config;
InternalLogger.LoggerFactory = new NLogLoggerFactory(new NLogLoggerProvider(new NLogProviderOptions() { ReplaceLoggerFactory = true }, LogManager.LogFactory));
}
}
}
@@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net472</TargetFramework>
<RegisterForComInterop>false</RegisterForComInterop>
<Platform>x64</Platform>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Lithnet.CredentialProvider" Version="1.0.0-beta.26" />
<PackageReference Include="NLog" Version="5.1.1" />
<PackageReference Include="NLog.Extensions.Logging" Version="5.2.1" />
</ItemGroup>
</Project>
@@ -39,7 +39,7 @@ namespace Lithnet.CredentialProvider.Samples {
internal static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Lithnet.CredentialProvider.Samples.Resources", typeof(Resources).Assembly);
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Lithnet.CredentialProvider.Sample.Net472.x64.Resources", typeof(Resources).Assembly);
resourceMan = temp;
}
return resourceMan;
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

@@ -0,0 +1,97 @@
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using Microsoft.Extensions.Logging;
namespace Lithnet.CredentialProvider.Samples
{
[ComVisible(true)]
[ClassInterface(ClassInterfaceType.None)]
[ProgId("Lithnet.CredentialProvider.Sample.net472.x64")]
[Guid("4eb911fa-ca18-40ea-86df-19aff5d1da58")]
public class TestCredentialProviderNet472x64 : CredentialProviderBase
{
public static void SelfRegister()
{
CredentialProviderRegistrationServices.RegisterCredentialProvider<TestCredentialProviderNet472x64>();
}
protected override ILoggerFactory GetLoggerFactory()
{
return InternalLogger.LoggerFactory;
}
public override IEnumerable<ControlBase> GetControls(UsageScenario cpus)
{
var password = new SecurePasswordTextboxControl(ControlKeys.Password, "Password");
if (cpus == UsageScenario.ChangePassword)
{
var confirmPassword = new SecurePasswordTextboxControl(ControlKeys.ConfirmPassword, "Confirm password");
yield return new TextboxControl(ControlKeys.Username, "Username");
yield return password;
yield return confirmPassword;
yield return new SubmitButtonControl(ControlKeys.ButtonSubmit, "Submit", confirmPassword);
}
else
{
yield return new CredentialProviderLabelControl(ControlKeys.LabelCredentialProvider, "Login with showcase credential provider");
yield return new CredentialProviderLogoControl(ControlKeys.ImageCredentialProvider, "Credential provider logo", Resources.TileIcon);
yield return new CredentialProviderLogoControl(ControlKeys.ImageUserTile, "User tile image", Resources.TileIcon);
yield return new LargeLabelControl(ControlKeys.LabelLargeHeading, "The is our showcase credential provider");
yield return new SmallLabelControl(ControlKeys.LabelSmallHeading, "Let's see what we can do");
yield return new CheckboxControl(ControlKeys.Checkbox, "A checkbox");
yield return new SmallLabelControl(ControlKeys.LabelCheckboxValue, "The check box is currently unchecked");
yield return new CommandLinkControl(ControlKeys.CommandLinkCheckboxValue, "Click this link to change the check box value in code behind");
yield return new ComboboxControl(ControlKeys.Combobox, "Items to choose from:");
yield return new SmallLabelControl(ControlKeys.LabelComboboxSelectedItem, "This is the currently selected item: <none>");
yield return new CommandLinkControl(ControlKeys.CommandLinkComboboxAdd, "Add a random item to the combo box");
yield return new CommandLinkControl(ControlKeys.CommandLinkComboboxRemove, "Remove the last item from the combo box");
yield return new TextboxControl(ControlKeys.Username, "Username");
yield return new CommandLinkControl(ControlKeys.CommandLinkUsername, "Click this link to generate a random username");
yield return password;
yield return new SubmitButtonControl(ControlKeys.ButtonSubmit, "Submit", password);
}
}
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;
}
}
public override bool ShouldIncludeUserTile(CredentialProviderUser user)
{
return true;
}
public override bool ShouldIncludeGenericTile()
{
return true;
}
public override CredentialProviderCredential1Tile CreateGenericTile()
{
return new TestCredentialProviderTile(this);
}
public override CredentialProviderCredential1Tile CreateUserTile(CredentialProviderUser user)
{
return new TestCredentialProviderTile(this, user);
}
}
}
@@ -15,7 +15,7 @@ namespace Lithnet.CredentialProvider.Samples
private SmallLabelControl CheckboxStateControl;
private SmallLabelControl ComboboxStateControl;
private ILogger logger = Program.LoggerFactory.CreateLogger<TestCredentialProviderTile>();
private ILogger logger = InternalLogger.LoggerFactory.CreateLogger<TestCredentialProviderTile>();
public TestCredentialProviderTile(CredentialProviderBase credentialProvider) : base(credentialProvider)
{
@@ -65,29 +65,29 @@ namespace Lithnet.CredentialProvider.Samples
{
if (UsageScenario == UsageScenario.ChangePassword)
{
PasswordConfirmControl = Controls.GetControl<SecurePasswordTextboxControl>(TestCredentialProviderControlKeys.ConfirmPassword);
PasswordConfirmControl = Controls.GetControl<SecurePasswordTextboxControl>(ControlKeys.ConfirmPassword);
}
PasswordControl = Controls.GetControl<SecurePasswordTextboxControl>(TestCredentialProviderControlKeys.Password);
CheckboxControl = Controls.GetControl<CheckboxControl>(TestCredentialProviderControlKeys.Checkbox);
CheckboxStateControl = Controls.GetControl<SmallLabelControl>(TestCredentialProviderControlKeys.LabelCheckboxValue);
PasswordControl = Controls.GetControl<SecurePasswordTextboxControl>(ControlKeys.Password);
CheckboxControl = Controls.GetControl<CheckboxControl>(ControlKeys.Checkbox);
CheckboxStateControl = Controls.GetControl<SmallLabelControl>(ControlKeys.LabelCheckboxValue);
Controls.GetControl<CommandLinkControl>(TestCredentialProviderControlKeys.CommandLinkCheckboxValue).OnClick = () =>
Controls.GetControl<CommandLinkControl>(ControlKeys.CommandLinkCheckboxValue).OnClick = () =>
{
CheckboxControl.IsChecked = !CheckboxControl.IsChecked;
};
CheckboxControl.PropertyChanged += CheckboxControl_PropertyChanged;
UsernameControl = Controls.GetControl<TextboxControl>(TestCredentialProviderControlKeys.Username);
Controls.GetControl<CommandLinkControl>(TestCredentialProviderControlKeys.CommandLinkUsername).OnClick = () =>
UsernameControl = Controls.GetControl<TextboxControl>(ControlKeys.Username);
Controls.GetControl<CommandLinkControl>(ControlKeys.CommandLinkUsername).OnClick = () =>
{
Username = Guid.NewGuid().ToString();
};
ComboboxStateControl = Controls.GetControl<SmallLabelControl>(TestCredentialProviderControlKeys.LabelComboboxSelectedItem);
ComboboxStateControl = Controls.GetControl<SmallLabelControl>(ControlKeys.LabelComboboxSelectedItem);
ComboboxControl = Controls.GetControl<ComboboxControl>(TestCredentialProviderControlKeys.Combobox);
ComboboxControl = Controls.GetControl<ComboboxControl>(ControlKeys.Combobox);
ComboboxControl.PropertyChanged += ComboboxControl_PropertyChanged;
ComboboxControl.ComboBoxItems.Add("Item 1");
ComboboxControl.ComboBoxItems.Add("Item 2");
@@ -95,12 +95,12 @@ namespace Lithnet.CredentialProvider.Samples
ComboboxControl.SelectedItemIndex = 0;
int count = 3;
Controls.GetControl<CommandLinkControl>(TestCredentialProviderControlKeys.CommandLinkComboboxAdd).OnClick = () =>
Controls.GetControl<CommandLinkControl>(ControlKeys.CommandLinkComboboxAdd).OnClick = () =>
{
ComboboxControl.ComboBoxItems.Add($"Item {++count}");
};
Controls.GetControl<CommandLinkControl>(TestCredentialProviderControlKeys.CommandLinkComboboxRemove).OnClick = () =>
Controls.GetControl<CommandLinkControl>(ControlKeys.CommandLinkComboboxRemove).OnClick = () =>
{
if (ComboboxControl.ComboBoxItems.Count > 0)
{
@@ -140,7 +140,7 @@ namespace Lithnet.CredentialProvider.Samples
domain = Environment.MachineName;
}
var spassword = Controls.GetControl<SecurePasswordTextboxControl>(TestCredentialProviderControlKeys.Password).Password;
var spassword = Controls.GetControl<SecurePasswordTextboxControl>(ControlKeys.Password).Password;
if (!IsChecked)
{
@@ -7,10 +7,10 @@ In order to install and run the sample app, you have to register the COM compone
Build the EXE, and from an elevated command prompt, change to the bin folder, and run the following commands
```
%windir%\Microsoft.NET\Framework64\v4.0.30319\regasm /codebase "Lithnet.CredentialProvider.Samples.exe"
%windir%\Microsoft.NET\Framework\v4.0.30319\regasm /codebase "Lithnet.CredentialProvider.Sample.net472.x86.dll"
REG ADD "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Authentication\Credential Providers\{1A3993B6-EB2B-44BB-A788-7AB1711DFF16}" /f
REG ADD "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Authentication\Credential Providers\{1A3993B6-EB2B-44BB-A788-7AB1711DFF16}" /ve /t REG_SZ /f /d "Lithnet.CredentialProvider.Samples.TestCredentialProvider"
REG ADD "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Authentication\Credential Providers\{c9055c88-03f9-4a12-8e33-1ee75826a4a6}" /f
REG ADD "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Authentication\Credential Providers\{c9055c88-03f9-4a12-8e33-1ee75826a4a6}" /ve /t REG_SZ /f /d "Lithnet.CredentialProvider.Sample.net472.x86"
```
## Disable the sample
@@ -18,19 +18,19 @@ REG ADD "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Authentication\Credentia
To disable the credential provider, run the following command.
```
REG ADD "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Authentication\Credential Providers\{1A3993B6-EB2B-44BB-A788-7AB1711DFF16}" /v "Disabled" /t REG_DWORD /f /d 1
REG ADD "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Authentication\Credential Providers\{c9055c88-03f9-4a12-8e33-1ee75826a4a6}" /v "Disabled" /t REG_DWORD /f /d 1
```
## Re-enable the sample
To enable the provider again after disabling it, run the following command.
```
REG ADD "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Authentication\Credential Providers\{1A3993B6-EB2B-44BB-A788-7AB1711DFF16}" /v "Disabled" /t REG_DWORD /f /d 0
REG ADD "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Authentication\Credential Providers\{c9055c88-03f9-4a12-8e33-1ee75826a4a6}" /v "Disabled" /t REG_DWORD /f /d 0
```
## Uninstalling the sample
To remove the credential provider, run the following command.
```
%windir%\Microsoft.NET\Framework64\v4.0.30319\regasm /u "Lithnet.CredentialProvider.Samples.exe"
REG DELETE "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Authentication\Credential Providers\{1A3993B6-EB2B-44BB-A788-7AB1711DFF16}" /f
%windir%\Microsoft.NET\Framework\v4.0.30319\regasm /u "Lithnet.CredentialProvider.Sample.net472.x86.dll"
REG DELETE "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Authentication\Credential Providers\{c9055c88-03f9-4a12-8e33-1ee75826a4a6}" /f
```
@@ -0,0 +1,20 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net472</TargetFramework>
<RegisterForComInterop>false</RegisterForComInterop>
<Platform>x86</Platform>
</PropertyGroup>
<ItemGroup>
<Compile Include="..\Lithnet.CredentialProvider.Sample.net472.x64\InternalLogger.cs" Link="InternalLogger.cs" />
<Compile Include="..\Lithnet.CredentialProvider.Sample.net472.x64\ControlKeys.cs" Link="ControlKeys.cs" />
<Compile Include="..\Lithnet.CredentialProvider.Sample.net472.x64\TestCredentialProviderTile.cs" Link="TestCredentialProviderTile.cs" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Lithnet.CredentialProvider" Version="1.0.0-beta.25" />
<PackageReference Include="NLog" Version="5.1.1" />
<PackageReference Include="NLog.Extensions.Logging" Version="5.2.1" />
</ItemGroup>
</Project>
@@ -0,0 +1,73 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace Lithnet.CredentialProvider.Samples {
using System;
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
// This class was auto-generated by the StronglyTypedResourceBuilder
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resources {
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Resources() {
}
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Lithnet.CredentialProvider.Sample.Net472.x64.Resources", typeof(Resources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap TileIcon {
get {
object obj = ResourceManager.GetObject("TileIcon", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
}
}
@@ -0,0 +1,124 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<data name="TileIcon" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>Resources\TileIcon.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
</root>
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

@@ -0,0 +1,100 @@
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using Microsoft.Extensions.Logging;
namespace Lithnet.CredentialProvider.Samples
{
[ComVisible(true)]
[ClassInterface(ClassInterfaceType.None)]
[ProgId("Lithnet.CredentialProvider.Sample.net472.x86")]
[Guid("c9055c88-03f9-4a12-8e33-1ee75826a4a6")]
public class TestCredentialProviderNet472x86 : CredentialProviderBase
{
private static readonly ILogger logger = InternalLogger.LoggerFactory.CreateLogger<TestCredentialProviderNet472x86>();
public static void SelfRegister()
{
CredentialProviderRegistrationServices.RegisterCredentialProvider<TestCredentialProviderNet472x86>();
}
protected override ILoggerFactory GetLoggerFactory()
{
return InternalLogger.LoggerFactory;
}
public override IEnumerable<ControlBase> GetControls(UsageScenario cpus)
{
var password = new SecurePasswordTextboxControl(ControlKeys.Password, "Password");
if (cpus == UsageScenario.ChangePassword)
{
var confirmPassword = new SecurePasswordTextboxControl(ControlKeys.ConfirmPassword, "Confirm password");
yield return new TextboxControl(ControlKeys.Username, "Username");
yield return password;
yield return confirmPassword;
yield return new SubmitButtonControl(ControlKeys.ButtonSubmit, "Submit", confirmPassword);
}
else
{
yield return new CredentialProviderLabelControl(ControlKeys.LabelCredentialProvider, "Login with showcase credential provider");
yield return new CredentialProviderLogoControl(ControlKeys.ImageCredentialProvider, "Credential provider logo", Resources.TileIcon);
yield return new CredentialProviderLogoControl(ControlKeys.ImageUserTile, "User tile image", Resources.TileIcon);
yield return new LargeLabelControl(ControlKeys.LabelLargeHeading, "The is our showcase credential provider");
yield return new SmallLabelControl(ControlKeys.LabelSmallHeading, "Let's see what we can do");
yield return new CheckboxControl(ControlKeys.Checkbox, "A checkbox");
yield return new SmallLabelControl(ControlKeys.LabelCheckboxValue, "The check box is currently unchecked");
yield return new CommandLinkControl(ControlKeys.CommandLinkCheckboxValue, "Click this link to change the check box value in code behind");
yield return new ComboboxControl(ControlKeys.Combobox, "Items to choose from:");
yield return new SmallLabelControl(ControlKeys.LabelComboboxSelectedItem, "This is the currently selected item: <none>");
yield return new CommandLinkControl(ControlKeys.CommandLinkComboboxAdd, "Add a random item to the combo box");
yield return new CommandLinkControl(ControlKeys.CommandLinkComboboxRemove, "Remove the last item from the combo box");
yield return new TextboxControl(ControlKeys.Username, "Username");
yield return new CommandLinkControl(ControlKeys.CommandLinkUsername, "Click this link to generate a random username");
yield return password;
yield return new SubmitButtonControl(ControlKeys.ButtonSubmit, "Submit", password);
}
}
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;
}
}
public override bool ShouldIncludeUserTile(CredentialProviderUser user)
{
return true;
}
public override bool ShouldIncludeGenericTile()
{
return true;
}
public override CredentialProviderCredential1Tile CreateGenericTile()
{
return new TestCredentialProviderTile(this);
}
public override CredentialProviderCredential1Tile CreateUserTile(CredentialProviderUser user)
{
return new TestCredentialProviderTile(this, user);
}
}
}
@@ -0,0 +1,36 @@
# Using the sample credential provider
## Installing the sample
In order to install and run the sample app, you have to register the COM component
Build the EXE, and from an elevated command prompt, change to the bin folder, and run the following commands
```
regsvr32 "Lithnet.CredentialProvider.Sample.net6.0.x64.comhost.dll"
REG ADD "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Authentication\Credential Providers\{4cd12d80-9259-4f38-94dc-1828080ad9ff}" /f
REG ADD "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Authentication\Credential Providers\{4cd12d80-9259-4f38-94dc-1828080ad9ff}" /ve /t REG_SZ /f /d "Lithnet.CredentialProvider.Sample.net6.0.x64"
```
## Disable the sample
To disable the credential provider, run the following command.
```
REG ADD "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Authentication\Credential Providers\{4cd12d80-9259-4f38-94dc-1828080ad9ff}" /v "Disabled" /t REG_DWORD /f /d 1
```
## Re-enable the sample
To enable the provider again after disabling it, run the following command.
```
REG ADD "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Authentication\Credential Providers\{4cd12d80-9259-4f38-94dc-1828080ad9ff}" /v "Disabled" /t REG_DWORD /f /d 0
```
## Uninstalling the sample
To remove the credential provider, run the following command.
```
regsvr32 /u "Lithnet.CredentialProvider.Sample.net6.0.x64.comhost.dll"
REG DELETE "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Authentication\Credential Providers\{4cd12d80-9259-4f38-94dc-1828080ad9ff}" /f
```
@@ -0,0 +1,31 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0-windows</TargetFramework>
<RegisterForComInterop>false</RegisterForComInterop>
<Platform>x64</Platform>
<EnableComHosting>true</EnableComHosting>
</PropertyGroup>
<ItemGroup>
<None Remove="Resources\TileIcon.png" />
</ItemGroup>
<ItemGroup>
<Compile Include="..\Lithnet.CredentialProvider.Sample.net472.x64\InternalLogger.cs" Link="InternalLogger.cs" />
<Compile Include="..\Lithnet.CredentialProvider.Sample.net472.x64\ControlKeys.cs" Link="ControlKeys.cs" />
<Compile Include="..\Lithnet.CredentialProvider.Sample.net472.x64\TestCredentialProviderTile.cs" Link="TestCredentialProviderTile.cs" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Resources\TileIcon.png" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Lithnet.CredentialProvider" Version="1.0.0-beta.25" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="6.0.0" />
<PackageReference Include="NLog" Version="5.1.1" />
<PackageReference Include="NLog.Extensions.Logging" Version="5.2.1" />
</ItemGroup>
</Project>
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

@@ -0,0 +1,105 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Reflection;
using System.Runtime.InteropServices;
using Microsoft.Extensions.Logging;
namespace Lithnet.CredentialProvider.Samples
{
[ComVisible(true)]
[ClassInterface(ClassInterfaceType.None)]
[ProgId("Lithnet.CredentialProvider.Sample.net6.0.x64")]
[Guid("4cd12d80-9259-4f38-94dc-1828080ad9ff")]
public class TestCredentialProviderNet60x64 : CredentialProviderBase
{
private static readonly ILogger logger = InternalLogger.LoggerFactory.CreateLogger<TestCredentialProviderNet60x64>();
public static void SelfRegister()
{
CredentialProviderRegistrationServices.RegisterCredentialProvider<TestCredentialProviderNet60x64>();
}
protected override ILoggerFactory GetLoggerFactory()
{
return InternalLogger.LoggerFactory;
}
public override IEnumerable<ControlBase> GetControls(UsageScenario cpus)
{
var password = new SecurePasswordTextboxControl(ControlKeys.Password, "Password");
if (cpus == UsageScenario.ChangePassword)
{
var confirmPassword = new SecurePasswordTextboxControl(ControlKeys.ConfirmPassword, "Confirm password");
yield return new TextboxControl(ControlKeys.Username, "Username");
yield return password;
yield return confirmPassword;
yield return new SubmitButtonControl(ControlKeys.ButtonSubmit, "Submit", confirmPassword);
}
else
{
yield return new CredentialProviderLabelControl(ControlKeys.LabelCredentialProvider, "Login with showcase credential provider");
var image = new Bitmap(Assembly.GetExecutingAssembly().GetManifestResourceStream("Lithnet.CredentialProvider.Sample.net6.0.x64.Resources.TileIcon.png"));
yield return new CredentialProviderLogoControl(ControlKeys.ImageCredentialProvider, "Credential provider logo", image);
yield return new CredentialProviderLogoControl(ControlKeys.ImageUserTile, "User tile image", image);
yield return new LargeLabelControl(ControlKeys.LabelLargeHeading, "The is our showcase credential provider");
yield return new SmallLabelControl(ControlKeys.LabelSmallHeading, "Let's see what we can do");
yield return new CheckboxControl(ControlKeys.Checkbox, "A checkbox");
yield return new SmallLabelControl(ControlKeys.LabelCheckboxValue, "The check box is currently unchecked");
yield return new CommandLinkControl(ControlKeys.CommandLinkCheckboxValue, "Click this link to change the check box value in code behind");
yield return new ComboboxControl(ControlKeys.Combobox, "Items to choose from:");
yield return new SmallLabelControl(ControlKeys.LabelComboboxSelectedItem, "This is the currently selected item: <none>");
yield return new CommandLinkControl(ControlKeys.CommandLinkComboboxAdd, "Add a random item to the combo box");
yield return new CommandLinkControl(ControlKeys.CommandLinkComboboxRemove, "Remove the last item from the combo box");
yield return new TextboxControl(ControlKeys.Username, "Username");
yield return new CommandLinkControl(ControlKeys.CommandLinkUsername, "Click this link to generate a random username");
yield return password;
yield return new SubmitButtonControl(ControlKeys.ButtonSubmit, "Submit", password);
}
}
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;
}
}
public override bool ShouldIncludeUserTile(CredentialProviderUser user)
{
return true;
}
public override bool ShouldIncludeGenericTile()
{
return true;
}
public override CredentialProviderCredential1Tile CreateGenericTile()
{
return new TestCredentialProviderTile(this);
}
public override CredentialProviderCredential1Tile CreateUserTile(CredentialProviderUser user)
{
return new TestCredentialProviderTile(this, user);
}
}
}
@@ -0,0 +1,36 @@
# Using the sample credential provider
## Installing the sample
In order to install and run the sample app, you have to register the COM component
Build the EXE, and from an elevated command prompt, change to the bin folder, and run the following commands
```
regsvr32 "Lithnet.CredentialProvider.Sample.net6.0.x86.comhost.dll"
REG ADD "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Authentication\Credential Providers\{90592593-f4d3-4f62-aa83-9cf1f7b590e0}" /f
REG ADD "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Authentication\Credential Providers\{90592593-f4d3-4f62-aa83-9cf1f7b590e0}" /ve /t REG_SZ /f /d "Lithnet.CredentialProvider.Sample.net6.0.x86"
```
## Disable the sample
To disable the credential provider, run the following command.
```
REG ADD "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Authentication\Credential Providers\{90592593-f4d3-4f62-aa83-9cf1f7b590e0}" /v "Disabled" /t REG_DWORD /f /d 1
```
## Re-enable the sample
To enable the provider again after disabling it, run the following command.
```
REG ADD "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Authentication\Credential Providers\{90592593-f4d3-4f62-aa83-9cf1f7b590e0}" /v "Disabled" /t REG_DWORD /f /d 0
```
## Uninstalling the sample
To remove the credential provider, run the following command.
```
regsvr32 /u "Lithnet.CredentialProvider.Sample.net6.0.x86.comhost.dll"
REG DELETE "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Authentication\Credential Providers\{90592593-f4d3-4f62-aa83-9cf1f7b590e0}" /f
```
@@ -0,0 +1,31 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0-windows</TargetFramework>
<RegisterForComInterop>false</RegisterForComInterop>
<Platform>x86</Platform>
<EnableComHosting>true</EnableComHosting>
</PropertyGroup>
<ItemGroup>
<None Remove="Resources\TileIcon.png" />
</ItemGroup>
<ItemGroup>
<Compile Include="..\Lithnet.CredentialProvider.Sample.net472.x64\InternalLogger.cs" Link="InternalLogger.cs" />
<Compile Include="..\Lithnet.CredentialProvider.Sample.net472.x64\ControlKeys.cs" Link="ControlKeys.cs" />
<Compile Include="..\Lithnet.CredentialProvider.Sample.net472.x64\TestCredentialProviderTile.cs" Link="TestCredentialProviderTile.cs" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Resources\TileIcon.png" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Lithnet.CredentialProvider" Version="1.0.0-beta.25" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="6.0.0" />
<PackageReference Include="NLog" Version="5.1.1" />
<PackageReference Include="NLog.Extensions.Logging" Version="5.2.1" />
</ItemGroup>
</Project>
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

@@ -0,0 +1,104 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Reflection;
using System.Runtime.InteropServices;
using Microsoft.Extensions.Logging;
namespace Lithnet.CredentialProvider.Samples
{
[ComVisible(true)]
[ClassInterface(ClassInterfaceType.None)]
[ProgId("Lithnet.CredentialProvider.Sample.net6.0.x86")]
[Guid("90592593-f4d3-4f62-aa83-9cf1f7b590e0")]
public class TestCredentialProviderNet60x86 : CredentialProviderBase
{
private static readonly ILogger logger = InternalLogger.LoggerFactory.CreateLogger<TestCredentialProviderNet60x86>();
public static void SelfRegister()
{
CredentialProviderRegistrationServices.RegisterCredentialProvider<TestCredentialProviderNet60x86>();
}
protected override ILoggerFactory GetLoggerFactory()
{
return InternalLogger.LoggerFactory;
}
public override IEnumerable<ControlBase> GetControls(UsageScenario cpus)
{
var password = new SecurePasswordTextboxControl(ControlKeys.Password, "Password");
if (cpus == UsageScenario.ChangePassword)
{
var confirmPassword = new SecurePasswordTextboxControl(ControlKeys.ConfirmPassword, "Confirm password");
yield return new TextboxControl(ControlKeys.Username, "Username");
yield return password;
yield return confirmPassword;
yield return new SubmitButtonControl(ControlKeys.ButtonSubmit, "Submit", confirmPassword);
}
else
{
var image = new Bitmap(Assembly.GetExecutingAssembly().GetManifestResourceStream("Lithnet.CredentialProvider.Sample.net6.0.x86.Resources.TileIcon.png"));
yield return new CredentialProviderLabelControl(ControlKeys.LabelCredentialProvider, "Login with showcase credential provider");
yield return new CredentialProviderLogoControl(ControlKeys.ImageCredentialProvider, "Credential provider logo", image);
yield return new CredentialProviderLogoControl(ControlKeys.ImageUserTile, "User tile image", image);
yield return new LargeLabelControl(ControlKeys.LabelLargeHeading, "The is our showcase credential provider");
yield return new SmallLabelControl(ControlKeys.LabelSmallHeading, "Let's see what we can do");
yield return new CheckboxControl(ControlKeys.Checkbox, "A checkbox");
yield return new SmallLabelControl(ControlKeys.LabelCheckboxValue, "The check box is currently unchecked");
yield return new CommandLinkControl(ControlKeys.CommandLinkCheckboxValue, "Click this link to change the check box value in code behind");
yield return new ComboboxControl(ControlKeys.Combobox, "Items to choose from:");
yield return new SmallLabelControl(ControlKeys.LabelComboboxSelectedItem, "This is the currently selected item: <none>");
yield return new CommandLinkControl(ControlKeys.CommandLinkComboboxAdd, "Add a random item to the combo box");
yield return new CommandLinkControl(ControlKeys.CommandLinkComboboxRemove, "Remove the last item from the combo box");
yield return new TextboxControl(ControlKeys.Username, "Username");
yield return new CommandLinkControl(ControlKeys.CommandLinkUsername, "Click this link to generate a random username");
yield return password;
yield return new SubmitButtonControl(ControlKeys.ButtonSubmit, "Submit", password);
}
}
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;
}
}
public override bool ShouldIncludeUserTile(CredentialProviderUser user)
{
return true;
}
public override bool ShouldIncludeGenericTile()
{
return true;
}
public override CredentialProviderCredential1Tile CreateGenericTile()
{
return new TestCredentialProviderTile(this);
}
public override CredentialProviderCredential1Tile CreateUserTile(CredentialProviderUser user)
{
return new TestCredentialProviderTile(this, user);
}
}
}
@@ -0,0 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0-windows</TargetFramework>
<RegisterForComInterop>false</RegisterForComInterop>
<Platform>x64</Platform>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Logging" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="6.0.0" />
<PackageReference Include="NLog" Version="5.1.1" />
<PackageReference Include="NLog.Extensions.Logging" Version="5.2.1" />
</ItemGroup>
</Project>
@@ -0,0 +1,60 @@
using System;
using System.Runtime.InteropServices;
namespace Lithnet.CredentialProvider.Samples
{
public static class CredUI
{
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct CREDUI_INFO
{
public int cbSize;
public IntPtr hwndParent;
public string pszMessageText;
public string pszCaptionText;
public IntPtr hbmBanner;
}
[DllImport("credui.dll", CharSet = CharSet.Auto)]
public static extern int CredUIPromptForWindowsCredentials(
ref CREDUI_INFO uiInfo,
int authError,
ref uint authPackage,
IntPtr InAuthBuffer,
uint InAuthBufferSize,
out IntPtr refOutAuthBuffer,
out uint refOutAuthBufferSize,
ref bool fSave,
uint flags
);
public static void Prompt(string caption, string message)
{
var uiInfo = new CREDUI_INFO()
{
pszCaptionText = caption,
pszMessageText = message
};
uiInfo.cbSize = Marshal.SizeOf(uiInfo);
uint authPackage = 0;
var save = false;
CredUIPromptForWindowsCredentials(
ref uiInfo,
0,
ref authPackage,
IntPtr.Zero,
0,
out IntPtr outCredBuffer,
out uint outCredSize,
ref save,
0
);
Marshal.FreeCoTaskMem(outCredBuffer);
}
}
}
@@ -0,0 +1,16 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0-windows</TargetFramework>
<RegisterForComInterop>false</RegisterForComInterop>
<Platform>x86</Platform>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Logging" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="6.0.0" />
<PackageReference Include="NLog" Version="5.1.1" />
<PackageReference Include="NLog.Extensions.Logging" Version="5.2.1" />
</ItemGroup>
</Project>
@@ -0,0 +1,44 @@
using System;
using Microsoft.Extensions.Logging;
using NLog;
using NLog.Extensions.Logging;
namespace Lithnet.CredentialProvider.Samples
{
internal static class Program
{
internal static ILoggerFactory LoggerFactory { get; }
static Program()
{
/*
This sample uses NLog to capture trace events from the provider, but you can use any
logging system compatible with Microsoft.Extensions.Logging;
*/
var config = new NLog.Config.LoggingConfiguration();
var logconsole = new NLog.Targets.ConsoleTarget("logconsole");
/*
Add file based logging if required
*/
// var logfile = new NLog.Targets.FileTarget("logfile") { FileName = "c:\\file.txt" };
//config.AddRule(NLog.LogLevel.Trace, NLog.LogLevel.Fatal, logfile);
config.AddRule(NLog.LogLevel.Trace, NLog.LogLevel.Fatal, logconsole);
LogManager.Configuration = config;
Program.LoggerFactory = new NLogLoggerFactory(new NLogLoggerProvider(new NLogProviderOptions() { ReplaceLoggerFactory = true }, LogManager.LogFactory));
}
static void Main(string[] args)
{
CredUI.Prompt("Login with Cred UI", "Select your favorite credential provider");
Console.WriteLine("Done! Press any key to exit");
Console.ReadKey();
}
}
}