Skip to content

Commit

Permalink
Adds PowerShell module for getting Lithnet local admin passwords and …
Browse files Browse the repository at this point in the history
…history

Fixes an issue where the encryption certificate UI showed that read permissions were missing from a certificate
  • Loading branch information
ryannewington committed Nov 8, 2020
1 parent a655b5a commit 6a14951
Show file tree
Hide file tree
Showing 27 changed files with 609 additions and 209 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,7 @@ output/

output-x64
output-x86
output-ps

setup-packages/
Prerequisites/
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@
<ROW Property="ARPCOMMENTS" Value="This installer database contains the logic and data required to install [|ProductName]." ValueLocId="*"/>
<ROW Property="ARPPRODUCTICON" Value="accessmanager.exe" Type="8"/>
<ROW Property="Manufacturer" Value="Lithnet"/>
<ROW Property="ProductCode" Value="1033:{D4E1EA3E-C147-4222-8FA6-80B1748472C0} " Type="16"/>
<ROW Property="ProductCode" Value="1033:{55E53860-7C1B-494A-850D-D80C1908FC23} " Type="16"/>
<ROW Property="ProductLanguage" Value="1033"/>
<ROW Property="ProductName" Value="Lithnet Access Manager Agent"/>
<ROW Property="ProductVersion" Value="1.0.7728.0" Type="32" TargetFile="Lithnet.AccessManager.Agent.exe"/>
<ROW Property="ProductVersion" Value="1.0.7791.0" Type="32" TargetFile="Lithnet.AccessManager.Agent.exe"/>
<ROW Property="SETUPEXEDIR" Value="1"/>
<ROW Property="SecureCustomProperties" Value="OLDPRODUCTS;AI_NEWERPRODUCTFOUND"/>
<ROW Property="UpgradeCode" Value="{EEDECF4C-BABB-4AE0-9CB9-DC051FF1AE75}"/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@
<ROW Property="ARPCOMMENTS" Value="This installer database contains the logic and data required to install [|ProductName]." ValueLocId="*"/>
<ROW Property="ARPPRODUCTICON" Value="accessmanager.exe" Type="8"/>
<ROW Property="Manufacturer" Value="Lithnet"/>
<ROW Property="ProductCode" Value="1033:{8664C883-6F30-4F52-8FC1-11DF6AAA1DD6} " Type="16"/>
<ROW Property="ProductCode" Value="1033:{31D5CC3B-8809-4E4D-909E-C3EA8322F9D3} " Type="16"/>
<ROW Property="ProductLanguage" Value="1033"/>
<ROW Property="ProductName" Value="Lithnet Access Manager Agent"/>
<ROW Property="ProductVersion" Value="1.0.7728.0" Type="32" TargetFile="Lithnet.AccessManager.Agent.exe"/>
<ROW Property="ProductVersion" Value="1.0.7791.0" Type="32" TargetFile="Lithnet.AccessManager.Agent.exe"/>
<ROW Property="SETUPEXEDIR" Value="1"/>
<ROW Property="SecureCustomProperties" Value="OLDPRODUCTS;AI_NEWERPRODUCTFOUND"/>
<ROW Property="UpgradeCode" Value="{EEDECF4C-BABB-4AE0-9CB9-DC051FF1AE75}"/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,8 @@
<PackageReference Include="Microsoft.Extensions.Hosting" Version="3.1.6" />
<PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="3.1.6" />
<PackageReference Include="Microsoft.Win32.Registry" Version="4.7.0" />
<PackageReference Include="nlog" Version="4.7.3" />
<PackageReference Include="NLog.Extensions.Logging" Version="1.6.4" />
<PackageReference Include="nlog" Version="4.7.5" />
<PackageReference Include="NLog.Extensions.Logging" Version="1.6.5" />
<PackageReference Include="system.directoryservices" Version="4.7.0" />
<PackageReference Include="System.DirectoryServices.AccountManagement" Version="4.7.0" />
</ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Management.Automation;
using System.Linq;

namespace Lithnet.AccessManager.PowerShell.Test
{
[TestClass]
public class GetLithnetLocalAdminPasswordTests
{
[TestMethod]
public void GetLocalAdminPassword()
{
System.Management.Automation.PowerShell ps = System.Management.Automation.PowerShell.Create();
ps.AddCommand(new CmdletInfo("Get-LithnetLocalAdminPassword", typeof(GetLocalAdminPassword)));
ps.AddParameter("ComputerName", "IDMDEV1\\PC1");
var output = ps.Invoke();

Assert.AreEqual(1, output.Count);
var result = output[0];

Assert.AreEqual("Password", result.Properties["Password"].Value);
}

[TestMethod]
public void GetLocalAdminPasswordHistory()
{
System.Management.Automation.PowerShell ps = System.Management.Automation.PowerShell.Create();
ps.AddCommand(new CmdletInfo("Get-LithnetLocalAdminPasswordHistory", typeof(GetLocalAdminPasswordHistory)));
ps.AddParameter("ComputerName", "IDMDEV1\\PC1");
var output = ps.Invoke();

Assert.AreEqual(3, output.Count);

var passwords = output.Select(t => t.Properties["Password"].Value as string).ToList();

CollectionAssert.AreEquivalent(new[] { "History-1", "History-2", "History-3" }, passwords);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{22F8D82B-84B7-4D44-83AC-33BCB3B6EEBA}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Lithnet.AccessManager.PowerShell.Test</RootNamespace>
<AssemblyName>Lithnet.AccessManager.PowerShell.Test</AssemblyName>
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<ProjectTypeGuids>{3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">15.0</VisualStudioVersion>
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
<ReferencePath>$(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages</ReferencePath>
<IsCodedUITest>False</IsCodedUITest>
<TestProjectType>UnitTest</TestProjectType>
<NuGetPackageImportStamp>
</NuGetPackageImportStamp>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<GenerateBindingRedirectsOutputType>true</GenerateBindingRedirectsOutputType>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
</ItemGroup>
<ItemGroup>
<Compile Include="GetLithnetLocalAdminPasswordTests.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Lithnet.AccessManager.PowerShell\Lithnet.AccessManager.PowerShell.csproj">
<Project>{c8e94e87-f4bc-4623-a72d-7df376a2daec}</Project>
<Name>Lithnet.AccessManager.PowerShell</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Logging">
<Version>3.1.9</Version>
</PackageReference>
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions">
<Version>3.1.9</Version>
</PackageReference>
<PackageReference Include="Microsoft.PowerShell.5.ReferenceAssemblies">
<Version>1.1.0</Version>
</PackageReference>
<PackageReference Include="MSTest.TestAdapter">
<Version>2.1.1</Version>
</PackageReference>
<PackageReference Include="MSTest.TestFramework">
<Version>2.1.1</Version>
</PackageReference>
</ItemGroup>
<Import Project="$(VSToolsPath)\TeamTest\Microsoft.TestTools.targets" Condition="Exists('$(VSToolsPath)\TeamTest\Microsoft.TestTools.targets')" />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

[assembly: AssemblyTitle("Lithnet.AccessManager.PowerShell.Test")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Lithnet.AccessManager.PowerShell.Test")]
[assembly: AssemblyCopyright("Copyright © 2020")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]

[assembly: ComVisible(false)]

[assembly: Guid("22f8d82b-84b7-4d44-83ac-33bcb3b6eeba")]

[assembly: AssemblyVersion("1.0.*")]
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
using System;
using System.IO;
using System.Management.Automation;
using System.Reflection;

namespace Lithnet.AccessManager.PowerShell
{
public class AssemblyResolver : IModuleAssemblyInitializer, IModuleAssemblyCleanup
{
private static readonly string basePath = Path.GetFullPath(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location));

public void OnImport()
{
AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;
}

private Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
string assyPath = Path.Combine(basePath, $"{args.Name}.dll");

if (File.Exists(assyPath))
{
return Assembly.Load(assyPath);
}

return null;
}

public void OnRemove(PSModuleInfo psModuleInfo)
{
AppDomain.CurrentDomain.AssemblyResolve -= CurrentDomain_AssemblyResolve;
}
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
using System;
using System.Management.Automation;
using System.Security;
using System.Security.Cryptography.X509Certificates;
using System.ServiceModel.Channels;
using Microsoft.Extensions.Logging;

namespace Lithnet.AccessManager.PowerShell
{
[Cmdlet(VerbsCommon.Get, "LocalAdminPassword")]
public class GetLocalAdminPassword : Cmdlet
{
[Parameter(Mandatory = true, ParameterSetName = "CertificateFile", Position = 1)]
[Parameter(Mandatory = true, ParameterSetName = "Default", Position = 1)]
public string ComputerName { get; set; }

[Parameter(Mandatory = true, ParameterSetName = "CertificateFile", Position = 2)]
public string PfxCertificateFile { get; set; }

[Parameter(Mandatory = true, ParameterSetName = "CertificateFile", Position = 3)]
public SecureString PfxCertificateFilePassword { get; set; }

private ILoggerFactory logFactory;
private IDiscoveryServices discoveryServices;
private ICertificateProvider certificateProvider;
private IEncryptionProvider encryptionProvider;
private ILithnetAdminPasswordProvider adminPasswordProvider;
private IDirectory directory;
private X509Certificate2 certificate;

protected override void BeginProcessing()
{
this.logFactory = Microsoft.Extensions.Logging.Abstractions.NullLoggerFactory.Instance;
this.discoveryServices = new DiscoveryServices(logFactory.CreateLogger<DiscoveryServices>());
this.certificateProvider = new CertificateProvider(logFactory.CreateLogger<CertificateProvider>(), discoveryServices);
this.encryptionProvider = new EncryptionProvider();
this.adminPasswordProvider = new LithnetAdminPasswordProvider(logFactory.CreateLogger<LithnetAdminPasswordProvider>(), encryptionProvider, certificateProvider);
this.directory = new ActiveDirectory(discoveryServices);

if (this.PfxCertificateFile != null)
{
this.certificate = new X509Certificate2(this.PfxCertificateFile, this.PfxCertificateFilePassword);
}
else
{
this.certificate = null;
}
}

protected override void ProcessRecord()
{
IComputer computer = this.directory.GetComputer(this.ComputerName);

var item = this.adminPasswordProvider.GetCurrentPassword(computer, null);

if (item == null)
{
this.WriteVerbose("The computer did not have a Lithnet local admin password");
return;
}


var decryptedData = this.encryptionProvider.Decrypt(item.EncryptedData, (thumbprint) =>
{
if (certificate != null)
{
if (string.Equals(thumbprint, certificate.Thumbprint, System.StringComparison.OrdinalIgnoreCase))
{
return certificate;
}
}

return this.certificateProvider.FindDecryptionCertificate(thumbprint);
});

var result = new PSObject();
result.Properties.Add(new PSNoteProperty("ComputerName", computer.MsDsPrincipalName));
result.Properties.Add(new PSNoteProperty("Password", decryptedData));
result.Properties.Add(new PSNoteProperty("Created", item.Created.ToLocalTime()));
result.Properties.Add(new PSNoteProperty("Retired", item.Retired?.ToLocalTime()));

this.WriteObject(result);
}
}
}
Loading

0 comments on commit 6a14951

Please sign in to comment.