Skip to content

Commit

Permalink
chore: add oidc login tests
Browse files Browse the repository at this point in the history
Signed-off-by: Mason Hu <[email protected]>
  • Loading branch information
mas-who committed Jun 18, 2024
1 parent 4e6a3be commit 588eb53
Show file tree
Hide file tree
Showing 16 changed files with 192 additions and 49 deletions.
18 changes: 16 additions & 2 deletions .github/workflows/coverage.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -78,9 +78,23 @@ jobs:
- name: Install Playwright Browser
run: npx playwright install --with-deps chromium

- name: Create OIDC users
- name: Setup for tests
shell: bash
run: ./tests/scripts/create_oidc_identities
env:
LXD_OIDC_CLIENT_ID: ${{ secrets.LXD_OIDC_CLIENT_ID }}
LXD_OIDC_ISSUER: ${{ secrets.LXD_OIDC_ISSUER }}
LXD_OIDC_AUDIENCE: ${{ secrets.LXD_OIDC_AUDIENCE }}
LXD_OIDC_USER: ${{ secrets.LXD_OIDC_USER }}
LXD_OIDC_PASSWORD: ${{ secrets.LXD_OIDC_PASSWORD }}
LXD_OIDC_GROUPS_CLAIM: ${{ secrets.LXD_OIDC_GROUPS_CLAIM }}
run: |
echo "LXD_OIDC_CLIENT_ID=$LXD_OIDC_CLIENT_ID" >> .env.local
echo "LXD_OIDC_ISSUER=$LXD_OIDC_ISSUER" >> .env.local
echo "LXD_OIDC_AUDIENCE=$LXD_OIDC_AUDIENCE" >> .env.local
echo "LXD_OIDC_USER=$LXD_OIDC_USER" >> .env.local
echo "LXD_OIDC_PASSWORD=$LXD_OIDC_PASSWORD" >> .env.local
echo "LXD_OIDC_GROUPS_CLAIM=$LXD_OIDC_GROUPS_CLAIM" >> .env.local
./tests/scripts/setup_test
- name: Run tests with coverage
shell: bash
Expand Down
21 changes: 19 additions & 2 deletions .github/workflows/pr.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -149,10 +149,27 @@ jobs:
LXD_CHANNEL=$(echo '${{ matrix.lxd_channel }}' | sed 's#/#-#g')
echo "LXD_CHANNEL=$LXD_CHANNEL" >> $GITHUB_OUTPUT
- name: Create OIDC users
- name: Setup for tests
if: ${{ matrix.lxd_channel != '5.0/edge' }}
shell: bash
run: ./tests/scripts/create_oidc_identities
env:
LXD_OIDC_CLIENT_ID: ${{ secrets.LXD_OIDC_CLIENT_ID }}
LXD_OIDC_ISSUER: ${{ secrets.LXD_OIDC_ISSUER }}
LXD_OIDC_AUDIENCE: ${{ secrets.LXD_OIDC_AUDIENCE }}
LXD_OIDC_USER: ${{ secrets.LXD_OIDC_USER }}
LXD_OIDC_PASSWORD: ${{ secrets.LXD_OIDC_PASSWORD }}
LXD_OIDC_GROUPS_CLAIM: ${{ secrets.LXD_OIDC_GROUPS_CLAIM }}
run: |
echo "LXD_OIDC_CLIENT_ID=$LXD_OIDC_CLIENT_ID" >> .env.local
echo "LXD_OIDC_ISSUER=$LXD_OIDC_ISSUER" >> .env.local
echo "LXD_OIDC_AUDIENCE=$LXD_OIDC_AUDIENCE" >> .env.local
echo "LXD_OIDC_USER=$LXD_OIDC_USER" >> .env.local
echo "LXD_OIDC_PASSWORD=$LXD_OIDC_PASSWORD" >> .env.local
echo "LXD_OIDC_GROUPS_CLAIM=$LXD_OIDC_GROUPS_CLAIM" >> .env.local
./tests/scripts/setup_test
- name: show lxd configs
run: sudo lxc config show

