only use the names of the realms (#21576)
* only use the names of the realms fixes: #21555 * fixed merge error * fixed test * removed braces from arrow function
This commit is contained in:
parent
03716ed452
commit
e24d51edca
6 changed files with 69 additions and 31 deletions
|
@ -95,20 +95,13 @@ describe("Realm tests", () => {
|
||||||
sidebarPage.goToCreateRealm();
|
sidebarPage.goToCreateRealm();
|
||||||
createRealmPage.fillRealmName(newRealmName).createRealm();
|
createRealmPage.fillRealmName(newRealmName).createRealm();
|
||||||
|
|
||||||
const fetchUrl = "/admin/realms?briefRepresentation=true";
|
|
||||||
cy.intercept(fetchUrl).as("fetch");
|
|
||||||
|
|
||||||
masthead.checkNotificationMessage("Realm created successfully");
|
masthead.checkNotificationMessage("Realm created successfully");
|
||||||
|
|
||||||
cy.wait(["@fetch"]);
|
|
||||||
|
|
||||||
sidebarPage.goToCreateRealm();
|
sidebarPage.goToCreateRealm();
|
||||||
createRealmPage.fillRealmName(editedRealmName).createRealm();
|
createRealmPage.fillRealmName(editedRealmName).createRealm();
|
||||||
|
|
||||||
masthead.checkNotificationMessage("Realm created successfully");
|
masthead.checkNotificationMessage("Realm created successfully");
|
||||||
|
|
||||||
cy.wait(["@fetch"]);
|
|
||||||
|
|
||||||
// Show current realms
|
// Show current realms
|
||||||
sidebarPage.showCurrentRealms(4);
|
sidebarPage.showCurrentRealms(4);
|
||||||
});
|
});
|
||||||
|
|
|
@ -96,12 +96,8 @@ export const RealmSelector = () => {
|
||||||
})
|
})
|
||||||
.concat(
|
.concat(
|
||||||
realms
|
realms
|
||||||
.filter(
|
.filter((name) => !recentRealms.includes(name) || name === realm)
|
||||||
(r) => !recentRealms.includes(r.realm!) || r.realm === realm,
|
.map((name) => ({ name, used: false })),
|
||||||
)
|
|
||||||
.map((r) => {
|
|
||||||
return { name: r.realm!, used: false };
|
|
||||||
}),
|
|
||||||
),
|
),
|
||||||
[recentRealms, realm, realms],
|
[recentRealms, realm, realms],
|
||||||
);
|
);
|
||||||
|
@ -164,15 +160,15 @@ export const RealmSelector = () => {
|
||||||
</DropdownToggle>
|
</DropdownToggle>
|
||||||
}
|
}
|
||||||
dropdownItems={(realms.length !== 0
|
dropdownItems={(realms.length !== 0
|
||||||
? realms.map((r) => (
|
? realms.map((name) => (
|
||||||
<DropdownItem
|
<DropdownItem
|
||||||
key={r.realm}
|
key={name}
|
||||||
component={
|
component={
|
||||||
<Link
|
<Link
|
||||||
to={toDashboard({ realm: r.realm! })}
|
to={toDashboard({ realm: name })}
|
||||||
onClick={() => setOpen(false)}
|
onClick={() => setOpen(false)}
|
||||||
>
|
>
|
||||||
<RealmText value={r.realm!} />
|
<RealmText value={name} />
|
||||||
</Link>
|
</Link>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
@ -187,7 +183,7 @@ export const RealmSelector = () => {
|
||||||
{whoAmI.canCreateRealm() && (
|
{whoAmI.canCreateRealm() && (
|
||||||
<>
|
<>
|
||||||
<Divider key="divider" />
|
<Divider key="divider" />
|
||||||
<DropdownItem key="add">
|
<DropdownItem key="add" component="div">
|
||||||
<AddRealm onClick={() => setOpen(false)} />
|
<AddRealm onClick={() => setOpen(false)} />
|
||||||
</DropdownItem>
|
</DropdownItem>
|
||||||
</>
|
</>
|
||||||
|
|
|
@ -1,16 +1,14 @@
|
||||||
import { NetworkError } from "@keycloak/keycloak-admin-client";
|
import { NetworkError } from "@keycloak/keycloak-admin-client";
|
||||||
import type RealmRepresentation from "@keycloak/keycloak-admin-client/lib/defs/realmRepresentation";
|
|
||||||
import { sortBy } from "lodash-es";
|
|
||||||
import { PropsWithChildren, useCallback, useMemo, useState } from "react";
|
import { PropsWithChildren, useCallback, useMemo, useState } from "react";
|
||||||
import { createNamedContext, useRequiredContext } from "ui-shared";
|
import { createNamedContext, useRequiredContext } from "ui-shared";
|
||||||
|
|
||||||
import { adminClient } from "../admin-client";
|
|
||||||
import { keycloak } from "../keycloak";
|
import { keycloak } from "../keycloak";
|
||||||
import { useFetch } from "../utils/useFetch";
|
import { useFetch } from "../utils/useFetch";
|
||||||
|
import { fetchAdminUI } from "./auth/admin-ui-endpoint";
|
||||||
|
|
||||||
type RealmsContextProps = {
|
type RealmsContextProps = {
|
||||||
/** A list of all the realms. */
|
/** A list of all the realms. */
|
||||||
realms: RealmRepresentation[];
|
realms: string[];
|
||||||
/** Refreshes the realms with the latest information. */
|
/** Refreshes the realms with the latest information. */
|
||||||
refresh: () => Promise<void>;
|
refresh: () => Promise<void>;
|
||||||
};
|
};
|
||||||
|
@ -21,11 +19,11 @@ export const RealmsContext = createNamedContext<RealmsContextProps | undefined>(
|
||||||
);
|
);
|
||||||
|
|
||||||
export const RealmsProvider = ({ children }: PropsWithChildren) => {
|
export const RealmsProvider = ({ children }: PropsWithChildren) => {
|
||||||
const [realms, setRealms] = useState<RealmRepresentation[]>([]);
|
const [realms, setRealms] = useState<string[]>([]);
|
||||||
const [refreshCount, setRefreshCount] = useState(0);
|
const [refreshCount, setRefreshCount] = useState(0);
|
||||||
|
|
||||||
function updateRealms(realms: RealmRepresentation[]) {
|
function updateRealms(realms: string[]) {
|
||||||
setRealms(sortBy(realms, "realm"));
|
setRealms(realms.sort());
|
||||||
}
|
}
|
||||||
|
|
||||||
useFetch(
|
useFetch(
|
||||||
|
@ -36,7 +34,7 @@ export const RealmsProvider = ({ children }: PropsWithChildren) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return await adminClient.realms.find({ briefRepresentation: true });
|
return await fetchAdminUI<string[]>("ui-ext/realms", {});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error instanceof NetworkError && error.response.status < 500) {
|
if (error instanceof NetworkError && error.response.status < 500) {
|
||||||
return [];
|
return [];
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
import RealmRepresentation from "@keycloak/keycloak-admin-client/lib/defs/realmRepresentation";
|
|
||||||
import { PropsWithChildren, useEffect, useMemo } from "react";
|
import { PropsWithChildren, useEffect, useMemo } from "react";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
@ -44,13 +43,12 @@ export const RecentRealmsProvider = ({ children }: PropsWithChildren) => {
|
||||||
|
|
||||||
export const useRecentRealms = () => useRequiredContext(RecentRealmsContext);
|
export const useRecentRealms = () => useRequiredContext(RecentRealmsContext);
|
||||||
|
|
||||||
function filterRealmNames(realms: RealmRepresentation[], realmNames: string[]) {
|
function filterRealmNames(realms: string[], storedRealms: string[]) {
|
||||||
// If no realms have been set yet we can't filter out any non-existent realm names.
|
// If no realms have been set yet we can't filter out any non-existent realm names.
|
||||||
if (realms.length === 0) {
|
if (realms.length === 0) {
|
||||||
return realmNames;
|
return storedRealms;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only keep realm names that actually still exist.
|
// Only keep realm names that actually still exist.
|
||||||
const exisingRealmNames = realms.map(({ realm }) => realm!);
|
return storedRealms.filter((realm) => realms.includes(realm));
|
||||||
return realmNames.filter((realm) => exisingRealmNames.includes(realm));
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,4 +50,8 @@ public final class AdminExtResource {
|
||||||
return new SessionsResource(session, realm, auth);
|
return new SessionsResource(session, realm, auth);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Path("/realms")
|
||||||
|
public RealmResource realms() {
|
||||||
|
return new RealmResource(session);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,49 @@
|
||||||
|
package org.keycloak.admin.ui.rest;
|
||||||
|
|
||||||
|
import jakarta.ws.rs.GET;
|
||||||
|
import jakarta.ws.rs.Produces;
|
||||||
|
import jakarta.ws.rs.core.MediaType;
|
||||||
|
import org.eclipse.microprofile.openapi.annotations.Operation;
|
||||||
|
import org.eclipse.microprofile.openapi.annotations.enums.SchemaType;
|
||||||
|
import org.eclipse.microprofile.openapi.annotations.media.Content;
|
||||||
|
import org.eclipse.microprofile.openapi.annotations.media.Schema;
|
||||||
|
import org.eclipse.microprofile.openapi.annotations.responses.APIResponse;
|
||||||
|
import org.jboss.resteasy.annotations.cache.NoCache;
|
||||||
|
import org.keycloak.models.KeycloakSession;
|
||||||
|
import org.keycloak.models.RealmModel;
|
||||||
|
import org.keycloak.services.ForbiddenException;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
import static org.keycloak.utils.StreamsUtil.throwIfEmpty;
|
||||||
|
|
||||||
|
public class RealmResource {
|
||||||
|
private final KeycloakSession session;
|
||||||
|
|
||||||
|
public RealmResource(KeycloakSession session) {
|
||||||
|
this.session = session;
|
||||||
|
}
|
||||||
|
|
||||||
|
@GET
|
||||||
|
@NoCache
|
||||||
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
|
@Operation(
|
||||||
|
summary = "Lists only the names of the realms",
|
||||||
|
description = "Returns a list of realm names based on what the caller is allowed to view"
|
||||||
|
)
|
||||||
|
@APIResponse(
|
||||||
|
responseCode = "200",
|
||||||
|
description = "",
|
||||||
|
content = {@Content(
|
||||||
|
schema = @Schema(
|
||||||
|
implementation = String.class,
|
||||||
|
type = SchemaType.ARRAY
|
||||||
|
)
|
||||||
|
)}
|
||||||
|
)
|
||||||
|
public Stream<String> realmList() {
|
||||||
|
Stream<String> realms = session.realms().getRealmsStream().filter(Objects::nonNull).map(RealmModel::getName);
|
||||||
|
return throwIfEmpty(realms, new ForbiddenException());
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue