Align environment variables between consoles (#30125)
* change to make authServerUrl the same as authUrl fixes: #29641 Signed-off-by: Erik Jan de Wit <erikjan.dewit@gmail.com> * Remove `authUrl` entirely Signed-off-by: Jon Koops <jonkoops@gmail.com> * Remove file that is unrelated Signed-off-by: Jon Koops <jonkoops@gmail.com> * Split out and align environment variables between consoles Signed-off-by: Jon Koops <jonkoops@gmail.com> * Restore removed variables to preserve backwards compatibility Signed-off-by: Jon Koops <jonkoops@gmail.com> * Also deprecate the `authUrl` for the Admin Console Signed-off-by: Jon Koops <jonkoops@gmail.com> --------- Signed-off-by: Erik Jan de Wit <erikjan.dewit@gmail.com> Signed-off-by: Jon Koops <jonkoops@gmail.com> Co-authored-by: Jon Koops <jonkoops@gmail.com>
This commit is contained in:
parent
2576429def
commit
5897334ddb
27 changed files with 242 additions and 176 deletions
|
@ -438,3 +438,22 @@ An external {jdgserver_name} deployment is supported for multi-site setups as ou
|
|||
|
||||
The Oracle Database JDBC driver is no longer part of the Keycloak distribution.
|
||||
If you wish to use Oracle DB, you must manually install a version of the Oracle Driver that is compatible with your specific environment. Instructions for this process can be found in the https://www.keycloak.org/server/db[Configuring the database] {section}.
|
||||
|
||||
= Deprecated theme variables
|
||||
|
||||
The following variables were deprecated in the Account theme:
|
||||
|
||||
* `authUrl`. Use `authServerUrl` instead.
|
||||
|
||||
The following variables from the environment script injected into the page of the Account theme are deprecated:
|
||||
|
||||
* `authUrl`. Use `authServerUrl` instead.
|
||||
* `features.isInternationalizationEnabled`. Do not use this variable.
|
||||
|
||||
The following variables were deprecated in the Admin theme:
|
||||
|
||||
* `authUrl`. Do not use this variable.
|
||||
|
||||
The following variables from the environment script injected into the page of the Admin theme are deprecated:
|
||||
|
||||
* `authUrl`. Do not use this variable.
|
||||
|
|
|
@ -22,7 +22,7 @@ import { KeycloakProvider } from "@keycloak/keycloak-account-ui";
|
|||
//...
|
||||
|
||||
<KeycloakProvider environment={{
|
||||
authUrl: "http://localhost:8080",
|
||||
authServerUrl: "http://localhost:8080",
|
||||
realm: "master",
|
||||
clientId: "security-admin-console"
|
||||
}}>
|
||||
|
|
|
@ -149,27 +149,28 @@
|
|||
<script id="environment" type="application/json">
|
||||
{
|
||||
"authUrl": "${authUrl}",
|
||||
"baseUrl": "${baseUrl}",
|
||||
"authServerUrl": "${authServerUrl}",
|
||||
"realm": "${realm.name}",
|
||||
"clientId": "${clientId}",
|
||||
"resourceUrl": "${resourceUrl}",
|
||||
"logo": "${properties.logo!""}",
|
||||
"logoUrl": "${properties.logoUrl!""}",
|
||||
"baseUrl": "${baseUrl}",
|
||||
"locale": "${locale}",
|
||||
"referrerName": "${referrerName!""}",
|
||||
"referrerUrl": "${referrer_uri!""}",
|
||||
"features": {
|
||||
"isRegistrationEmailAsUsername": ${realm.registrationEmailAsUsername?c},
|
||||
"isEditUserNameAllowed": ${realm.editUsernameAllowed?c},
|
||||
"isInternationalizationEnabled": ${realm.isInternationalizationEnabled()?c},
|
||||
"isLinkedAccountsEnabled": ${realm.identityFederationEnabled?c},
|
||||
"isMyResourcesEnabled": ${(realm.userManagedAccessAllowed && isAuthorizationEnabled)?c},
|
||||
"deleteAccountAllowed": ${deleteAccountAllowed?c},
|
||||
"updateEmailFeatureEnabled": ${updateEmailFeatureEnabled?c},
|
||||
"updateEmailActionEnabled": ${updateEmailActionEnabled?c},
|
||||
"isViewGroupsEnabled": ${isViewGroupsEnabled?c},
|
||||
"isOid4VciEnabled": ${isOid4VciEnabled?c}
|
||||
},
|
||||
"referrerName": "${referrerName!""}",
|
||||
"referrerUrl": "${referrer_uri!""}"
|
||||
"isRegistrationEmailAsUsername": ${realm.registrationEmailAsUsername?c},
|
||||
"isEditUserNameAllowed": ${realm.editUsernameAllowed?c},
|
||||
"isInternationalizationEnabled": ${realm.isInternationalizationEnabled()?c},
|
||||
"isLinkedAccountsEnabled": ${realm.identityFederationEnabled?c},
|
||||
"isMyResourcesEnabled": ${(realm.userManagedAccessAllowed && isAuthorizationEnabled)?c},
|
||||
"deleteAccountAllowed": ${deleteAccountAllowed?c},
|
||||
"updateEmailFeatureEnabled": ${updateEmailFeatureEnabled?c},
|
||||
"updateEmailActionEnabled": ${updateEmailActionEnabled?c},
|
||||
"isViewGroupsEnabled": ${isViewGroupsEnabled?c},
|
||||
"isOid4VciEnabled": ${isOid4VciEnabled?c}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
|
|
|
@ -1,13 +1,16 @@
|
|||
import { KeycloakContext } from "@keycloak/keycloak-ui-shared";
|
||||
import { BaseEnvironment } from "@keycloak/keycloak-ui-shared/dist/context/environment";
|
||||
import {
|
||||
KeycloakContext,
|
||||
type BaseEnvironment,
|
||||
} from "@keycloak/keycloak-ui-shared";
|
||||
|
||||
import { CallOptions } from "./api/methods";
|
||||
import { Links, parseLinks } from "./api/parse-links";
|
||||
import { parseResponse } from "./api/parse-response";
|
||||
import {
|
||||
CredentialsIssuer,
|
||||
Permission,
|
||||
Resource,
|
||||
Scope,
|
||||
CredentialsIssuer,
|
||||
SupportedCredentialConfiguration,
|
||||
} from "./api/representations";
|
||||
import { request } from "./api/request";
|
||||
|
@ -85,7 +88,7 @@ export async function getIssuer(context: KeycloakContext<BaseEnvironment>) {
|
|||
{},
|
||||
new URL(
|
||||
joinPath(
|
||||
context.environment.authUrl +
|
||||
context.environment.authServerUrl +
|
||||
"/realms/" +
|
||||
context.environment.realm +
|
||||
"/.well-known/openid-credential-issuer",
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import {
|
||||
AccountEnvironment,
|
||||
KeycloakContext,
|
||||
BaseEnvironment,
|
||||
type KeycloakContext,
|
||||
} from "@keycloak/keycloak-ui-shared";
|
||||
import { BaseEnvironment } from "@keycloak/keycloak-ui-shared/dist/context/environment";
|
||||
|
||||
import { joinPath } from "../utils/joinPath";
|
||||
import { parseResponse } from "./parse-response";
|
||||
import {
|
||||
|
@ -45,7 +45,7 @@ export async function getSupportedLocales({
|
|||
}
|
||||
|
||||
export async function savePersonalInfo(
|
||||
context: KeycloakContext<AccountEnvironment>,
|
||||
context: KeycloakContext<BaseEnvironment>,
|
||||
info: UserRepresentation,
|
||||
): Promise<void> {
|
||||
const response = await request("/", context, { body: info, method: "POST" });
|
||||
|
@ -134,7 +134,7 @@ export async function linkAccount(
|
|||
) {
|
||||
const redirectUri = encodeURIComponent(
|
||||
joinPath(
|
||||
context.environment.authUrl,
|
||||
context.environment.authServerUrl,
|
||||
"realms",
|
||||
context.environment.realm,
|
||||
"account",
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
import { KeycloakContext } from "@keycloak/keycloak-ui-shared";
|
||||
import { BaseEnvironment } from "@keycloak/keycloak-ui-shared/dist/context/environment";
|
||||
import {
|
||||
KeycloakContext,
|
||||
type BaseEnvironment,
|
||||
} from "@keycloak/keycloak-ui-shared";
|
||||
import Keycloak from "keycloak-js";
|
||||
|
||||
import { joinPath } from "../utils/joinPath";
|
||||
import { CONTENT_TYPE_HEADER, CONTENT_TYPE_JSON } from "./constants";
|
||||
|
||||
|
@ -50,7 +53,13 @@ export async function request(
|
|||
|
||||
export const url = (environment: BaseEnvironment, path: string) =>
|
||||
new URL(
|
||||
joinPath(environment.authUrl, "realms", environment.realm, "account", path),
|
||||
joinPath(
|
||||
environment.authServerUrl,
|
||||
"realms",
|
||||
environment.realm,
|
||||
"account",
|
||||
path,
|
||||
),
|
||||
);
|
||||
|
||||
export const token = (keycloak: Keycloak) =>
|
||||
|
|
61
js/apps/account-ui/src/environment.ts
Normal file
61
js/apps/account-ui/src/environment.ts
Normal file
|
@ -0,0 +1,61 @@
|
|||
import {
|
||||
getInjectedEnvironment,
|
||||
type BaseEnvironment,
|
||||
} from "@keycloak/keycloak-ui-shared";
|
||||
|
||||
export type Environment = BaseEnvironment & {
|
||||
/** The URL to the root of the account console. */
|
||||
baseUrl: string;
|
||||
/** The locale of the user */
|
||||
locale: string;
|
||||
/** Name of the referrer application in the back link */
|
||||
referrerName?: string;
|
||||
/** UR to the referrer application in the back link */
|
||||
referrerUrl?: string;
|
||||
/** Feature flags */
|
||||
features: Feature;
|
||||
};
|
||||
|
||||
export type Feature = {
|
||||
isRegistrationEmailAsUsername: boolean;
|
||||
isEditUserNameAllowed: boolean;
|
||||
isLinkedAccountsEnabled: boolean;
|
||||
isMyResourcesEnabled: boolean;
|
||||
deleteAccountAllowed: boolean;
|
||||
updateEmailFeatureEnabled: boolean;
|
||||
updateEmailActionEnabled: boolean;
|
||||
isViewGroupsEnabled: boolean;
|
||||
isOid4VciEnabled: 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") ||
|
||||
location.pathname.match("/realms/(.*?)/account")?.[1] ||
|
||||
"master";
|
||||
|
||||
const defaultEnvironment: Environment = {
|
||||
// Base environment variables
|
||||
authServerUrl: "http://localhost:8180",
|
||||
realm: realm,
|
||||
clientId: "security-admin-console-v2",
|
||||
resourceUrl: "http://localhost:8080",
|
||||
logo: "/logo.svg",
|
||||
logoUrl: "/",
|
||||
// Account Console specific environment variables
|
||||
baseUrl: `http://localhost:8180/realms/${realm}/account/`,
|
||||
locale: "en",
|
||||
features: {
|
||||
isRegistrationEmailAsUsername: false,
|
||||
isEditUserNameAllowed: true,
|
||||
isLinkedAccountsEnabled: true,
|
||||
isMyResourcesEnabled: true,
|
||||
deleteAccountAllowed: true,
|
||||
updateEmailFeatureEnabled: true,
|
||||
updateEmailActionEnabled: true,
|
||||
isViewGroupsEnabled: true,
|
||||
isOid4VciEnabled: true,
|
||||
},
|
||||
};
|
||||
|
||||
export const environment = getInjectedEnvironment(defaultEnvironment);
|
|
@ -1,7 +1,8 @@
|
|||
import { LanguageDetectorModule, createInstance } from "i18next";
|
||||
import HttpBackend from "i18next-http-backend";
|
||||
import { initReactI18next } from "react-i18next";
|
||||
import { environment } from "@keycloak/keycloak-ui-shared";
|
||||
|
||||
import { environment } from "./environment";
|
||||
import { joinPath } from "./utils/joinPath";
|
||||
|
||||
const DEFAULT_LOCALE = "en";
|
||||
|
@ -28,7 +29,7 @@ export const i18n = createInstance({
|
|||
},
|
||||
backend: {
|
||||
loadPath: joinPath(
|
||||
environment.authUrl,
|
||||
environment.authServerUrl,
|
||||
`resources/${environment.realm}/account/{{lng}}`,
|
||||
),
|
||||
parse: (data: string) => {
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import {
|
||||
AccountEnvironment,
|
||||
UserProfileFields,
|
||||
beerify,
|
||||
debeerify,
|
||||
|
@ -20,6 +19,7 @@ import { TFunction } from "i18next";
|
|||
import { useState } from "react";
|
||||
import { ErrorOption, useForm } from "react-hook-form";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
import {
|
||||
getPersonalInfo,
|
||||
getSupportedLocales,
|
||||
|
@ -30,12 +30,13 @@ import {
|
|||
UserRepresentation,
|
||||
} from "../api/representations";
|
||||
import { Page } from "../components/page/Page";
|
||||
import type { Environment } from "../environment";
|
||||
import { TFuncKey, i18n } from "../i18n";
|
||||
import { usePromise } from "../utils/usePromise";
|
||||
|
||||
export const PersonalInfo = () => {
|
||||
const { t } = useTranslation();
|
||||
const context = useEnvironment<AccountEnvironment>();
|
||||
const context = useEnvironment<Environment>();
|
||||
const [userProfileMetadata, setUserProfileMetadata] =
|
||||
useState<UserProfileMetadata>();
|
||||
const [supportedLocales, setSupportedLocales] = useState<string[]>([]);
|
||||
|
|
|
@ -1,13 +1,14 @@
|
|||
import {
|
||||
KeycloakMasthead,
|
||||
label,
|
||||
useEnvironment,
|
||||
} from "@keycloak/keycloak-ui-shared";
|
||||
import { Button } from "@patternfly/react-core";
|
||||
import { ExternalLinkSquareAltIcon } from "@patternfly/react-icons";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useHref } from "react-router-dom";
|
||||
import {
|
||||
KeycloakMasthead,
|
||||
environment,
|
||||
label,
|
||||
useEnvironment,
|
||||
} from "@keycloak/keycloak-ui-shared";
|
||||
|
||||
import { environment } from "../environment";
|
||||
import { joinPath } from "../utils/joinPath";
|
||||
|
||||
import style from "./header.module.css";
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import { useEnvironment } from "@keycloak/keycloak-ui-shared";
|
||||
import {
|
||||
Nav,
|
||||
NavExpandable,
|
||||
|
@ -22,13 +23,9 @@ import {
|
|||
useLinkClickHandler,
|
||||
useLocation,
|
||||
} from "react-router-dom";
|
||||
import {
|
||||
AccountEnvironment,
|
||||
environment,
|
||||
useEnvironment,
|
||||
type Feature,
|
||||
} from "@keycloak/keycloak-ui-shared";
|
||||
|
||||
import fetchContentJson from "../content/fetchContent";
|
||||
import { environment, type Environment, type Feature } from "../environment";
|
||||
import { TFuncKey } from "../i18n";
|
||||
import { usePromise } from "../utils/usePromise";
|
||||
|
||||
|
@ -49,7 +46,7 @@ export type MenuItem = RootMenuItem | MenuItemWithChildren;
|
|||
|
||||
export const PageNav = () => {
|
||||
const [menuItems, setMenuItems] = useState<MenuItem[]>();
|
||||
const context = useEnvironment<AccountEnvironment>();
|
||||
const context = useEnvironment<Environment>();
|
||||
|
||||
usePromise((signal) => fetchContentJson({ signal, context }), setMenuItems);
|
||||
return (
|
||||
|
@ -86,7 +83,7 @@ function NavMenuItem({ menuItem }: NavMenuItemProps) {
|
|||
const { t } = useTranslation();
|
||||
const {
|
||||
environment: { features },
|
||||
} = useEnvironment<AccountEnvironment>();
|
||||
} = useEnvironment<Environment>();
|
||||
const { pathname } = useLocation();
|
||||
const isActive = useMemo(
|
||||
() => matchMenuItem(pathname, menuItem),
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
import { KeycloakProvider, environment } from "@keycloak/keycloak-ui-shared";
|
||||
import { KeycloakProvider } from "@keycloak/keycloak-ui-shared";
|
||||
import { Page, Spinner } from "@patternfly/react-core";
|
||||
import { Suspense } from "react";
|
||||
import { Outlet } from "react-router-dom";
|
||||
|
||||
import { environment } from "../environment";
|
||||
import { Header } from "./Header";
|
||||
import { PageNav } from "./PageNav";
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import { lazy } from "react";
|
||||
import type { IndexRouteObject, RouteObject } from "react-router-dom";
|
||||
import { environment } from "@keycloak/keycloak-ui-shared";
|
||||
|
||||
import { environment } from "./environment";
|
||||
import { ErrorPage } from "./root/ErrorPage";
|
||||
import { Root } from "./root/Root";
|
||||
|
||||
|
|
|
@ -124,16 +124,16 @@
|
|||
<![CDATA[
|
||||
<script id="environment" type="application/json">
|
||||
{
|
||||
"authUrl": "${authUrl}",
|
||||
"authServerUrl": "${authServerUrl}",
|
||||
"realm": "${loginRealm!"master"}",
|
||||
"clientId": "${clientId}",
|
||||
"authServerUrl": "${authServerUrl}",
|
||||
"authUrl": "${authUrl}",
|
||||
"consoleBaseUrl": "${consoleBaseUrl}",
|
||||
"resourceUrl": "${resourceUrl}",
|
||||
"masterRealm": "${masterRealm}",
|
||||
"resourceVersion": "${resourceVersion}",
|
||||
"logo": "${properties.logo!""}",
|
||||
"logoUrl": "${properties.logoUrl!""}"
|
||||
"logoUrl": "${properties.logoUrl!""}",
|
||||
"consoleBaseUrl": "${consoleBaseUrl}",
|
||||
"masterRealm": "${masterRealm}",
|
||||
"resourceVersion": "${resourceVersion}"
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
import KeycloakAdminClient from "@keycloak/keycloak-admin-client";
|
||||
import { Page } from "@patternfly/react-core";
|
||||
import { PropsWithChildren, Suspense, useEffect, useState } from "react";
|
||||
import { Outlet } from "react-router-dom";
|
||||
import {
|
||||
mainPageContentId,
|
||||
useEnvironment,
|
||||
} from "@keycloak/keycloak-ui-shared";
|
||||
import { Page } from "@patternfly/react-core";
|
||||
import { PropsWithChildren, Suspense, useEffect, useState } from "react";
|
||||
import { Outlet } from "react-router-dom";
|
||||
|
||||
import { Header } from "./PageHeader";
|
||||
import { PageNav } from "./PageNav";
|
||||
import { AdminClientContext, initAdminClient } from "./admin-client";
|
||||
|
@ -23,6 +24,7 @@ import { AccessContextProvider } from "./context/access/Access";
|
|||
import { RealmContextProvider } from "./context/realm-context/RealmContext";
|
||||
import { ServerInfoProvider } from "./context/server-info/ServerInfoProvider";
|
||||
import { WhoAmIContextProvider } from "./context/whoami/WhoAmI";
|
||||
import type { Environment } from "./environment";
|
||||
import { SubGroups } from "./groups/SubGroupsContext";
|
||||
import { AuthWall } from "./root/AuthWall";
|
||||
|
||||
|
@ -47,7 +49,7 @@ const AppContexts = ({ children }: PropsWithChildren) => (
|
|||
);
|
||||
|
||||
export const App = () => {
|
||||
const { keycloak, environment } = useEnvironment();
|
||||
const { keycloak, environment } = useEnvironment<Environment>();
|
||||
const [adminClient, setAdminClient] = useState<KeycloakAdminClient>();
|
||||
|
||||
useEffect(() => {
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
import { KeycloakProvider, environment } from "@keycloak/keycloak-ui-shared";
|
||||
import { KeycloakProvider } from "@keycloak/keycloak-ui-shared";
|
||||
|
||||
import { App } from "./App";
|
||||
import { environment } from "./environment";
|
||||
|
||||
export const Root = () => (
|
||||
<KeycloakProvider environment={environment}>
|
||||
|
|
|
@ -3,9 +3,10 @@ import {
|
|||
createNamedContext,
|
||||
useRequiredContext,
|
||||
} from "@keycloak/keycloak-ui-shared";
|
||||
import { BaseEnvironment } from "@keycloak/keycloak-ui-shared/dist/context/environment";
|
||||
import type Keycloak from "keycloak-js";
|
||||
|
||||
import type { Environment } from "./environment";
|
||||
|
||||
export type AdminClientProps = {
|
||||
keycloak: Keycloak;
|
||||
adminClient: KeycloakAdminClient;
|
||||
|
@ -19,12 +20,12 @@ export const useAdminClient = () => useRequiredContext(AdminClientContext);
|
|||
|
||||
export async function initAdminClient(
|
||||
keycloak: Keycloak,
|
||||
environment: BaseEnvironment,
|
||||
environment: Environment,
|
||||
) {
|
||||
const adminClient = new KeycloakAdminClient();
|
||||
|
||||
adminClient.setConfig({ realmName: environment.realm });
|
||||
adminClient.baseUrl = environment.authUrl;
|
||||
adminClient.baseUrl = environment.authServerUrl;
|
||||
adminClient.registerTokenProvider({
|
||||
async getAccessToken() {
|
||||
try {
|
||||
|
|
33
js/apps/admin-ui/src/environment.ts
Normal file
33
js/apps/admin-ui/src/environment.ts
Normal file
|
@ -0,0 +1,33 @@
|
|||
import {
|
||||
getInjectedEnvironment,
|
||||
type BaseEnvironment,
|
||||
} from "@keycloak/keycloak-ui-shared";
|
||||
|
||||
export type Environment = BaseEnvironment & {
|
||||
/** The URL to the base of the Admin Console. */
|
||||
consoleBaseUrl: string;
|
||||
/** The name of the master realm. */
|
||||
masterRealm: string;
|
||||
/** The version hash of the auth server. */
|
||||
resourceVersion: string;
|
||||
};
|
||||
|
||||
// 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";
|
||||
|
||||
const defaultEnvironment: Environment = {
|
||||
// Base environment variables
|
||||
authServerUrl: "http://localhost:8180",
|
||||
realm: realm,
|
||||
clientId: "security-admin-console-v2",
|
||||
resourceUrl: "http://localhost:8080",
|
||||
logo: "/logo.svg",
|
||||
logoUrl: "",
|
||||
// Admin Console specific environment variables
|
||||
consoleBaseUrl: "/admin/master/console/",
|
||||
masterRealm: "master",
|
||||
resourceVersion: "unknown",
|
||||
};
|
||||
|
||||
export const environment = getInjectedEnvironment(defaultEnvironment);
|
|
@ -1,7 +1,8 @@
|
|||
import { createInstance } from "i18next";
|
||||
import HttpBackend from "i18next-http-backend";
|
||||
import { initReactI18next } from "react-i18next";
|
||||
import { environment } from "@keycloak/keycloak-ui-shared";
|
||||
|
||||
import { environment } from "../environment";
|
||||
import { joinPath } from "../utils/joinPath";
|
||||
|
||||
type KeyValue = { key: string; value: string };
|
||||
|
|
|
@ -1,18 +1,19 @@
|
|||
import { fetchWithError } from "@keycloak/keycloak-admin-client";
|
||||
import type IdentityProviderRepresentation from "@keycloak/keycloak-admin-client/lib/defs/identityProviderRepresentation";
|
||||
import { FormGroup, Title } from "@patternfly/react-core";
|
||||
import { useFormContext } from "react-hook-form";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import {
|
||||
AdminEnvironment,
|
||||
FormErrorText,
|
||||
HelpItem,
|
||||
TextControl,
|
||||
useEnvironment,
|
||||
} from "@keycloak/keycloak-ui-shared";
|
||||
import { FormGroup, Title } from "@patternfly/react-core";
|
||||
import { useFormContext } from "react-hook-form";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
import { useAdminClient } from "../../admin-client";
|
||||
import { FileUploadForm } from "../../components/json-file-upload/FileUploadForm";
|
||||
import { useRealm } from "../../context/realm-context/RealmContext";
|
||||
import type { Environment } from "../../environment";
|
||||
import { addTrailingSlash } from "../../util";
|
||||
import { getAuthorizationHeaders } from "../../utils/getAuthorizationHeaders";
|
||||
import { DiscoveryEndpointField } from "../component/DiscoveryEndpointField";
|
||||
|
@ -24,7 +25,7 @@ type FormFields = IdentityProviderRepresentation & {
|
|||
|
||||
export const SamlConnectSettings = () => {
|
||||
const { adminClient } = useAdminClient();
|
||||
const { environment } = useEnvironment<AdminEnvironment>();
|
||||
const { environment } = useEnvironment<Environment>();
|
||||
|
||||
const { t } = useTranslation();
|
||||
const id = "saml";
|
||||
|
|
|
@ -1,13 +1,15 @@
|
|||
import { FormGroup } from "@patternfly/react-core";
|
||||
import { useFormContext, useWatch } from "react-hook-form";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import {
|
||||
HelpItem,
|
||||
TextControl,
|
||||
useEnvironment,
|
||||
} from "@keycloak/keycloak-ui-shared";
|
||||
import { FormGroup } from "@patternfly/react-core";
|
||||
import { useFormContext, useWatch } from "react-hook-form";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
import { FormattedLink } from "../../components/external-link/FormattedLink";
|
||||
import { useRealm } from "../../context/realm-context/RealmContext";
|
||||
import type { Environment } from "../../environment";
|
||||
import { DisplayOrder } from "../component/DisplayOrder";
|
||||
import { RedirectUrl } from "../component/RedirectUrl";
|
||||
|
||||
|
@ -22,7 +24,7 @@ export const SamlGeneralSettings = ({
|
|||
}: SamlGeneralSettingsProps) => {
|
||||
const { t } = useTranslation();
|
||||
const { realm } = useRealm();
|
||||
const { environment } = useEnvironment();
|
||||
const { environment } = useEnvironment<Environment>();
|
||||
|
||||
const { control } = useFormContext();
|
||||
const alias = useWatch({ control, name: "alias" });
|
||||
|
@ -54,7 +56,7 @@ export const SamlGeneralSettings = ({
|
|||
>
|
||||
<FormattedLink
|
||||
title={t("samlEndpointsLabel")}
|
||||
href={`${environment.authUrl}/realms/${realm}/broker/${alias}/endpoint/descriptor`}
|
||||
href={`${environment.authServerUrl}/realms/${realm}/broker/${alias}/endpoint/descriptor`}
|
||||
isInline
|
||||
/>
|
||||
</FormGroup>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { fetchWithError } from "@keycloak/keycloak-admin-client";
|
||||
import type RealmRepresentation from "@keycloak/keycloak-admin-client/lib/defs/realmRepresentation";
|
||||
import { UserProfileConfig } from "@keycloak/keycloak-admin-client/lib/defs/userProfileMetadata";
|
||||
import { AdminEnvironment, useEnvironment } from "@keycloak/keycloak-ui-shared";
|
||||
import { useEnvironment } from "@keycloak/keycloak-ui-shared";
|
||||
import {
|
||||
AlertVariant,
|
||||
ButtonVariant,
|
||||
|
@ -16,6 +16,7 @@ import { useEffect, useState } from "react";
|
|||
import { Controller, useForm } from "react-hook-form";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
|
||||
import { useAdminClient } from "../admin-client";
|
||||
import { useAlerts } from "../components/alert/Alerts";
|
||||
import { useConfirmDialog } from "../components/confirm-dialog/ConfirmDialog";
|
||||
|
@ -29,6 +30,7 @@ import { useRealms } from "../context/RealmsContext";
|
|||
import { useAccess } from "../context/access/Access";
|
||||
import { useRealm } from "../context/realm-context/RealmContext";
|
||||
import { toDashboard } from "../dashboard/routes/Dashboard";
|
||||
import type { Environment } from "../environment";
|
||||
import helpUrls from "../help-urls";
|
||||
import { convertFormValuesToObject, convertToFormValues } from "../util";
|
||||
import { getAuthorizationHeaders } from "../utils/getAuthorizationHeaders";
|
||||
|
@ -74,7 +76,7 @@ const RealmSettingsHeader = ({
|
|||
refresh,
|
||||
}: RealmSettingsHeaderProps) => {
|
||||
const { adminClient } = useAdminClient();
|
||||
const { environment } = useEnvironment<AdminEnvironment>();
|
||||
const { environment } = useEnvironment<Environment>();
|
||||
const { t } = useTranslation();
|
||||
const { refresh: refreshRealms } = useRealms();
|
||||
const { addAlert, addError } = useAlerts();
|
||||
|
|
|
@ -49,7 +49,7 @@ export const KeycloakProvider = <T extends BaseEnvironment>({
|
|||
const [error, setError] = useState<unknown>();
|
||||
const keycloak = useMemo(() => {
|
||||
const keycloak = new Keycloak({
|
||||
url: environment.authUrl,
|
||||
url: environment.authServerUrl,
|
||||
realm: environment.realm,
|
||||
clientId: environment.clientId,
|
||||
});
|
||||
|
|
|
@ -1,109 +1,33 @@
|
|||
export const DEFAULT_REALM = "master";
|
||||
|
||||
export type Feature = {
|
||||
isRegistrationEmailAsUsername: boolean;
|
||||
isEditUserNameAllowed: boolean;
|
||||
isInternationalizationEnabled: boolean;
|
||||
isLinkedAccountsEnabled: boolean;
|
||||
isEventsEnabled: boolean;
|
||||
isMyResourcesEnabled: boolean;
|
||||
isTotpConfigured: boolean;
|
||||
deleteAccountAllowed: boolean;
|
||||
updateEmailFeatureEnabled: boolean;
|
||||
updateEmailActionEnabled: boolean;
|
||||
isViewGroupsEnabled: boolean;
|
||||
isOid4VciEnabled: boolean;
|
||||
};
|
||||
|
||||
/** The base environment variables that are shared between the Admin and Account Consoles. */
|
||||
export type BaseEnvironment = {
|
||||
/** The URL to the root of the auth server. */
|
||||
authUrl: string;
|
||||
/** The URL to the root of the account console. */
|
||||
baseUrl: string;
|
||||
/** The realm used to authenticate the user to the Account Console. */
|
||||
/**
|
||||
* The URL to the root of the Keycloak server, this is **NOT** always equivalent to the URL of the Admin Console.
|
||||
* For example, the Keycloak server could be hosted on `auth.example.com` and Admin Console may be hosted on `admin.example.com`.
|
||||
*
|
||||
* @see {@link https://www.keycloak.org/server/hostname#_administration_console}
|
||||
*/
|
||||
authServerUrl: string;
|
||||
/** The identifier of the realm used to authenticate the user. */
|
||||
realm: string;
|
||||
/** The identifier of the client used to authenticate the user to the Account Console. */
|
||||
/** The identifier of the client used to authenticate the user. */
|
||||
clientId: string;
|
||||
/** The URL to resources such as the files in the `public` directory. */
|
||||
/** The base URL of the resources. */
|
||||
resourceUrl: string;
|
||||
/** Indicates the src for the Brand image */
|
||||
/** The source URL for the the logo image. */
|
||||
logo: string;
|
||||
/** Indicates the url to be followed when Brand image is clicked */
|
||||
/** The URL to be followed when the logo is clicked. */
|
||||
logoUrl: string;
|
||||
};
|
||||
|
||||
export type AdminEnvironment = BaseEnvironment & {
|
||||
/** The URL to the root of the auth server. */
|
||||
authServerUrl: string;
|
||||
/** The name of the master realm. */
|
||||
masterRealm: string;
|
||||
/** The URL to the base of the Admin UI. */
|
||||
consoleBaseUrl: string;
|
||||
/** The version hash of the auth server. */
|
||||
resourceVersion: string;
|
||||
};
|
||||
|
||||
export type AccountEnvironment = BaseEnvironment & {
|
||||
/** The locale of the user */
|
||||
locale: string;
|
||||
/** Feature flags */
|
||||
features: Feature;
|
||||
/** Name of the referrer application in the back link */
|
||||
referrerName?: string;
|
||||
/** UR to the referrer application in the back link */
|
||||
referrerUrl?: string;
|
||||
};
|
||||
|
||||
// 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") ||
|
||||
location.pathname.match("/realms/(.*?)/account")?.[1];
|
||||
|
||||
const defaultEnvironment: AdminEnvironment & AccountEnvironment = {
|
||||
authUrl: "http://localhost:8180",
|
||||
authServerUrl: "http://localhost:8180",
|
||||
baseUrl: `http://localhost:8180/realms/${realm ?? DEFAULT_REALM}/account/`,
|
||||
realm: realm ?? DEFAULT_REALM,
|
||||
clientId: "security-admin-console-v2",
|
||||
resourceUrl: "http://localhost:8080",
|
||||
logo: "/logo.svg",
|
||||
logoUrl: "/",
|
||||
locale: "en",
|
||||
consoleBaseUrl: "/admin/master/console/",
|
||||
masterRealm: "master",
|
||||
resourceVersion: "unknown",
|
||||
features: {
|
||||
isRegistrationEmailAsUsername: false,
|
||||
isEditUserNameAllowed: true,
|
||||
isInternationalizationEnabled: true,
|
||||
isLinkedAccountsEnabled: true,
|
||||
isEventsEnabled: true,
|
||||
isMyResourcesEnabled: true,
|
||||
isTotpConfigured: true,
|
||||
deleteAccountAllowed: true,
|
||||
updateEmailFeatureEnabled: true,
|
||||
updateEmailActionEnabled: true,
|
||||
isViewGroupsEnabled: true,
|
||||
isOid4VciEnabled: false,
|
||||
},
|
||||
};
|
||||
|
||||
// Merge the default and injected environment variables together.
|
||||
const environment = {
|
||||
...defaultEnvironment,
|
||||
...getInjectedEnvironment(),
|
||||
};
|
||||
|
||||
export { environment };
|
||||
|
||||
/**
|
||||
* Extracts the environment variables that are passed if the application is running as a Keycloak theme.
|
||||
* Extracts the environment variables that are passed if the application is running as a Keycloak theme and combines them with the provided defaults.
|
||||
* These variables are injected by Keycloak into the `index.ftl` as a script tag, the contents of which can be parsed as JSON.
|
||||
*
|
||||
* @argument defaults - The default values to fall to if a value is not present in the environment.
|
||||
*/
|
||||
function getInjectedEnvironment(): Record<string, string | number | boolean> {
|
||||
export function getInjectedEnvironment<T>(defaults: T): T {
|
||||
const element = document.getElementById("environment");
|
||||
|
||||
let env = {} as Record<string, string | number | boolean>;
|
||||
let env = {} as T;
|
||||
|
||||
// Attempt to parse the contents as JSON and return its value.
|
||||
try {
|
||||
|
@ -115,6 +39,6 @@ function getInjectedEnvironment(): Record<string, string | number | boolean> {
|
|||
console.error("Unable to parse environment variables.");
|
||||
}
|
||||
|
||||
// Otherwise, return an empty record.
|
||||
return env;
|
||||
// Return the merged environment variables with the defaults.
|
||||
return { ...defaults, ...env };
|
||||
}
|
||||
|
|
|
@ -7,10 +7,8 @@ export {
|
|||
type KeycloakContext,
|
||||
} from "./context/KeycloakContext";
|
||||
export {
|
||||
environment,
|
||||
type AccountEnvironment,
|
||||
type AdminEnvironment,
|
||||
type Feature,
|
||||
getInjectedEnvironment,
|
||||
type BaseEnvironment,
|
||||
} from "./context/environment";
|
||||
export { ContinueCancelModal } from "./continue-cancel/ContinueCancelModal";
|
||||
export {
|
||||
|
|
|
@ -105,7 +105,10 @@ public class AccountConsole implements AccountResourceProvider {
|
|||
|
||||
URI adminBaseUri = session.getContext().getUri(UrlType.ADMIN).getBaseUri();
|
||||
URI authUrl = uriInfo.getBaseUri();
|
||||
map.put("authUrl", authUrl.getPath().endsWith("/") ? authUrl : authUrl + "/");
|
||||
var authServerUrl = authUrl.getPath().endsWith("/") ? authUrl : authUrl + "/";
|
||||
// TODO: The 'authUrl' variable is deprecated and only exists to provide backwards compatibility for older themes, it should be removed in a future version.
|
||||
map.put("authUrl", authServerUrl);
|
||||
map.put("authServerUrl", authServerUrl);
|
||||
map.put("baseUrl", accountBaseUrl.getPath().endsWith("/") ? accountBaseUrl : accountBaseUrl + "/");
|
||||
map.put("realm", realm);
|
||||
map.put("clientId", Constants.ACCOUNT_CONSOLE_CLIENT_ID);
|
||||
|
|
|
@ -346,6 +346,7 @@ public class AdminConsole {
|
|||
}
|
||||
|
||||
map.put("authServerUrl", authServerBaseUrl);
|
||||
// TODO: The 'authUrl' variable is deprecated and only exists to provide backwards compatibility for older themes, it should be removed in a future version.
|
||||
map.put("authUrl", adminBaseUrl);
|
||||
map.put("consoleBaseUrl", Urls.adminConsoleRoot(adminBaseUri, realm.getName()).getPath());
|
||||
map.put("resourceUrl", Urls.themeRoot(adminBaseUri).getPath() + "/admin/" + theme.getName());
|
||||
|
|
Loading…
Reference in a new issue