- name: Run Playwright tests
run: npx playwright test --project ${{ matrix.browser }}:lxd-${{ steps.lxd-env.outputs.LXD_CHANNEL }}
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -83,3 +83,4 @@ dist/
tests/screenshots

haproxy-local.cfg
tests/.auth
12 changes: 12 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,18 @@ The e2e tests can be run against LXD 5.0, or the edge version of LXD. If you wan

snap refresh lxd --channel latest/edge

The tests are carried out for oidc authenticated identities and therefore will require oidc setup for your lxd server. You may refer to the [Setup oidc login wiki page](https://github.com/canonical/lxd-ui/wiki/Setup-oidc-login) for setup instructions. Once you have completed the oidc setup, create a `.env.local` file at the root level of the project and ensure the environment variables shown below are set against the relevant lxd server oidc config values:
# Configs that enables OIDC authentication for the lxd server
LXD_OIDC_CLIENT_ID=[oidc.client.id]
LXD_OIDC_ISSUER=[oidc.issuer]
LXD_OIDC_AUDIENCE=[oidc.audience]
# Config required for provisioning the OIDC identity with admin permission
LXD_OIDC_GROUPS_CLAIM=[oidc.groups.claim]

# user email and password from your identity provider for the identity that you intend to authenticate with
LXD_OIDC_USER=[login-user-email]
LXD_OIDC_PASSWORD=[login-user-password]

The tests expect the environment on localhost to be accessible. Execute `dotrun` first then run the tests against the latest LXD version with

yarn test-e2e-edge
Expand Down
2 changes: 1 addition & 1 deletion HACKING.md
Original file line number Diff line number Diff line change
@@ -1 +1 @@
moved to [contribution guidelines](CONTRIBUTING.md)
moved to [contribution guidelines](CONTRIBUTING.md)
6 changes: 4 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@
"start": "concurrently --kill-others --raw 'vite --host | grep -v 3000' 'yarn serve'",
"serve": "./entrypoint",
"test-js": "vitest --run",
"test-e2e-edge": "tests/scripts/create_oidc_identities && npx playwright test --project chromium:lxd-latest-edge firefox:lxd-latest-edge && tests/scripts/delete_oidc_identities",
"test-e2e-5.21-edge": "tests/scripts/create_oidc_identities && npx playwright test --project chromium:lxd-5.21-edge firefox:lxd-5.21-edge && tests/scripts/delete_oidc_identities",
"test-e2e-edge": "tests/scripts/setup_test && npx playwright test --project chromium:lxd-latest-edge firefox:lxd-latest-edge && tests/scripts/teardown_test",
"test-e2e-5.21-edge": "tests/scripts/setup_test && npx playwright test --project chromium:lxd-5.21-edge firefox:lxd-5.21-edge && tests/scripts/teardown_test",
"test-e2e-5.0-edge": "npx playwright test --project chromium:lxd-5.0-edge firefox:lxd-5.0-edge",
"test-coverage": "yarn test-js-coverage && yarn test-e2e-coverage && yarn test-report-coverage",
"test-js-coverage": "vitest --run --coverage",
Expand Down Expand Up @@ -62,6 +62,7 @@
"@playwright/test": "1.41.0",
"@types/convert-source-map": "2.0.3",
"@types/cytoscape-popper": "2.0.4",
"@types/dotenv": "8.2.0",
"@types/lodash.isequal": "^4.5.8",
"@types/node-forge": "1.3.11",
"@types/react": "18.2.48",
Expand All @@ -77,6 +78,7 @@
"babel-plugin-istanbul": "6.1.1",
"concurrently": "8.2.2",
"convert-source-map": "2.0.0",
"dotenv": "16.4.5",
"eslint": "8.56.0",
"eslint-config-prettier": "9.1.0",
"eslint-plugin-prettier": "5.1.3",
Expand Down
30 changes: 29 additions & 1 deletion playwright.config.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
import type { PlaywrightTestConfig } from "@playwright/test";
import { devices } from "@playwright/test";
import { TestOptions } from "./tests/fixtures/lxd-test";
import { TestOptions, authFile } from "./tests/fixtures/lxd-test";
import dotenv from "dotenv";
import path from "path";
import { fileURLToPath } from "url";
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
// provide environment variables from .env.local to all tests
dotenv.config({ path: path.resolve(__dirname, ".env.local") });

/**
* See https://playwright.dev/docs/test-configuration.
Expand Down Expand Up @@ -42,6 +49,17 @@ const config: PlaywrightTestConfig<TestOptions> = {

/* Configure projects for major browsers */
projects: [
// Setup project
{
name: "setup-chromium",
use: { ...devices["Desktop Chrome"] },
testMatch: /.*\.setup\.ts/,
},
{
name: "setup-firefox",
use: { ...devices["Desktop Firefox"] },
testMatch: /.*\.setup\.ts/,
},
{
name: "chromium:lxd-5.0-edge",
use: {
Expand All @@ -61,36 +79,46 @@ const config: PlaywrightTestConfig<TestOptions> = {
use: {
...devices["Desktop Chrome"],
lxdVersion: "5.21-edge",
storageState: authFile,
},
dependencies: ["setup-chromium"],
},
{
name: "firefox:lxd-5.21-edge",
use: {
...devices["Desktop Firefox"],
lxdVersion: "5.21-edge",
storageState: authFile,
},
dependencies: ["setup-firefox"],
},
{
name: "chromium:lxd-latest-edge",
use: {
...devices["Desktop Chrome"],
lxdVersion: "latest-edge",
storageState: authFile,
},
dependencies: ["setup-chromium"],
},
{
name: "firefox:lxd-latest-edge",
use: {
...devices["Desktop Firefox"],
lxdVersion: "latest-edge",
storageState: authFile,
},
dependencies: ["setup-firefox"],
},
{
name: "coverage",
use: {
...devices["Desktop Chrome"],
lxdVersion: "latest-edge",
storageState: authFile,
hasCoverage: true,
},
dependencies: ["setup-chromium"],
},
],
};
Expand Down
2 changes: 2 additions & 0 deletions tests/fixtures/lxd-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,5 @@ export const test = base.extend<TestOptions>({
});

export const expect = test.expect;

export const authFile = "tests/.auth/user.json";
2 changes: 1 addition & 1 deletion tests/helpers/permission-identities.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Page } from "@playwright/test";
import { expect } from "../fixtures/lxd-test";

// These identities are created by the create_oidc_identities script in tests/scripts
// These identities are created by the setup_test script in tests/scripts
export const identityBar = "[email protected]";
export const identityFoo = "[email protected]";

Expand Down
4 changes: 4 additions & 0 deletions tests/images.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ import { deleteInstance, randomInstanceName } from "./helpers/instances";
test("search for custom image and create an instance from it", async ({
page,
}) => {
test.skip(
Boolean(!process.env.CI),
"Skipping test locally for custom image creation",
);
const customInstance = randomInstanceName();
const image = "my-custom-image"; // this is created in pr.yaml and coverage.yaml

Expand Down
32 changes: 0 additions & 32 deletions tests/scripts/create_oidc_identities

This file was deleted.

8 changes: 0 additions & 8 deletions tests/scripts/delete_oidc_identities

This file was deleted.

53 changes: 53 additions & 0 deletions tests/scripts/setup_test
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
#! /usr/bin/env bash
set -e

# remove tls cert for oidc login
FINGERPRINT=$(lxc config trust list | grep lxd-ui.crt | awk '{print $8}')
lxc config trust remove ${FINGERPRINT}

# setup oidc configs
if [ -f .env.local ]
then
set -o allexport; source .env.local; set +o allexport
fi
lxc config set oidc.issuer=${LXD_OIDC_ISSUER}
lxc config set oidc.client.id=${LXD_OIDC_CLIENT_ID}
lxc config set oidc.audience=${LXD_OIDC_AUDIENCE}
lxc config set oidc.groups.claim=${LXD_OIDC_GROUPS_CLAIM}

# create identity provider group mapping
lxc auth group create login-admin
lxc auth group permission add login-admin server admin
# The name of the identity provider group should be the same as the role name assigned to the user
lxc auth identity-provider-group create admin
lxc auth identity-provider-group group add admin login-admin

# create oidc user foo
lxd sql global "
INSERT OR REPLACE INTO identities
(id, auth_method, type, identifier, name, metadata)
VALUES
(
(SELECT id from identities WHERE name='foo'),
2,
5,
'[email protected]',
'foo',
'{}'
);
"

# create oidc user bar
lxd sql global "
INSERT OR REPLACE INTO identities
(id, auth_method, type, identifier, name, metadata)
VALUES
(
(SELECT id from identities WHERE name='bar'),
2,
5,
'[email protected]',
'bar',
'{}'
);
"
13 changes: 13 additions & 0 deletions tests/scripts/teardown_test
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#! /usr/bin/env bash
set -e

lxd sql global "
DELETE
FROM identities
WHERE name IN ('foo', 'bar', 'admin');
"
lxc auth identity-provider-group delete admin
lxc auth group delete login-admin

# add tls cert back
lxc config trust add keys/lxd-ui.crt
25 changes: 25 additions & 0 deletions tests/setup/auth.setup.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { Page } from "@playwright/test";
import { test as setup, expect, authFile } from "../fixtures/lxd-test";

const loginUser = async (page: Page) => {
await page.getByRole("link", { name: "Login with SSO" }).click();
await page.getByLabel("Email address*").click();
await page.getByLabel("Email address*").fill(process.env.LXD_OIDC_USER || "");
await page.getByLabel("Password*").click();
await page.getByLabel("Password*").fill(process.env.LXD_OIDC_PASSWORD || "");
await page.getByRole("button", { name: "Continue", exact: true }).click();
await expect(page.getByText("Log out")).toBeVisible();
};

setup("authenticate", async ({ page }) => {
await page.goto("/ui/");
await loginUser(page);
// Check logout functionality
await page.getByText("Log out").click();
await expect(
page.getByRole("link", { name: "Login with SSO" }),
).toBeVisible();
await loginUser(page);

await page.context().storageState({ path: authFile });
});
12 changes: 12 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1623,6 +1623,13 @@
resolved "https://registry.yarnpkg.com/@types/cytoscape/-/cytoscape-3.21.0.tgz#30f5634774862b9a507b89a1b10616efabf1bf88"
integrity sha512-RN5SPiyVDpUP+LoOlxxlOYAMzkE7iuv3gA1jt3Hx2qTwArpZVPPdO+SI0hUj49OAn4QABR7JK9Gi0hibzGE0Aw==

"@types/[email protected]":
version "8.2.0"
resolved "https://registry.yarnpkg.com/@types/dotenv/-/dotenv-8.2.0.tgz#5cd64710c3c98e82d9d15844375a33bf1b45d053"
integrity sha512-ylSC9GhfRH7m1EUXBXofhgx4lUWmFeQDINW5oLuS+gxWdfUeW4zJdeVTYVkexEW+e2VUvlZR2kGnGGipAWR7kw==
dependencies:
dotenv "*"

"@types/[email protected]", "@types/estree@^1.0.0":
version "1.0.5"
resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.5.tgz#a6ce3e556e00fd9895dd872dd172ad0d4bd687f4"
Expand Down Expand Up @@ -2905,6 +2912,11 @@ domexception@^4.0.0:
dependencies:
webidl-conversions "^7.0.0"

dotenv@*, [email protected]:
version "16.4.5"
resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.4.5.tgz#cdd3b3b604cb327e286b4762e13502f717cb099f"
integrity sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==

eastasianwidth@^0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/eastasianwidth/-/eastasianwidth-0.2.0.tgz#696ce2ec0aa0e6ea93a397ffcf24aa7840c827cb"
Expand Down

0 comments on commit 588eb53

Please sign in to comment.