mirror of
https://github.com/keycloak/keycloak.git
synced 2026-01-10 15:32:05 -03:30
Closes #27628 Signed-off-by: Jon Koops <jonkoops@gmail.com> (cherry picked from commit 3216e7c781a9bb6399d33255e6b10275b3cc81f9)
This commit is contained in:
parent
a1cfc4d816
commit
bd38e1d323
@ -166,7 +166,9 @@
|
||||
"updateEmailFeatureEnabled": ${updateEmailFeatureEnabled?c},
|
||||
"updateEmailActionEnabled": ${updateEmailActionEnabled?c},
|
||||
"isViewGroupsEnabled": ${isViewGroupsEnabled?c}
|
||||
}
|
||||
},
|
||||
"referrerName": "${referrerName!""}",
|
||||
"referrerUrl": "${referrer_uri!""}"
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
|
||||
@ -29,6 +29,10 @@ export type Environment = {
|
||||
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;
|
||||
};
|
||||
|
||||
// The default environment, used during development.
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
import { Button } from "@patternfly/react-core";
|
||||
import { ExternalLinkSquareAltIcon } from "@patternfly/react-icons";
|
||||
import {
|
||||
KeycloakMasthead,
|
||||
KeycloakProvider,
|
||||
@ -7,28 +9,30 @@ import {
|
||||
import { useMemo } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useHref } from "react-router-dom";
|
||||
import { useEnvironment } from "./KeycloakContext";
|
||||
import { label } from "ui-shared";
|
||||
|
||||
import { environment } from "../environment";
|
||||
import { joinPath } from "../utils/joinPath";
|
||||
import { ExternalLinkSquareAltIcon } from "@patternfly/react-icons";
|
||||
import { Button } from "@patternfly/react-core";
|
||||
import { useEnvironment } from "./KeycloakContext";
|
||||
|
||||
import style from "./header.module.css";
|
||||
|
||||
const ReferrerLink = () => {
|
||||
const { t } = useTranslation();
|
||||
const searchParams = new URLSearchParams(location.search);
|
||||
|
||||
return searchParams.has("referrer_uri") ? (
|
||||
return environment.referrerUrl ? (
|
||||
<Button
|
||||
data-testid="referrer-link"
|
||||
component="a"
|
||||
href={searchParams.get("referrer_uri")!.replace("_hash_", "#")}
|
||||
href={environment.referrerUrl.replace("_hash_", "#")}
|
||||
variant="link"
|
||||
icon={<ExternalLinkSquareAltIcon />}
|
||||
iconPosition="right"
|
||||
isInline
|
||||
>
|
||||
{t("backTo", { app: searchParams.get("referrer") })}
|
||||
{t("backTo", {
|
||||
app: label(t, environment.referrerName, environment.referrerUrl),
|
||||
})}
|
||||
</Button>
|
||||
) : null;
|
||||
};
|
||||
|
||||
5
js/apps/account-ui/test/constants.ts
Normal file
5
js/apps/account-ui/test/constants.ts
Normal file
@ -0,0 +1,5 @@
|
||||
export const SERVER_URL = "http://localhost:8080";
|
||||
export const ROOT_PATH = "/realms/:realm/account";
|
||||
export const DEFAULT_REALM = "master";
|
||||
export const ADMIN_USER = "admin";
|
||||
export const ADMIN_PASSWORD = "admin";
|
||||
@ -1,15 +1,26 @@
|
||||
import { Page } from "@playwright/test";
|
||||
|
||||
import { ADMIN_PASSWORD, ADMIN_USER, DEFAULT_REALM } from "./constants";
|
||||
import { getRootPath } from "./utils";
|
||||
|
||||
export const login = async (
|
||||
page: Page,
|
||||
username: string,
|
||||
password: string,
|
||||
realm?: string,
|
||||
username = ADMIN_USER,
|
||||
password = ADMIN_PASSWORD,
|
||||
realm = DEFAULT_REALM,
|
||||
queryParams?: Record<string, string>,
|
||||
) => {
|
||||
if (realm)
|
||||
await page.goto(
|
||||
process.env.CI ? `/realms/${realm}/account` : `/?realm=${realm}`,
|
||||
);
|
||||
const params = new URLSearchParams(queryParams);
|
||||
|
||||
if (!process.env.CI) {
|
||||
params.set("realm", realm);
|
||||
}
|
||||
|
||||
const rootPath =
|
||||
(process.env.CI ? getRootPath(realm) : "/") +
|
||||
(params.size > 0 ? `?${params.toString()}` : "");
|
||||
|
||||
await page.goto(rootPath);
|
||||
await page.getByLabel("Username").fill(username);
|
||||
await page.getByLabel("Password", { exact: true }).fill(password);
|
||||
await page.getByRole("button", { name: "Sign In" }).click();
|
||||
|
||||
47
js/apps/account-ui/test/referrer.spec.ts
Normal file
47
js/apps/account-ui/test/referrer.spec.ts
Normal file
@ -0,0 +1,47 @@
|
||||
import { expect, test } from "@playwright/test";
|
||||
|
||||
import { ADMIN_PASSWORD, ADMIN_USER, DEFAULT_REALM } from "./constants";
|
||||
import { login } from "./login";
|
||||
import { getAdminUrl } from "./utils";
|
||||
|
||||
// NOTE: This test suite will only pass when running a production build, as the referrer is extracted on the server side.
|
||||
// This will change once https://github.com/keycloak/keycloak/pull/27311 has been merged.
|
||||
|
||||
test.describe("Signing in with referrer link", () => {
|
||||
test("shows a referrer link when a matching client exists", async ({
|
||||
page,
|
||||
}) => {
|
||||
const referrer = "security-admin-console";
|
||||
const referrerUrl = getAdminUrl();
|
||||
const referrerName = "security admin console";
|
||||
|
||||
const queryParams = {
|
||||
referrer,
|
||||
referrer_uri: referrerUrl,
|
||||
};
|
||||
|
||||
await login(page, ADMIN_USER, ADMIN_PASSWORD, DEFAULT_REALM, queryParams);
|
||||
await expect(page.getByTestId("referrer-link")).toContainText(referrerName);
|
||||
|
||||
// Navigate around to ensure the referrer is still shown.
|
||||
await page.getByTestId("accountSecurity").click();
|
||||
await expect(page.getByTestId("account-security/signing-in")).toBeVisible();
|
||||
await expect(page.getByTestId("referrer-link")).toContainText(referrerName);
|
||||
});
|
||||
|
||||
test("shows no referrer link when an invalid URL is passed", async ({
|
||||
page,
|
||||
}) => {
|
||||
const referrer = "security-admin-console";
|
||||
const referrerUrl = "http://i-am-not-an-allowed-url.com";
|
||||
|
||||
const queryParams = {
|
||||
referrer,
|
||||
referrer_uri: referrerUrl,
|
||||
};
|
||||
|
||||
await login(page, ADMIN_USER, ADMIN_PASSWORD, DEFAULT_REALM, queryParams);
|
||||
await expect(page.getByText("Manage your basic information")).toBeVisible();
|
||||
await expect(page.getByTestId("referrer-link")).toBeHidden();
|
||||
});
|
||||
});
|
||||
14
js/apps/account-ui/test/utils.ts
Normal file
14
js/apps/account-ui/test/utils.ts
Normal file
@ -0,0 +1,14 @@
|
||||
import { generatePath } from "react-router-dom";
|
||||
|
||||
import { DEFAULT_REALM, ROOT_PATH, SERVER_URL } from "./constants";
|
||||
|
||||
export function getAccountUrl() {
|
||||
return SERVER_URL + getRootPath();
|
||||
}
|
||||
|
||||
export function getAdminUrl() {
|
||||
return SERVER_URL + "/admin/master/console/";
|
||||
}
|
||||
|
||||
export const getRootPath = (realm = DEFAULT_REALM) =>
|
||||
generatePath(ROOT_PATH, { realm });
|
||||
@ -204,40 +204,45 @@ public class AccountConsole implements AccountResourceProvider {
|
||||
|
||||
return propertyValue;
|
||||
}
|
||||
|
||||
|
||||
@GET
|
||||
@Path("index.html")
|
||||
public Response getIndexHtmlRedirect() {
|
||||
return Response.status(302).location(session.getContext().getUri().getRequestUriBuilder().path("../").build()).build();
|
||||
}
|
||||
|
||||
|
||||
private String[] getReferrer() {
|
||||
String referrer = session.getContext().getUri().getQueryParameters().getFirst("referrer");
|
||||
|
||||
if (referrer == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
ClientModel referrerClient = realm.getClientByClientId(referrer);
|
||||
|
||||
if (referrerClient == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String referrerUri = session.getContext().getUri().getQueryParameters().getFirst("referrer_uri");
|
||||
|
||||
ClientModel referrerClient = realm.getClientByClientId(referrer);
|
||||
if (referrerClient != null) {
|
||||
if (referrerUri != null) {
|
||||
referrerUri = RedirectUtils.verifyRedirectUri(session, referrerUri, referrerClient);
|
||||
} else {
|
||||
referrerUri = ResolveRelative.resolveRelativeUri(session, referrerClient.getRootUrl(), referrerClient.getBaseUrl());
|
||||
}
|
||||
|
||||
if (referrerUri != null) {
|
||||
String referrerName = referrerClient.getName();
|
||||
if (Validation.isBlank(referrerName)) {
|
||||
referrerName = referrer;
|
||||
}
|
||||
return new String[]{referrer, referrerName, referrerUri};
|
||||
}
|
||||
if (referrerUri != null) {
|
||||
referrerUri = RedirectUtils.verifyRedirectUri(session, referrerUri, referrerClient);
|
||||
} else {
|
||||
referrerUri = ResolveRelative.resolveRelativeUri(session, referrerClient.getRootUrl(), referrerClient.getBaseUrl());
|
||||
}
|
||||
|
||||
return null;
|
||||
if (referrerUri == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String referrerName = referrerClient.getName();
|
||||
|
||||
if (Validation.isBlank(referrerName)) {
|
||||
referrerName = referrer;
|
||||
}
|
||||
|
||||
return new String[]{referrer, referrerName, referrerUri};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user