Allow New Admin Console to run as a WAR on Keycloak server. (#439)

* Allow app to run as a WAR on Keycloak server.

* New client creation json that works for both dev and prod

* fixed tests

* Try Mark's trick to get realm_test to run.

* Make tests use keycloakBefore()

* Fix duplicate import

* fix github actions

Co-authored-by: Erik Jan de Wit <erikjan.dewit@gmail.com>
This commit is contained in:
Stan Silvert 2021-03-18 08:48:14 -04:00 committed by GitHub
parent 21c0cfcdad
commit 398ca19ec1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
20 changed files with 130 additions and 63 deletions

View file

@ -30,7 +30,8 @@ jobs:
run: ./start.js & sleep 40
- name: Run Admin Console
run: npx http-server ./build -P http://localhost:8180/auth/ & sleep 30
run: mkdir ./build/adminv2 && mv ./build/js ./build/adminv2/
run: npx http-server ./build -P http://localhost:8180/ & sleep 30
- name: Admin Console client
run: ./import.js

View file

@ -3,6 +3,7 @@ import Masthead from "../support/pages/admin_console/Masthead";
import ListingPage from "../support/pages/admin_console/ListingPage";
import SidebarPage from "../support/pages/admin_console/SidebarPage";
import CreateClientScopePage from "../support/pages/admin_console/manage/client_scopes/CreateClientScopePage";
import { keycloakBefore } from "../support/util/keycloak_before";
let itemId = "client_scope_crud";
const loginPage = new LoginPage();
@ -12,10 +13,9 @@ const listingPage = new ListingPage();
const createClientScopePage = new CreateClientScopePage();
describe("Client Scopes test", function () {
describe("Client Scope creation", function () {
beforeEach(function () {
cy.visit("");
keycloakBefore();
loginPage.logIn();
sidebarPage.goToClientScopes();
});
@ -44,14 +44,14 @@ describe("Client Scopes test", function () {
createClientScopePage.fillClientScopeData(itemId).save();
masthead.checkNotificationMessage("Client scope created");
masthead.checkNotificationMessage("Client scope created");
sidebarPage.goToClientScopes();
// Delete
listingPage.itemExist(itemId).deleteItem(itemId); // There should be a confirmation pop-up
masthead.checkNotificationMessage("The client scope has been deleted");
masthead.checkNotificationMessage("The client scope has been deleted");
listingPage // It is not refreshing after delete
.itemExist(itemId, false);

View file

@ -7,6 +7,7 @@ import ModalUtils from "../support/util/ModalUtils";
import AdvancedTab from "../support/pages/admin_console/manage/clients/AdvancedTab";
import AdminClient from "../support/util/AdminClient";
import InitialAccessTokenTab from "../support/pages/admin_console/manage/clients/InitialAccessTokenTab";
import { keycloakBefore } from "../support/util/keycloak_before";
let itemId = "client_crud";
const loginPage = new LoginPage();
@ -19,7 +20,7 @@ const modalUtils = new ModalUtils();
describe("Clients test", function () {
describe("Client creation", function () {
beforeEach(function () {
cy.visit("");
keycloakBefore();
loginPage.logIn();
sidebarPage.goToClients();
});
@ -107,7 +108,7 @@ describe("Clients test", function () {
let client: string;
beforeEach(() => {
cy.visit("");
keycloakBefore();
loginPage.logIn();
sidebarPage.goToClients();

View file

@ -7,6 +7,7 @@ import SidebarPage from "../support/pages/admin_console/SidebarPage";
import LoginPage from "../support/pages/LoginPage";
import ViewHeaderPage from "../support/pages/ViewHeaderPage";
import AdminClient from "../support/util/AdminClient";
import { keycloakBefore } from "../support/util/keycloak_before";
describe("Group test", () => {
const loginPage = new LoginPage();
@ -20,7 +21,7 @@ describe("Group test", () => {
describe("Group creation", () => {
beforeEach(function () {
cy.visit("");
keycloakBefore();
loginPage.logIn();
sidebarPage.goToGroups();
});

View file

@ -1,5 +1,6 @@
import LoginPage from "../support/pages/LoginPage";
import Masthead from "../support/pages/admin_console/Masthead";
import { keycloakBefore } from "../support/util/keycloak_before";
const username = "admin";
const password = "admin";
@ -8,18 +9,14 @@ const loginPage = new LoginPage();
const masthead = new Masthead();
describe("Logging In", function () {
beforeEach(function () {
cy.visit("");
keycloakBefore();
});
it("displays errors on wrong credentials", function () {
loginPage
.logIn("wrong", "user{enter}");
loginPage
.checkErrorMessage("Invalid username or password.")
.isLogInPage();
loginPage.logIn("wrong", "user{enter}");
loginPage.checkErrorMessage("Invalid username or password.").isLogInPage();
});
it("logs in", function () {

View file

@ -2,6 +2,7 @@ import ListingPage from "../support/pages/admin_console/ListingPage";
import LoginPage from "../support/pages/LoginPage";
import SidebarPage from "../support/pages/admin_console/SidebarPage";
import Masthead from "../support/pages/admin_console/Masthead";
import { keycloakBefore } from "../support/util/keycloak_before";
const loginPage = new LoginPage();
const masthead = new Masthead();
@ -24,7 +25,7 @@ const goToAcctMgtTest = () => {
describe("Masthead tests in desktop mode", () => {
beforeEach(() => {
cy.visit("");
keycloakBefore();
loginPage.logIn();
});
@ -51,7 +52,7 @@ describe("Masthead tests in desktop mode", () => {
describe("Masthead tests with kebab menu", () => {
beforeEach(() => {
cy.visit("");
keycloakBefore();
loginPage.logIn();
masthead.setMobileMode(true);
});

View file

@ -5,6 +5,7 @@ import ListingPage from "../support/pages/admin_console/ListingPage";
import SidebarPage from "../support/pages/admin_console/SidebarPage";
import CreateRealmRolePage from "../support/pages/admin_console/manage/realm_roles/CreateRealmRolePage";
import AssociatedRolesPage from "../support/pages/admin_console/manage/realm_roles/AssociatedRolesPage";
import { keycloakBefore } from "../support/util/keycloak_before";
let itemId = "realm_role_crud";
const loginPage = new LoginPage();
@ -18,7 +19,7 @@ const associatedRolesPage = new AssociatedRolesPage();
describe("Realm roles test", function () {
describe("Realm roles creation", function () {
beforeEach(function () {
cy.visit("");
keycloakBefore();
loginPage.logIn();
sidebarPage.goToRealmRoles();
});

View file

@ -3,6 +3,7 @@ import SidebarPage from "../support/pages/admin_console/SidebarPage";
import CreateRealmPage from "../support/pages/admin_console/CreateRealmPage";
import Masthead from "../support/pages/admin_console/Masthead";
import AdminClient from "../support/util/AdminClient";
import { keycloakBefore } from "../support/util/keycloak_before";
const masthead = new Masthead();
const loginPage = new LoginPage();
@ -13,7 +14,7 @@ describe("Realms test", function () {
const testRealmName = "Test realm";
describe("Realm creation", function () {
beforeEach(function () {
cy.visit("");
keycloakBefore();
loginPage.logIn();
});

View file

@ -3,6 +3,7 @@ import SidebarPage from "../support/pages/admin_console/SidebarPage";
import ProviderPage from "../support/pages/admin_console/manage/providers/ProviderPage";
import Masthead from "../support/pages/admin_console/Masthead";
import ModalUtils from "../support/util/ModalUtils";
import { keycloakBefore } from "../support/util/keycloak_before";
const loginPage = new LoginPage();
const masthead = new Masthead();
@ -41,19 +42,10 @@ const disableModalTitle = "Disable user federation provider?";
describe("User Fed Kerberos tests", () => {
beforeEach(() => {
/*
Prevent unpredictable 401 errors from failing individual tests.
These are most often occurring during the login process:
GET /admin/serverinfo/
GET /admin/master/console/whoami
*/
cy.on("uncaught:exception", (err, runnable) => {
return false;
});
cy.visit("");
loginPage.logIn();
sidebarPage.goToUserFederation();
});
keycloakBefore();
loginPage.logIn();
sidebarPage.goToUserFederation();
});
it("Create Kerberos provider from empty state", () => {
// if tests don't start at empty state, e.g. user has providers configured locally,

View file

@ -3,6 +3,7 @@ import SidebarPage from "../support/pages/admin_console/SidebarPage";
import ProviderPage from "../support/pages/admin_console/manage/providers/ProviderPage";
import Masthead from "../support/pages/admin_console/Masthead";
import ModalUtils from "../support/util/ModalUtils";
import { keycloakBefore } from "../support/util/keycloak_before";
const loginPage = new LoginPage();
const masthead = new Masthead();
@ -58,16 +59,7 @@ const disableModalTitle = "Disable user federation provider?";
describe("User Fed LDAP tests", () => {
beforeEach(() => {
/*
Prevent unpredictable 401 errors from failing individual tests.
These are most often occurring during the login process:
GET /admin/serverinfo/
GET /admin/master/console/whoami
*/
cy.on("uncaught:exception", (err, runnable) => {
return false;
});
cy.visit("");
keycloakBefore();
loginPage.logIn();
sidebarPage.goToUserFederation();
});

View file

@ -5,6 +5,7 @@ import Masthead from "../support/pages/admin_console/Masthead";
import ListingPage from "../support/pages/admin_console/ListingPage";
import UserDetailsPage from "../support/pages/admin_console/manage/users/UserDetailsPage";
import ModalUtils from "../support/util/ModalUtils";
import { keycloakBefore } from "../support/util/keycloak_before";
describe("Users test", () => {
const loginPage = new LoginPage();
@ -19,16 +20,7 @@ describe("Users test", () => {
describe("User creation", () => {
beforeEach(() => {
/*
Prevent unpredictable 401 errors from failing individual tests.
These are most often occurring during the login process:
GET /admin/serverinfo/
GET /admin/master/console/whoami
*/
cy.on("uncaught:exception", () => {
return false;
});
cy.visit("");
keycloakBefore();
loginPage.logIn();
sidebarPage.goToUsers();
});

View file

@ -42,7 +42,7 @@ export default class ListingPage {
searchItem(searchValue: string, wait = true) {
if (wait) {
const searchUrl = `/admin/realms/master/*${searchValue}*`;
const searchUrl = `/auth/admin/realms/master/*${searchValue}*`;
cy.intercept(searchUrl).as("search");
}
cy.get(this.searchInput).type(searchValue);

View file

@ -0,0 +1,15 @@
export const keycloakBefore = () => {
/*
Prevent unpredictable 401 errors from failing individual tests.
These are most often occurring during the login process:
GET /admin/serverinfo/
GET /admin/master/console/whoami
*/
cy.on("uncaught:exception", (err, runnable) => {
console.log("-------------------");
console.log(err);
console.log("--------------------");
return false;
});
cy.visit("");
};

View file

@ -3,8 +3,8 @@
<head>
<meta charset="utf-8" />
<link id="favicon" rel="icon" href="/favicon.ico" />
<link rel="stylesheet" href="/index.css" />
<link id="favicon" rel="icon" href="./favicon.ico" />
<link rel="stylesheet" href="./index.css" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="description" content="Web site to manage keycloak" />
<title>Keycloak Administration Console</title>

View file

@ -0,0 +1,66 @@
{
"clientId": "security-admin-console-v2",
"rootUrl": "",
"adminUrl": "",
"baseUrl": "",
"surrogateAuthRequired": false,
"enabled": true,
"alwaysDisplayInConsole": false,
"clientAuthenticatorType": "client-secret",
"redirectUris": [
"/adminv2/*",
"http://localhost:8080/*"
],
"webOrigins": [
"*"
],
"notBefore": 0,
"bearerOnly": false,
"consentRequired": false,
"standardFlowEnabled": true,
"implicitFlowEnabled": false,
"directAccessGrantsEnabled": true,
"serviceAccountsEnabled": false,
"publicClient": true,
"frontchannelLogout": false,
"protocol": "openid-connect",
"attributes": {
"saml.assertion.signature": "false",
"saml.force.post.binding": "false",
"saml.multivalued.roles": "false",
"saml.encrypt": "false",
"backchannel.logout.revoke.offline.tokens": "false",
"saml.server.signature": "false",
"saml.server.signature.keyinfo.ext": "false",
"exclude.session.state.from.auth.response": "false",
"backchannel.logout.session.required": "true",
"client_credentials.use_refresh_token": "false",
"saml_force_name_id_format": "false",
"saml.client.signature": "false",
"tls.client.certificate.bound.access.tokens": "false",
"saml.authnstatement": "false",
"display.on.consent.screen": "false",
"saml.onetimeuse.condition": "false"
},
"authenticationFlowBindingOverrides": {},
"fullScopeAllowed": true,
"nodeReRegistrationTimeout": -1,
"defaultClientScopes": [
"web-origins",
"role_list",
"roles",
"profile",
"email"
],
"optionalClientScopes": [
"address",
"phone",
"offline_access",
"microprofile-jwt"
],
"access": {
"view": true,
"configure": true,
"manage": true
}
}

View file

@ -1,7 +1,11 @@
module.exports = {
extends: "@snowpack/app-scripts-react",
proxy: {
"/admin": "http://localhost:8180/auth/admin/",
"/auth/admin": "http://localhost:8180/auth/admin/",
},
plugins: ["@snowpack/plugin-postcss", "@snowpack/plugin-webpack"],
buildOptions: {
baseUrl: "/adminv2",
clean: true,
},
};

View file

@ -1,7 +1,7 @@
import React, { ReactNode, useEffect } from "react";
import { Page } from "@patternfly/react-core";
import {
BrowserRouter as Router,
HashRouter as Router,
Route,
Switch,
useParams,

View file

@ -129,7 +129,7 @@ export const Header = () => {
<UserDropdown />
</PageHeaderToolsItem>
</PageHeaderToolsGroup>
<Avatar src="/img_avatar.svg" alt="Avatar image" />
<Avatar src="./img_avatar.svg" alt="Avatar image" />
</PageHeaderTools>
);
};
@ -183,7 +183,7 @@ export const Header = () => {
logo={
<Link to="/">
<Brand
src="/logo.svg"
src="./logo.svg"
id="masthead-logo"
alt="Logo"
className="keycloak__pageheader_brand"

View file

@ -6,17 +6,20 @@ export default async function (): Promise<KcAdminClient> {
const kcAdminClient = new KcAdminClient();
const authContext = "/auth";
const keycloakAuthUrl = window.location.origin + authContext;
const devMode = !window.location.pathname.startsWith("/adminv2");
try {
await kcAdminClient.init(
{ onLoad: "check-sso", pkceMethod: "S256" },
{
url: "http://localhost:8180/auth/",
url: devMode ? "http://localhost:8180/auth" : keycloakAuthUrl,
realm: realm,
clientId: "security-admin-console-v2",
}
);
kcAdminClient.setConfig({ realmName: realm });
kcAdminClient.baseUrl = "";
kcAdminClient.baseUrl = authContext;
} catch (error) {
alert("failed to initialize keycloak");
}

View file

@ -39,7 +39,7 @@ const EmptyDashboard = () => {
<PageSection variant="light">
<EmptyState variant="large">
<Brand
src="/icon.svg"
src="./icon.svg"
alt="Keycloak icon"
className="keycloak__dashboard_icon"
/>