Parse environment information as JSON (#851)
* Parse environment information as JSON * Pass 'isRunningAsTheme' from injected environment * Update comment to use index.ftl instead of html Co-authored-by: Stan Silvert <ssilvert@redhat.com> * Update realm param comment * Update version param * add more sensible defaults Co-authored-by: Stan Silvert <ssilvert@redhat.com>
This commit is contained in:
parent
d67b37e48e
commit
8236528a07
9 changed files with 100 additions and 62 deletions
|
@ -68,18 +68,23 @@
|
|||
<value>href="${resourceUrl}/</value>
|
||||
</replacement>
|
||||
<replacement>
|
||||
<token><head></token>
|
||||
<value>
|
||||
<head>
|
||||
<script type="text/javascript">
|
||||
var loginRealm = "${loginRealm}";
|
||||
var authServerUrl = "${authServerUrl}";
|
||||
var authUrl = "${authUrl}";
|
||||
var consoleBaseUrl = "${consoleBaseUrl}";
|
||||
var resourceUrl = "${resourceUrl}";
|
||||
var masterRealm = "${masterRealm}";
|
||||
var resourceVersion = "${resourceVersion}";
|
||||
</script>
|
||||
<token><![CDATA[</body>]]></token>
|
||||
<value xml:space="preserve">
|
||||
<![CDATA[
|
||||
<script id="environment" type="application/json">
|
||||
{
|
||||
"loginRealm": "${loginRealm}",
|
||||
"authServerUrl": "${authServerUrl}",
|
||||
"authUrl": "${authUrl}",
|
||||
"consoleBaseUrl": "${consoleBaseUrl}",
|
||||
"resourceUrl": "${resourceUrl}",
|
||||
"masterRealm": "${masterRealm}",
|
||||
"resourceVersion": "${resourceVersion}",
|
||||
"isRunningAsTheme": true
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
]]>
|
||||
</value>
|
||||
</replacement>
|
||||
</replacements>
|
||||
|
|
|
@ -18,7 +18,7 @@ import { WhoAmIContext } from "./context/whoami/WhoAmI";
|
|||
import { HelpContext, HelpHeader } from "./components/help-enabler/HelpHeader";
|
||||
import { Link, useHistory } from "react-router-dom";
|
||||
import { useAdminClient } from "./context/auth/AdminClient";
|
||||
import { resourceUri } from "./util";
|
||||
import environment from "./environment";
|
||||
|
||||
export const Header = () => {
|
||||
const adminClient = useAdminClient();
|
||||
|
@ -127,7 +127,10 @@ export const Header = () => {
|
|||
<UserDropdown />
|
||||
</PageHeaderToolsItem>
|
||||
</PageHeaderToolsGroup>
|
||||
<Avatar src={resourceUri + "/img_avatar.svg"} alt="Avatar image" />
|
||||
<Avatar
|
||||
src={environment.resourceUrl + "/img_avatar.svg"}
|
||||
alt="Avatar image"
|
||||
/>
|
||||
</PageHeaderTools>
|
||||
);
|
||||
};
|
||||
|
@ -181,7 +184,7 @@ export const Header = () => {
|
|||
logo={
|
||||
<Link to="/">
|
||||
<Brand
|
||||
src={resourceUri + "/logo.svg"}
|
||||
src={environment.resourceUrl + "/logo.svg"}
|
||||
id="masthead-logo"
|
||||
alt="Logo"
|
||||
className="keycloak__pageheader_brand"
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import KcAdminClient from "keycloak-admin";
|
||||
import { homeRealm, isDevMode, authUri } from "../../util";
|
||||
import environment from "../../environment";
|
||||
|
||||
export default async function (): Promise<KcAdminClient> {
|
||||
const kcAdminClient = new KcAdminClient();
|
||||
|
@ -7,16 +7,16 @@ export default async function (): Promise<KcAdminClient> {
|
|||
await kcAdminClient.init(
|
||||
{ onLoad: "check-sso", pkceMethod: "S256" },
|
||||
{
|
||||
url: authUri(),
|
||||
realm: homeRealm(),
|
||||
clientId: isDevMode
|
||||
? "security-admin-console-v2"
|
||||
: "security-admin-console",
|
||||
url: environment.authUrl,
|
||||
realm: environment.loginRealm,
|
||||
clientId: environment.isRunningAsTheme
|
||||
? "security-admin-console"
|
||||
: "security-admin-console-v2",
|
||||
}
|
||||
);
|
||||
kcAdminClient.setConfig({ realmName: homeRealm() });
|
||||
kcAdminClient.setConfig({ realmName: environment.loginRealm });
|
||||
|
||||
kcAdminClient.baseUrl = authUri();
|
||||
kcAdminClient.baseUrl = environment.authUrl;
|
||||
} catch (error) {
|
||||
alert("failed to initialize keycloak");
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ import _ from "lodash";
|
|||
import type RealmRepresentation from "keycloak-admin/lib/defs/realmRepresentation";
|
||||
import { RecentUsed } from "../../components/realm-selector/recent-used";
|
||||
import { useAdminClient, useFetch } from "../auth/AdminClient";
|
||||
import { WhoAmIContext } from "../whoami/WhoAmI";
|
||||
import environment from "../../environment";
|
||||
|
||||
type RealmContextType = {
|
||||
realm: string;
|
||||
|
@ -25,8 +25,7 @@ type RealmContextProviderProps = { children: React.ReactNode };
|
|||
export const RealmContextProvider = ({
|
||||
children,
|
||||
}: RealmContextProviderProps) => {
|
||||
const { whoAmI } = useContext(WhoAmIContext);
|
||||
const [realm, setRealm] = useState(whoAmI.getHomeRealm());
|
||||
const [realm, setRealm] = useState(environment.loginRealm);
|
||||
const [realms, setRealms] = useState<RealmRepresentation[]>([]);
|
||||
const adminClient = useAdminClient();
|
||||
const recentUsed = new RecentUsed();
|
||||
|
|
|
@ -4,7 +4,6 @@ import i18n from "../../i18n";
|
|||
import type WhoAmIRepresentation from "keycloak-admin/lib/defs/whoAmIRepresentation";
|
||||
import type { AccessType } from "keycloak-admin/lib/defs/whoAmIRepresentation";
|
||||
import { useAdminClient, useFetch } from "../auth/AdminClient";
|
||||
import { homeRealm } from "../../util";
|
||||
|
||||
export class WhoAmI {
|
||||
constructor(private me?: WhoAmIRepresentation) {
|
||||
|
@ -27,13 +26,6 @@ export class WhoAmI {
|
|||
return this.me.userId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the realm I am signed in to.
|
||||
*/
|
||||
public getHomeRealm(): string {
|
||||
return homeRealm();
|
||||
}
|
||||
|
||||
public canCreateRealm(): boolean {
|
||||
return this.me !== undefined && this.me.createRealm;
|
||||
}
|
||||
|
|
|
@ -7,11 +7,6 @@ test("returns display name", () => {
|
|||
expect(whoami.getDisplayName()).toEqual("Stan Silvert");
|
||||
});
|
||||
|
||||
test("returns correct home realm in dev mode", () => {
|
||||
const whoami = new WhoAmI(whoamiMock as WhoAmIRepresentation);
|
||||
expect(whoami.getHomeRealm()).toEqual("master");
|
||||
});
|
||||
|
||||
test("can not create realm", () => {
|
||||
const whoami = new WhoAmI(whoamiMock as WhoAmIRepresentation);
|
||||
expect(whoami.canCreateRealm()).toEqual(false);
|
||||
|
|
|
@ -28,8 +28,9 @@ import { useRealm } from "../context/realm-context/RealmContext";
|
|||
import { useServerInfo } from "../context/server-info/ServerInfoProvider";
|
||||
|
||||
import "./dashboard.css";
|
||||
import { toUpperCase, resourceUri } from "../util";
|
||||
import { toUpperCase } from "../util";
|
||||
import { HelpItem } from "../components/help-enabler/HelpItem";
|
||||
import environment from "../environment";
|
||||
|
||||
const EmptyDashboard = () => {
|
||||
const { t } = useTranslation("dashboard");
|
||||
|
@ -38,7 +39,7 @@ const EmptyDashboard = () => {
|
|||
<PageSection variant="light">
|
||||
<EmptyState variant="large">
|
||||
<Brand
|
||||
src={resourceUri + "/icon.svg"}
|
||||
src={environment.resourceUrl + "/icon.svg"}
|
||||
alt="Keycloak icon"
|
||||
className="keycloak__dashboard_icon"
|
||||
/>
|
||||
|
|
64
src/environment.ts
Normal file
64
src/environment.ts
Normal file
|
@ -0,0 +1,64 @@
|
|||
export type Environment = {
|
||||
/** The realm which should be used when signing into the application. */
|
||||
loginRealm: string;
|
||||
/** The URL to the root of the auth server. */
|
||||
authServerUrl: string;
|
||||
/** The URL to the path of the auth server where client requests can be sent. */
|
||||
authUrl: string;
|
||||
/** The URL to the base of the admin console. */
|
||||
consoleBaseUrl: string;
|
||||
resourceUrl: string;
|
||||
/** The name of the master realm. */
|
||||
masterRealm: string;
|
||||
/** The version hash of the auth sever. */
|
||||
resourceVersion: string;
|
||||
/** Indicates if the application is running as a Keycloak theme. */
|
||||
isRunningAsTheme: boolean;
|
||||
};
|
||||
|
||||
// During development the realm can be passed as a query parameter when redirecting back from Keycloak.
|
||||
const realm =
|
||||
new URLSearchParams(window.location.search).get("realm") ?? "master";
|
||||
|
||||
// The default environment, used during development.
|
||||
const defaultEnvironment: Environment = {
|
||||
loginRealm: realm,
|
||||
authServerUrl: "http://localhost:8180/auth",
|
||||
authUrl: "http://localhost:8180/auth",
|
||||
consoleBaseUrl: "/auth/admin/master/console/",
|
||||
resourceUrl: ".",
|
||||
masterRealm: "master",
|
||||
resourceVersion: "unknown",
|
||||
isRunningAsTheme: false,
|
||||
};
|
||||
|
||||
// Merge the default and injected environment variables together.
|
||||
const environment: Environment = {
|
||||
...defaultEnvironment,
|
||||
...getInjectedEnvironment(),
|
||||
};
|
||||
|
||||
export default environment;
|
||||
|
||||
/**
|
||||
* Extracts the environment variables that are passed if the application is running as a Keycloak theme.
|
||||
* These variables are injected by Keycloak into the `index.ftl` as a script tag, the contents of which can be parsed as JSON.
|
||||
*/
|
||||
function getInjectedEnvironment(): Record<string, string | number | boolean> {
|
||||
const element = document.getElementById("environment");
|
||||
|
||||
// If the element cannot be found, return an empty record.
|
||||
if (!element?.textContent) {
|
||||
return {};
|
||||
}
|
||||
|
||||
// Attempt to parse the contents as JSON and return its value.
|
||||
try {
|
||||
return JSON.parse(element.textContent);
|
||||
} catch (error) {
|
||||
console.error("Unable to parse environment variables.");
|
||||
}
|
||||
|
||||
// Otherwise, return an empty record.
|
||||
return {};
|
||||
}
|
21
src/util.ts
21
src/util.ts
|
@ -5,27 +5,6 @@ import type ClientRepresentation from "keycloak-admin/lib/defs/clientRepresentat
|
|||
import type { ProviderRepresentation } from "keycloak-admin/lib/defs/serverInfoRepesentation";
|
||||
import type KeycloakAdminClient from "keycloak-admin";
|
||||
|
||||
// if we are running on Keycloak server, resourceUrl will be passed from index.ftl
|
||||
declare const resourceUrl: string;
|
||||
export const isDevMode = typeof resourceUrl === "undefined";
|
||||
export const resourceUri = isDevMode ? "." : resourceUrl;
|
||||
|
||||
// if we are running on Keycloak server, loginRealm will be passed from index.ftl
|
||||
declare const loginRealm: string;
|
||||
export const homeRealm = () => {
|
||||
if (typeof loginRealm !== "undefined") return loginRealm;
|
||||
|
||||
return new URLSearchParams(window.location.search).get("realm") || "master";
|
||||
};
|
||||
|
||||
// if we are running on Keycloak server, authUrl will be passed from index.ftl
|
||||
declare const authUrl: string;
|
||||
export const authUri = () => {
|
||||
if (typeof authUrl !== "undefined") return authUrl;
|
||||
|
||||
return "http://localhost:8180/auth";
|
||||
};
|
||||
|
||||
export const sortProviders = (providers: {
|
||||
[index: string]: ProviderRepresentation;
|
||||
}) => {
|
||||
|
|
Loading…
Reference in a new issue