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

Integration of local IUserManager #327

Open
wants to merge 3 commits into
base: integration
Choose a base branch
from
Open
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
26 changes: 26 additions & 0 deletions docs/Extensions/UserManager/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Overview

The [IUserManager](../../../src/Microsoft.PowerApps.TestEngine/Users/IUserManager.cs) interface provides the ability for .Net assemblies to implement different authentication methods with test engine.

## Implementations

The following authentication MEF modules exist:

| Module | Name | Description |
|--------|------|-------------|
|test.user.environment.dll | environment | Read user name and password from environment variables
|test.user.browser.dll | browser | Login using the caches playwright browser context default profile. If the **BrowserContext** folder does not exist the user is prompted to interactively login |
|test.user.local.dll | local | Implements user manager that assumes that test resources are locally available to test engine and no web authentication is required |

## Import Process

Test Engine will search for .Net assemblies named **test.user.*.dll**. By default the user provider with the highest priority is selected. A user manager provider can be applied to a test engine execution.

> [!NOTE] In release mode only .Net Assemblies signed by trusted certificate providers in the Allow list will be imported.

## Roadmap

Other implementations that could be considered:

- [Certificate Based Authentication](https://learn.microsoft.com/entra/identity/authentication/concept-certificate-based-authentication) - Authenticate directly with X.509 certificates against their Microsoft Entra ID. Could be used to provide second factor identify provider depending on how the [Authentication binding policy](https://learn.microsoft.com/entra/identity/authentication/how-to-certificate-based-authentication) is configured.
- [Conditional Access Policy](https://learn.microsoft.com/entra/identity/conditional-access/concept-conditional-access-policies) Support various conditional access policies. For example browser agent.
14 changes: 14 additions & 0 deletions src/PowerAppsTestEngine.sln
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "testengine.module.pause", "
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "testengine.module.pause.tests", "testengine.module.pause.tests\testengine.module.pause.tests.csproj", "{3D9F90F2-0937-486D-AA0B-BFE425354F4A}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "testengine.user.local", "testengine.user.local\testengine.user.local.csproj", "{A8844B7E-2407-4B26-8AB1-D08D2023357D}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "testengine.user.local.tests", "testengine.user.local.tests\testengine.user.local.tests.csproj", "{E0737821-D25B-4F72-9C6B-168D5A307E87}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -100,6 +104,14 @@ Global
{3D9F90F2-0937-486D-AA0B-BFE425354F4A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3D9F90F2-0937-486D-AA0B-BFE425354F4A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3D9F90F2-0937-486D-AA0B-BFE425354F4A}.Release|Any CPU.Build.0 = Release|Any CPU
{A8844B7E-2407-4B26-8AB1-D08D2023357D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A8844B7E-2407-4B26-8AB1-D08D2023357D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A8844B7E-2407-4B26-8AB1-D08D2023357D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A8844B7E-2407-4B26-8AB1-D08D2023357D}.Release|Any CPU.Build.0 = Release|Any CPU
{E0737821-D25B-4F72-9C6B-168D5A307E87}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E0737821-D25B-4F72-9C6B-168D5A307E87}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E0737821-D25B-4F72-9C6B-168D5A307E87}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E0737821-D25B-4F72-9C6B-168D5A307E87}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand All @@ -117,6 +129,8 @@ Global
{8AEAF6BD-38E3-4649-9221-6A67AD1E96EC} = {0B61ADD8-5EED-4A2C-99AA-B597EC3EE223}
{B3A02421-223D-4E80-A8CE-977B425A6EB2} = {ACAB614B-304F-48C0-B8B1-8D95F3A9FBC4}
{3D9F90F2-0937-486D-AA0B-BFE425354F4A} = {ACAB614B-304F-48C0-B8B1-8D95F3A9FBC4}
{A8844B7E-2407-4B26-8AB1-D08D2023357D} = {0B61ADD8-5EED-4A2C-99AA-B597EC3EE223}
{E0737821-D25B-4F72-9C6B-168D5A307E87} = {0B61ADD8-5EED-4A2C-99AA-B597EC3EE223}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {7E7B2C01-DDE2-4C5A-96C3-AF474B074331}
Expand Down
67 changes: 67 additions & 0 deletions src/testengine.user.local.tests/LocalUserManagerModuleTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
using Microsoft.Playwright;
using Microsoft.PowerApps.TestEngine.Config;
using Microsoft.PowerApps.TestEngine.System;
using Microsoft.VisualStudio.TestPlatform.PlatformAbstractions.Interfaces;
using Moq;

