Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add tests for configure mixed elevation #4487

Merged
merged 14 commits into from
Jun 14, 2024
Next Next commit
save work
  • Loading branch information
ryfu-msft committed May 15, 2024
commit ca423d643d89e74110dd01b4e8738ed94c653f61
34 changes: 32 additions & 2 deletions src/AppInstallerCLICore/ConfigurationDynamicRuntimeFactory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,27 @@ namespace AppInstaller::CLI::ConfigurationRemoting
{
namespace anonymous
{
#ifndef DISABLE_TEST_HOOKS
constexpr std::wstring_view DisableRunAsGuid = L"1e62d683-2999-44e7-81f7-6f8f35e8d731";
constexpr std::wstring_view DisableSerialization = L"02f64b7d-6c2e-43fa-87dd-1f265800681d";

// Checks for a specific guid to control the behavior of a specific flow.
bool GetBehaviorForTestGuid(ConfigurationSet configurationSet, const std::wstring_view& testGuid)
{
auto disableRunAsBehavior = configurationSet.Metadata().TryLookup(testGuid);
if (disableRunAsBehavior)
{
auto disableRunAsProperty = disableRunAsBehavior.try_as<IPropertyValue>();
if (disableRunAsProperty && disableRunAsProperty.Type() == PropertyType::Boolean)
{
return disableRunAsProperty.GetBoolean();
}
}

return false;
}
#endif

struct DynamicProcessorInfo
{
IConfigurationSetProcessorFactory Factory;
Expand Down Expand Up @@ -138,7 +159,7 @@ namespace AppInstaller::CLI::ConfigurationRemoting
std::vector<ConfigurationUnit> highIntegrityUnits;
auto units = m_configurationSet.Units();

for (auto unit : units)
for (auto unit : units)
{
if (unit.IsActive() && GetIntegrityLevelForUnit(unit) == Security::IntegrityLevel::High)
{
Expand Down Expand Up @@ -172,7 +193,16 @@ namespace AppInstaller::CLI::ConfigurationRemoting
// If we got here, the only option is that the current integrity level is not High.
if (integrityLevel == Security::IntegrityLevel::High)
{
factory = CreateOutOfProcessFactory(true, SerializeSetProperties(), SerializeHighIntegrityLevelSet());
bool useRunAs = true;

#ifndef DISABLE_TEST_HOOKS
if (GetBehaviorForTestGuid(m_configurationSet, DisableRunAsGuid))
{
useRunAs = false;
}
#endif

factory = CreateOutOfProcessFactory(useRunAs, SerializeSetProperties(), SerializeHighIntegrityLevelSet());
}
else
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -190,9 +190,16 @@ namespace AppInstaller::CLI::ConfigurationRemoting
execInfo.lpParameters = arguments.c_str();
execInfo.nShow = SW_HIDE;

if (useRunAs)
if (useRunAs &&
#ifndef DISABLE_TEST_HOOKS // Always set to false so that userunAs is never included for unit tests.
true
#elif
true
#endif
)
{
execInfo.lpVerb = L"runas";
AICLI_LOG(Config, Verbose, << "Process set with runas verb.");
}

THROW_LAST_ERROR_IF(!ShellExecuteExW(&execInfo) || !execInfo.hProcess);
Expand Down
3 changes: 1 addition & 2 deletions src/AppInstallerCLICore/Workflows/ConfigurationFlow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -91,8 +91,7 @@ namespace AppInstaller::CLI::Workflow
IConfigurationSetProcessorFactory factory;

// Since downgrading is not currently supported, only use dynamic if not running as admin.
if (Settings::ExperimentalFeature::IsEnabled(Settings::ExperimentalFeature::Feature::ConfigureSelfElevation) &&
!Runtime::IsRunningAsAdmin())
if (Settings::ExperimentalFeature::IsEnabled(Settings::ExperimentalFeature::Feature::ConfigureSelfElevation) && !Runtime::IsRunningAsAdmin())
{
factory = ConfigurationRemoting::CreateDynamicRuntimeFactory();
// TODO: Implement SetProcessorFactory::IPwshConfigurationSetProcessorFactoryProperties on dynamic factory
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,7 @@ namespace Microsoft.Management.Configuration.Processor
{
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Management.Automation;
using System.Runtime.CompilerServices;
using System.Text;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
// -----------------------------------------------------------------------------
// <copyright file="ConfigurationMixedElevationTests.cs" company="Microsoft Corporation">
// Copyright (c) Microsoft Corporation. Licensed under the MIT License.
// </copyright>
// -----------------------------------------------------------------------------

namespace Microsoft.Management.Configuration.UnitTests.Tests
{
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
using Microsoft.Management.Configuration.Processor.Set;
using Microsoft.Management.Configuration.UnitTests.Fixtures;
using Microsoft.Management.Configuration.UnitTests.Helpers;
using Microsoft.VisualBasic;
using Xunit;
using Xunit.Abstractions;

/// <summary>
/// Unit tests for verifying the processor behavior for handling mixed elevation scenarios.
/// </summary>
[Collection("UnitTestCollection")]
[OutOfProc]
public class ConfigurationMixedElevationTests : ConfigurationProcessorTestBase
{
private readonly UnitTestFixture fixture;
private readonly ITestOutputHelper log;

/// <summary>
/// Initializes a new instance of the <see cref="ConfigurationMixedElevationTests"/> class.
/// </summary>
/// <param name="fixture">Unit test fixture.</param>
/// <param name="log">Log helper.</param>
public ConfigurationMixedElevationTests(UnitTestFixture fixture, ITestOutputHelper log)
: base(fixture, log)
{
this.fixture = fixture;
this.log = log;
}

/// <summary>
/// Verifies that a set of units with mixed elevation can run successfully.
/// </summary>
/// <returns>A <see cref="Task"/> representing the asynchronous unit test.</returns>
[Fact]
public async Task ApplyUnitsWithMixedElevation()
{
string resourceName = "E2ETestResource";
string moduleName = "xE2ETestResource";
Version version = new Version("0.0.0.1");

ConfigurationSet configurationSet = this.ConfigurationSet();

ConfigurationUnit configurationUnit1 = this.ConfigurationUnit();
configurationUnit1.Metadata.Add("securityContext", "elevated");
configurationUnit1.Metadata.Add("version", version.ToString());
configurationUnit1.Metadata.Add("module", moduleName);
configurationUnit1.Metadata.Add("secretCode", "123456789");
configurationUnit1.Type = resourceName;
configurationUnit1.Intent = ConfigurationUnitIntent.Apply;

ConfigurationUnit configurationUnit2 = this.ConfigurationUnit();
configurationUnit2.Metadata.Add("version", version.ToString());
configurationUnit2.Metadata.Add("module", moduleName);
configurationUnit2.Metadata.Add("secretCode", "123456789");
configurationUnit2.Type = resourceName;
configurationUnit2.Intent = ConfigurationUnitIntent.Apply;

configurationSet.Units = new ConfigurationUnit[] { configurationUnit1, configurationUnit2 };

IConfigurationSetProcessorFactory dynamicFactory = await this.fixture.ConfigurationStatics.CreateConfigurationSetProcessorFactoryAsync("{73fea39f-6f4a-41c9-ba94-6fd14d633e40}");

ConfigurationProcessor processor = this.CreateConfigurationProcessorWithDiagnostics(dynamicFactory);

TestConfigurationSetResult result = processor.TestSet(configurationSet);
Assert.NotNull(result);
Assert.Equal(1, result.UnitResults.Count);

ApplyConfigurationSetResult applyResult = processor.ApplySet(configurationSet, ApplyConfigurationSetFlags.None);
Assert.NotNull(applyResult);
}

/// <summary>
/// Verifies that a unit not in the limitation set will fail.
/// </summary>
/// <returns>A <see cref="Task"/> representing the asynchronous unit test.</returns>
[Fact]
public async Task ApplyUnitNotInLimitationSet()
{
string resourceName = "E2ETestResource";
string moduleName = "xE2ETestResource";
Version version = new Version("0.0.0.1");

ConfigurationSet configurationSet = this.ConfigurationSet();

ConfigurationUnit configurationUnit1 = this.ConfigurationUnit();
configurationUnit1.Metadata.Add("securityContext", "elevated");
configurationUnit1.Metadata.Add("version", version.ToString());
configurationUnit1.Metadata.Add("module", moduleName);
configurationUnit1.Metadata.Add("secretCode", "123456789");
configurationUnit1.Type = resourceName;
configurationUnit1.Intent = ConfigurationUnitIntent.Apply;

ConfigurationUnit configurationUnit2 = this.ConfigurationUnit();
configurationUnit2.Metadata.Add("version", version.ToString());
configurationUnit2.Metadata.Add("module", moduleName);
configurationUnit2.Metadata.Add("secretCode", "123456789");
configurationUnit2.Type = resourceName;
configurationUnit2.Intent = ConfigurationUnitIntent.Apply;

configurationSet.Units = new ConfigurationUnit[] { configurationUnit1, configurationUnit2 };

IConfigurationSetProcessorFactory dynamicFactory = await this.fixture.ConfigurationStatics.CreateConfigurationSetProcessorFactoryAsync("{73fea39f-6f4a-41c9-ba94-6fd14d633e40}");

ConfigurationProcessor processor = this.CreateConfigurationProcessorWithDiagnostics(dynamicFactory);

TestConfigurationSetResult result = processor.TestSet(configurationSet);
Assert.NotNull(result);
Assert.Equal(1, result.UnitResults.Count);

ApplyConfigurationSetResult applyResult = processor.ApplySet(configurationSet, ApplyConfigurationSetFlags.None);
Assert.NotNull(applyResult);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ namespace Microsoft.Management.Configuration.UnitTests.Tests
using Microsoft.Management.Configuration.Processor;
using Microsoft.Management.Configuration.Processor.Set;
using Microsoft.Management.Configuration.UnitTests.Fixtures;
using Moq;
using WinRT;
using Xunit;
using Xunit.Abstractions;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
// <copyright file="ConfigurationProcessorGetTests.cs" company="Microsoft Corporation">
// Copyright (c) Microsoft Corporation. Licensed under the MIT License.
// </copyright>
// -----------------------------------------------------------------------------

namespace Microsoft.Management.Configuration.UnitTests.Tests
{
using System.Collections.Generic;
using System.IO;
using Microsoft.Management.Configuration.UnitTests.Fixtures;
using Microsoft.Management.Configuration.UnitTests.Helpers;
Expand Down
3 changes: 2 additions & 1 deletion src/nuget.config
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<packageSources>
<clear />
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" />
<add key="AppInstallerCLIE2ETestsRepo" value="file:///C:/Users/ryfu/AppData/Local/Temp/efe9569e-e036-47b3-b4b7-31444da84fe1" />
</packageSources>
<disabledPackageSources>
<clear />
Expand Down