Skip to content

Commit a86193b

Browse files
committed
Add mock entra and fix tests
1 parent b346cae commit a86193b

File tree

7 files changed

+105
-4
lines changed

7 files changed

+105
-4
lines changed

.github/workflows/playwright.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,17 @@ on:
44
branches: [ main, master ]
55
pull_request:
66
branches: [ main, master ]
7+
workflow_dispatch:
78
jobs:
89
spa-test:
910
timeout-minutes: 60
1011
runs-on: ubuntu-latest
1112
steps:
1213
- uses: actions/checkout@v4
14+
- name: Install certutil (for https support)
15+
run: |
16+
sudo apt update
17+
sudo apt install libnss3-tools -y
1318
- uses: actions/setup-node@v4
1419
with:
1520
node-version: lts/*

MockOidcApp.AppHost/Program.cs

Lines changed: 89 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,101 @@
1+
using System.Text.Json;
2+
13
var builder = DistributedApplication.CreateBuilder(args);
24

35
var api = builder.AddProject<Projects.MockOidcApp_Api>("api")
46
.WithExternalHttpEndpoints();
57

6-
builder.AddNpmApp("vite", "../MockOidcApp.Vite", "dev")
8+
var vite = builder.AddNpmApp("vite", "../MockOidcApp.Vite", "dev")
79
.WithReference(api)
810
.WithEnvironment("BROWSER", "none")
911
.WithHttpEndpoint(env: "VITE_PORT", port: 5100)
1012
.WithExternalHttpEndpoints()
1113
.PublishAsDockerFile();
1214

15+
if (builder.ExecutionContext.IsPublishMode == false)
16+
{
17+
var clientId = Guid.NewGuid().ToString();
18+
var tenantId = Guid.NewGuid().ToString();
19+
var certPassword = Guid.NewGuid().ToString();
20+
var certExportExe = builder.AddExecutable("cert-export-exe", "dotnet", ".", "dev-certs", "https", "-ep", "./dev-certificates/aspnetapp.pfx", "-p", certPassword, "--trust", "--verbose");
21+
22+
var mockEntra = builder.AddContainer("mock-entra", "ghcr.io/soluto/oidc-server-mock")
23+
.WaitForCompletion(certExportExe)
24+
.WithEnvironment("ASPNETCORE_Kestrel__Certificates__Default__Password", certPassword)
25+
.WithEnvironment("ASPNETCORE_Kestrel__Certificates__Default__Path", "/https/aspnetapp.pfx")
26+
.WithBindMount("./dev-certificates", "/https")
27+
.WithEnvironment("ASPNETCORE_URLS", "https://+:443")
28+
.WithHttpsEndpoint(targetPort: 443);
29+
30+
mockEntra
31+
.WithEnvironment("ASPNET_SERVICES_OPTIONS_INLINE", System.Text.Json.JsonSerializer.Serialize(new { BasePath = $"/{tenantId}/v2.0" }))
32+
.WithEnvironment(
33+
"CLIENTS_CONFIGURATION_INLINE",
34+
() => System.Text.Json.JsonSerializer.Serialize(new[]
35+
{
36+
new
37+
{
38+
ClientId = clientId,
39+
ClientName = "Sample App",
40+
AllowedGrantTypes = new [] { "authorization_code" },
41+
RedirectUris = new [] { vite.GetEndpoint("http").Url },
42+
PostLogoutRedirectUris = new [] { vite.GetEndpoint("http").Url },
43+
AllowedScopes = new [] { "openid", "profile", $"api://{clientId}/access_as_user" },
44+
AllowOfflineAccess = true,
45+
RequireClientSecret = false,
46+
AlwaysSendClientClaims = true,
47+
Claims = new [] {
48+
new { Type = "aud", Value = $"api://{clientId}" },
49+
new { Type = "ver", Value = $"1.0" },
50+
},
51+
ClientClaimsPrefix = string.Empty,
52+
}
53+
}))
54+
.WithEnvironment("USERS_CONFIGURATION_INLINE", () => System.Text.Json.JsonSerializer.Serialize(new[]
55+
{
56+
new
57+
{
58+
SubjectId = "1",
59+
Username = "admin@test.com",
60+
Password = "Password123",
61+
Claims = new []
62+
{
63+
new { Type = "name", Value = "Frank Gardner" },
64+
new { Type = "scp", Value = "access_as_user"},
65+
}
66+
}
67+
}))
68+
.WithEnvironment(
69+
"SERVER_OPTIONS_INLINE",
70+
() => JsonSerializer.Serialize(new
71+
{
72+
Cors = new
73+
{
74+
CorsPaths = new[]
75+
{
76+
$"/{tenantId}/v2.0/.well-known/openid-configuration",
77+
$"/{tenantId}/v2.0/connect/token"
78+
}
79+
},
80+
}))
81+
.WithEnvironment(
82+
"API_SCOPES_INLINE",
83+
() => JsonSerializer.Serialize(new[]
84+
{
85+
new
86+
{
87+
Name = $"api://{clientId}/access_as_user",
88+
UserClaims = new[]
89+
{
90+
"scp"
91+
}
92+
}
93+
}));
94+
95+
api
96+
.WithEnvironment("AzureAd__Instance", mockEntra.GetEndpoint("https"))
97+
.WithEnvironment("AzureAd__ClientId", clientId)
98+
.WithEnvironment("AzureAd__TenantId", tenantId);
99+
}
100+
13101
builder.Build().Run();
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
*
2+
!.gitignore

MockOidcApp.SpaIntegrationTests/playwright.config.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ export default defineConfig({
3030

3131
/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
3232
trace: 'retain-on-failure',
33+
ignoreHTTPSErrors: true,
3334
},
3435

3536
/* Configure projects for major browsers */

MockOidcApp.SpaIntegrationTests/tests/homepage.spec.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,11 @@ describe('Homepage', () => {
1414
const button = await page.getByTestId("auth-button");
1515
await button.waitFor();
1616
await button.click();
17-
throw new Error("Not implemented - How can we login with Entra credentials when the login page could change at any time?");
17+
const loginButton = page.getByRole('button', { name: 'Login' });
18+
await loginButton.waitFor();
19+
await page.getByRole('textbox', { name: 'Username' }).fill("admin@test.com");
20+
await page.getByRole('textbox', { name: 'Password' }).fill("Password123");
21+
await loginButton.click();
1822

1923
await expect(page.getByTestId("auth-button")).toHaveText("Logout");
2024
await expect(page.getByTestId("welcome-message")).toHaveText("Hello Frank Gardner");

MockOidcApp.Vite/src/LoginButton.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,11 @@ function LoginButton() {
1212
})
1313
.catch((error) => console.log(error));
1414
};
15+
const account = instance.getActiveAccount();
1516
const handleLogout = () => {
16-
instance.logoutRedirect();
17+
instance.logoutRedirect({ idTokenHint: account?.idToken });
1718
};
1819

19-
const account = instance.getActiveAccount();
2020

2121
return (
2222
<>

MockOidcApp.Vite/src/authConfig.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import { Configuration } from '@azure/msal-browser';
1313
auth: {
1414
clientId: settings.auth.clientId,
1515
authority: settings.auth.authority,
16+
knownAuthorities: [settings.auth.authority],
1617
redirectUri: window.location.origin,
1718
postLogoutRedirectUri: '/',
1819
},

0 commit comments

Comments
 (0)