namespace testengine.user.local.tests
{
public class LocalUserManagerModuleTests
{
[Fact]
public void NameIsLocal()
{
// Arrange


// Act
var module = new LocalUserManagerModule();

// Assert
Assert.Equal("local", module.Name);
}

[Fact]
public void EmptyLocation()
{
// Arrange


// Act
var module = new LocalUserManagerModule();

// Assert
Assert.Empty(module.Location);
}

[Fact]
public void DoesNotUseStaticContext()
{
// Arrange


// Act
var module = new LocalUserManagerModule();

// Assert
Assert.False(module.UseStaticContext);
}

[Fact]
public async Task LoginAsUserNoAction()
{
// Arrange
var module = new LocalUserManagerModule();
var mockBrowser = new Mock<IBrowserContext>(MockBehavior.Strict);
var mockState = new Mock<ITestState>(MockBehavior.Strict);
var mockInstaceState = new Mock<ISingleTestInstanceState>(MockBehavior.Strict);
var mockEnvironment = new Mock<IEnvironmentVariable>(MockBehavior.Strict);

// Act
await module.LoginAsUserAsync("https://www.microsoft.com", mockBrowser.Object, mockState.Object, mockInstaceState.Object, mockEnvironment.Object);

// Assert

}
}
}
1 change: 1 addition & 0 deletions src/testengine.user.local.tests/Usings.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
global using Xunit;
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>

<IsPackable>false</IsPackable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.1.0" />
<PackageReference Include="Moq" Version="4.20.70" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="coverlet.collector" Version="3.1.2">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\testengine.user.local\testengine.user.local.csproj" />
</ItemGroup>

</Project>
40 changes: 40 additions & 0 deletions src/testengine.user.local/LocalUserManagerModule.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

using System.ComponentModel.Composition;
using Microsoft.PowerApps.TestEngine.Config;
using Microsoft.PowerApps.TestEngine.System;
using Microsoft.Playwright;
using Microsoft.PowerApps.TestEngine.Users;

namespace testengine.user.local
{
/// <summary>
/// Implements IUserManager assuming that the components being tested are local to the test engine not authenticated via a web session
/// </summary>
[Export(typeof(IUserManager))]
public class LocalUserManagerModule : IUserManager
{
public string Name { get { return "local"; } }

public int Priority { get { return 50; } }

public bool UseStaticContext { get { return false; } }

public string Location { get; set; } = "";

private IBrowserContext? Context { get; set; }

public IPage? Page { get; set; }

public async Task LoginAsUserAsync(
string desiredUrl,
IBrowserContext context,
ITestState testState,
ISingleTestInstanceState singleTestInstanceState,
IEnvironmentVariable environmentVariable)
{
await Task.CompletedTask;
}
}
}
21 changes: 21 additions & 0 deletions src/testengine.user.local/testengine.user.local.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\Microsoft.PowerApps.TestEngine\Microsoft.PowerApps.TestEngine.csproj" />
</ItemGroup>

<ItemGroup>
<MySourceFiles Include="..\..\bin\$(configuration)\testengine.user.local\testengine.user.local.dll" />
</ItemGroup>

<Target Name="CopyFiles" AfterTargets="AfterBuild">
<Copy SourceFiles="@(MySourceFiles)" DestinationFolder="..\..\bin\$(configuration)\PowerAppsTestEngine" />
</Target>

</Project>
Loading