Cleans up static loggers
Adds test projects for different frameworks and architectures Adds registration tool assembly
This commit is contained in:
@@ -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
|
||||
{
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user