Skip to content
Merged

Dev #11

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,13 @@ jobs:
runs-on: windows-latest

steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
with:
fetch-depth: 0

- name: Setup dotnet
id: setup-dotnet
uses: actions/setup-dotnet@v4
uses: actions/setup-dotnet@v5
with:
global-json-file: src/global.json

Expand Down
175 changes: 103 additions & 72 deletions src/.editorconfig

Large diffs are not rendered by default.

17 changes: 12 additions & 5 deletions src/Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,22 @@
<Product>Windows User Rights Assignment Utility</Product>
<Description>Utility for managing user right assignments.</Description>
<Copyright>Copyright © Joseph L. Casale 2022</Copyright>
</PropertyGroup>

<PropertyGroup>
<CodeAnalysisRuleSet>$(MSBuildThisFileDirectory)StyleCop.ruleset</CodeAnalysisRuleSet>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Meziantou.Analyzer" Version="2.0.217">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="StyleCop.Analyzers.Unstable" Version="1.2.0.556">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>

<Target Name="GetVersionFromGit" BeforeTargets="BeforeBuild">
<Exec Command="git.exe describe --tags --long" WorkingDirectory="$(MSBuildProjectDirectory)" ConsoleToMSBuild="true" StandardOutputImportance="Low">
<Exec Command="git.exe describe --tags --long" WorkingDirectory="$(MSBuildProjectDirectory)" ConsoleToMsBuild="true" StandardOutputImportance="Low">
<Output TaskParameter="ConsoleOutput" PropertyName="GitTag" />
</Exec>

Expand Down
34 changes: 0 additions & 34 deletions src/StyleCop.ruleset

This file was deleted.

2 changes: 1 addition & 1 deletion src/Tests.Application/AdminOnlyFactAttribute.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,6 @@ public AdminOnlyFactAttribute()
return;
}

