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();
|
||||
createRealmPage.fillRealmName(newRealmName).createRealm();
|
||||
|
||||
const fetchUrl = "/admin/realms?briefRepresentation=true";
|
||||
cy.intercept(fetchUrl).as("fetch");
|
||||
|
||||
masthead.checkNotificationMessage("Realm created successfully");
|
||||
|
||||
cy.wait(["@fetch"]);
|
||||
|
||||
sidebarPage.goToCreateRealm();
|
||||
createRealmPage.fillRealmName(editedRealmName).createRealm();
|
||||
|
||||
masthead.checkNotificationMessage("Realm created successfully");
|
||||
|
||||
cy.wait(["@fetch"]);
|
||||
|
||||
// Show current realms
|
||||
sidebarPage.showCurrentRealms(4);
|
||||
});
|
||||
|
|
|
@ -96,12 +96,8 @@ export const RealmSelector = () => {
|
|||
})
|
||||
.concat(
|
||||
realms
|
||||
.filter(
|
||||
(r) => !recentRealms.includes(r.realm!) || r.realm === realm,
|
||||
)
|
||||
.map((r) => {
|
||||
return { name: r.realm!, used: false };
|
||||
}),
|
||||
.filter((name) => !recentRealms.includes(name) || name === realm)
|
||||
.map((name) => ({ name, used: false })),
|
||||
),
|
||||
[recentRealms, realm, realms],
|
||||
);
|
||||
|
@ -164,15 +160,15 @@ export const RealmSelector = () => {
|
|||
</DropdownToggle>
|
||||
}
|
||||
dropdownItems={(realms.length !== 0
|
||||
? realms.map((r) => (
|
||||
? realms.map((name) => (
|
||||
<DropdownItem
|
||||
key={r.realm}
|
||||
key={name}
|
||||
component={
|
||||
<Link
|
||||
to={toDashboard({ realm: r.realm! })}
|
||||
to={toDashboard({ realm: name })}
|
||||
onClick={() => setOpen(false)}
|
||||
>
|
||||
<RealmText value={r.realm!} />
|
||||
<RealmText value={name} />
|
||||
</Link>
|
||||
}
|
||||
/>
|
||||
|
@ -187,7 +183,7 @@ export const RealmSelector = () => {
|
|||
{whoAmI.canCreateRealm() && (
|
||||
<>
|
||||
<Divider key="divider" />
|
||||
<DropdownItem key="add">
|
||||
<DropdownItem key="add" component="div">
|
||||
<AddRealm onClick={() => setOpen(false)} />
|
||||
</DropdownItem>
|
||||
</>
|
||||
|
|
|
@ -1,16 +1,14 @@
|
|||
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 { createNamedContext, useRequiredContext } from "ui-shared";
|
||||
|
||||
import { adminClient } from "../admin-client";
|
||||
import { keycloak } from "../keycloak";
|
||||
import { useFetch } from "../utils/useFetch";
|
||||
import { fetchAdminUI } from "./auth/admin-ui-endpoint";
|
||||
|
||||
type RealmsContextProps = {
|
||||
/** A list of all the realms. */
|
||||
realms: RealmRepresentation[];
|
||||
realms: string[];
|
||||
/** Refreshes the realms with the latest information. */
|
||||
refresh: () => Promise<void>;
|
||||
};
|
||||
|
@ -21,11 +19,11 @@ export const RealmsContext = createNamedContext<RealmsContextProps | undefined>(
|
|||
);
|
||||
|
||||
export const RealmsProvider = ({ children }: PropsWithChildren) => {
|
||||
const [realms, setRealms] = useState<RealmRepresentation[]>([]);
|
||||
const [realms, setRealms] = useState<string[]>([]);
|
||||
const [refreshCount, setRefreshCount] = useState(0);
|
||||
|
||||
function updateRealms(realms: RealmRepresentation[]) {
|
||||
setRealms(sortBy(realms, "realm"));
|
||||
function updateRealms(realms: string[]) {
|
||||
setRealms(realms.sort());
|
||||
}
|
||||
|
||||
useFetch(
|
||||
|
@ -36,7 +34,7 @@ export const RealmsProvider = ({ children }: PropsWithChildren) => {
|
|||
}
|
||||
|
||||
try {
|
||||
return await adminClient.realms.find({ briefRepresentation: true });
|
||||
return await fetchAdminUI<string[]>("ui-ext/realms", {});
|
||||
} catch (error) {
|
||||
if (error instanceof NetworkError && error.response.status < 500) {
|
||||
return [];
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import RealmRepresentation from "@keycloak/keycloak-admin-client/lib/defs/realmRepresentation";
|
||||
import { PropsWithChildren, useEffect, useMemo } from "react";
|
||||
|
||||
import {
|
||||
|
@ -44,13 +43,12 @@ export const RecentRealmsProvider = ({ children }: PropsWithChildren) => {
|
|||
|
||||
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 (realms.length === 0) {
|
||||
return realmNames;
|
||||
return storedRealms;
|
||||
}
|
||||
|
||||
// Only keep realm names that actually still exist.
|
||||
const exisingRealmNames = realms.map(({ realm }) => realm!);
|
||||
return realmNames.filter((realm) => exisingRealmNames.includes(realm));
|
||||
return storedRealms.filter((realm) => realms.includes(realm));
|
||||
}
|
||||
|
|
|
@ -50,4 +50,8 @@ public final class AdminExtResource {
|
|||
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