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:
Erik Jan de Wit 2023-07-18 09:52:06 +02:00 committed by GitHub
parent 03716ed452
commit e24d51edca
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 69 additions and 31 deletions

View file

@ -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);
});

View file

@ -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>
</>

View file

@ -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 [];

View file

@ -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));
}

View file

@ -50,4 +50,8 @@ public final class AdminExtResource {
return new SessionsResource(session, realm, auth);
}
@Path("/realms")
public RealmResource realms() {
return new RealmResource(session);
}
}

View file

@ -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());
}
}