this.Skip = "Current user is not an administrator.";
Skip = "Current user is not an administrator.";
}
}
2 changes: 1 addition & 1 deletion src/Tests.Application/LsaUserRightsGetPrincipalsTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public sealed class LsaUserRightsGetPrincipalsTests : LsaUserRightsTestBase
[AdminOnlyFact]
public void GetPrincipalsShouldWork()
{
var expected = this.InitialState.Values
var expected = InitialState.Values
.SelectMany(p => p)
.Distinct()
.Order()
Expand Down
4 changes: 2 additions & 2 deletions src/Tests.Application/LsaUserRightsGrantPrivilegeTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public void GrantPrivilegeShouldWork()
{
var securityIdentifier = new SecurityIdentifier(Users);

if (this.InitialState.TryGetValue(SeMachineAccountPrivilege, out var initial))
if (InitialState.TryGetValue(SeMachineAccountPrivilege, out var initial))
{
Assert.DoesNotContain(securityIdentifier, initial);
}
Expand All @@ -35,7 +35,7 @@ public void GrantPrivilegeShouldWork()
policy.Connect();
policy.LsaAddAccountRights(securityIdentifier, SeMachineAccountPrivilege);

var current = this.GetCurrentState();
var current = GetCurrentState();

current.TryGetValue(SeMachineAccountPrivilege, out var collection);

Expand Down
4 changes: 2 additions & 2 deletions src/Tests.Application/LsaUserRightsRevokePrivilegeTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public void RevokePrivilegeShouldWork()
{
var securityIdentifier = new SecurityIdentifier(BackupOperators);

this.InitialState.TryGetValue(SeBackupPrivilege, out var initial);
InitialState.TryGetValue(SeBackupPrivilege, out var initial);

Assert.NotNull(initial);
Assert.Contains(securityIdentifier, initial);
Expand All @@ -35,7 +35,7 @@ public void RevokePrivilegeShouldWork()
policy.Connect();
policy.LsaRemoveAccountRights(securityIdentifier, SeBackupPrivilege);

var current = this.GetCurrentState();
var current = GetCurrentState();

if (current.TryGetValue(SeBackupPrivilege, out var collection))
{
Expand Down
59 changes: 23 additions & 36 deletions src/Tests.Application/LsaUserRightsTestBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,10 @@ public abstract class LsaUserRightsTestBase : IDisposable
private const string RestoreSecurityTemplateName = "restore.ini";
private const string RestoreSecurityLogName = "restore.log";

private readonly DirectoryInfo? directory = CreateTempDirectory();
private readonly IReadOnlyDictionary<string, IReadOnlyCollection<SecurityIdentifier>> initialState;
private readonly DirectoryInfo? _directory = CreateTempDirectory();
private readonly IReadOnlyDictionary<string, IReadOnlyCollection<SecurityIdentifier>> _initialState;

private bool disposed;
private bool _disposed;

/// <summary>
/// Initializes a new instance of the <see cref="LsaUserRightsTestBase"/> class.
Expand All @@ -39,17 +39,17 @@ protected LsaUserRightsTestBase()
try
{
// Create a backup to restore during disposal.
CreateSecurityDatabaseBackup(this.directory.FullName);
CreateSecurityDatabaseBackup(_directory.FullName);

// Load the contents of the backup for use as initial state.
this.initialState = ReadSecurityDatabaseBackup(this.directory.FullName);
_initialState = ReadSecurityDatabaseBackup(_directory.FullName);

// Create the updated configuration file to remove assignments for any privileges that were originally empty.
CreateRestoreTemplate(this.directory.FullName, this.initialState);
CreateRestoreTemplate(_directory.FullName, _initialState);
}
catch
{
this.directory = null;
_directory = null;

throw;
}
Expand All @@ -62,16 +62,16 @@ protected IReadOnlyDictionary<string, IReadOnlyCollection<SecurityIdentifier>> I
{
get
{
ObjectDisposedException.ThrowIf(this.disposed, this);
ObjectDisposedException.ThrowIf(_disposed, this);

return this.initialState;
return _initialState;
}
}

/// <inheritdoc />
public void Dispose()
{
this.Dispose(true);
Dispose(true);
GC.SuppressFinalize(this);
}

Expand All @@ -81,21 +81,21 @@ public void Dispose()
/// <param name="disposing">A value indicating whether the method call comes from a dispose method (its value is <see langword="true"/>) or from a finalizer (its value is <see langword="false"/>).</param>
protected virtual void Dispose(bool disposing)
{
if (this.disposed)
if (_disposed)
{
return;
}

if (disposing)
{
if (this.directory is not null)
if (_directory is not null)
{
RestoreSecurityDatabaseBackup(this.directory.FullName);
RestoreSecurityDatabaseBackup(_directory.FullName);

this.directory.Delete(true);
_directory.Delete(true);
}

this.disposed = true;
_disposed = true;
}
}

Expand All @@ -105,7 +105,7 @@ protected virtual void Dispose(bool disposing)
/// <returns>A map of privilege to security identifiers.</returns>
protected IReadOnlyDictionary<string, IReadOnlyCollection<SecurityIdentifier>> GetCurrentState()
{
ObjectDisposedException.ThrowIf(this.disposed, this);
ObjectDisposedException.ThrowIf(_disposed, this);

var directoryInfo = CreateTempDirectory();

Expand All @@ -125,11 +125,7 @@ protected IReadOnlyDictionary<string, IReadOnlyCollection<SecurityIdentifier>> G
/// <param name="stateBackup">The map of privilege to security identifiers for the backup configuration file.</param>
private static void CreateRestoreTemplate(string workingDirectory, IReadOnlyDictionary<string, IReadOnlyCollection<SecurityIdentifier>> stateBackup)
{
if (string.IsNullOrWhiteSpace(workingDirectory))
{
throw new ArgumentException("Value cannot be null or whitespace.", nameof(workingDirectory));
}

ArgumentException.ThrowIfNullOrWhiteSpace(workingDirectory);
ArgumentNullException.ThrowIfNull(stateBackup);

// Load existing assignments.
Expand Down Expand Up @@ -173,10 +169,7 @@ private static void CreateRestoreTemplate(string workingDirectory, IReadOnlyDict
/// <param name="workingDirectory">The path to a directory where the backup files will be created.</param>
private static void CreateSecurityDatabaseBackup(string workingDirectory)
{
if (string.IsNullOrWhiteSpace(workingDirectory))
{
throw new ArgumentException("Value cannot be null or whitespace.", nameof(workingDirectory));
}
ArgumentException.ThrowIfNullOrWhiteSpace(workingDirectory);

var arguments = string.Format(
CultureInfo.InvariantCulture,
Expand Down Expand Up @@ -239,12 +232,9 @@ private static DirectoryInfo CreateTempDirectory()
/// </summary>
/// <param name="workingDirectory">The path to a directory where the backup files exist.</param>
/// <returns>A map of privilege to security identifiers.</returns>
private static IReadOnlyDictionary<string, IReadOnlyCollection<SecurityIdentifier>> ReadSecurityDatabaseBackup(string workingDirectory)
private static ReadOnlyDictionary<string, IReadOnlyCollection<SecurityIdentifier>> ReadSecurityDatabaseBackup(string workingDirectory)
{
if (string.IsNullOrWhiteSpace(workingDirectory))
{
throw new ArgumentException("Value cannot be null or whitespace.", nameof(workingDirectory));
}
ArgumentException.ThrowIfNullOrWhiteSpace(workingDirectory);

var path = Path.Combine(workingDirectory, ExportSecurityTemplateName);

Expand All @@ -271,7 +261,7 @@ private static IReadOnlyDictionary<string, IReadOnlyCollection<SecurityIdentifie
foreach (var value in values)
{
var securityIdentifier = value.StartsWith('*')
? new SecurityIdentifier(value.TrimStart('*'))
? new(value.TrimStart('*'))
: value.ToSecurityIdentifier();

securityIdentifiers.Add(securityIdentifier);
Expand All @@ -280,7 +270,7 @@ private static IReadOnlyDictionary<string, IReadOnlyCollection<SecurityIdentifie
dictionary.Add(child.Key, securityIdentifiers.AsReadOnly());
}

return new ReadOnlyDictionary<string, IReadOnlyCollection<SecurityIdentifier>>(dictionary);
return new(dictionary);
}

/// <summary>
Expand All @@ -289,10 +279,7 @@ private static IReadOnlyDictionary<string, IReadOnlyCollection<SecurityIdentifie
/// <param name="workingDirectory">The path to a directory where the backup files exist.</param>
private static void RestoreSecurityDatabaseBackup(string workingDirectory)
{
if (string.IsNullOrWhiteSpace(workingDirectory))
{
throw new ArgumentException("Value cannot be null or whitespace.", nameof(workingDirectory));
}
ArgumentException.ThrowIfNullOrWhiteSpace(workingDirectory);

var arguments = string.Format(
CultureInfo.InvariantCulture,
Expand Down
20 changes: 6 additions & 14 deletions src/Tests.Application/Tests.Application.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -11,23 +11,15 @@

<ItemGroup>
<PackageReference Include="CsvHelper" Version="33.1.0" />
<PackageReference Include="Meziantou.Analyzer" Version="2.0.212">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.Extensions.Configuration" Version="9.0.8" />
<PackageReference Include="Microsoft.Extensions.Configuration.Ini" Version="9.0.8" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="9.0.8" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="9.0.8" />
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="9.0.8" />
<PackageReference Include="Microsoft.Extensions.Configuration" Version="9.0.9" />
<PackageReference Include="Microsoft.Extensions.Configuration.Ini" Version="9.0.9" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="9.0.9" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="9.0.9" />
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="9.0.9" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.14.1" />
<PackageReference Include="StyleCop.Analyzers.Unstable" Version="1.2.0.556">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="System.Linq.Async" Version="6.0.3" />
<PackageReference Include="xunit" Version="2.9.3" />
<PackageReference Include="xunit.runner.visualstudio" Version="3.1.3">
<PackageReference Include="xunit.runner.visualstudio" Version="3.1.4">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
Expand Down
8 changes: 4 additions & 4 deletions src/Tests.Application/UserRightsManagerListTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ public sealed class UserRightsManagerListTests : UserRightsManagerTestBase
[Fact]
public void InvalidArgumentsThrowsException()
{
var manager = this.ServiceProvider.GetRequiredService<IUserRightsManager>();
var manager = ServiceProvider.GetRequiredService<IUserRightsManager>();

Assert.ThrowsAny<ArgumentException>(() => manager.GetUserRights(null!));
}
Expand Down Expand Up @@ -74,7 +74,7 @@ public async Task SerializingToCsvShouldWork()
Assert.Equal([Privilege1, Privilege2], policy.LsaEnumerateAccountRights(PrincipalSid1));
Assert.Equal([Privilege1, Privilege2], policy.LsaEnumerateAccountRights(PrincipalSid2));

var manager = this.ServiceProvider.GetRequiredService<IUserRightsManager>();
var manager = ServiceProvider.GetRequiredService<IUserRightsManager>();
var userRights = manager.GetUserRights(policy).ToArray();

Assert.Equal(expected, userRights, new UserRightEntryEqualityComparer());
Expand Down Expand Up @@ -137,11 +137,11 @@ public async Task SerializingToJsonShouldWork()
var policy = new MockLsaUserRights(database);
policy.Connect("SystemName");

Assert.Equal(new[] { PrincipalSid1, PrincipalSid2 }, policy.LsaEnumerateAccountsWithUserRight().Order());
Assert.Equal([PrincipalSid1, PrincipalSid2], policy.LsaEnumerateAccountsWithUserRight().Order());
Assert.Equal(new[] { Privilege1, Privilege2 }, policy.LsaEnumerateAccountRights(PrincipalSid1));
Assert.Equal(new[] { Privilege1, Privilege2 }, policy.LsaEnumerateAccountRights(PrincipalSid2));

var manager = this.ServiceProvider.GetRequiredService<IUserRightsManager>();
var manager = ServiceProvider.GetRequiredService<IUserRightsManager>();
var userRights = manager.GetUserRights(policy).ToArray();

Assert.Equal(expected, userRights, new UserRightEntryEqualityComparer());
Expand Down
Loading
Loading