Add APIResponse annotations to Realm resources

Closes #36907

Signed-off-by: Borja Domínguez Vázquez <borja.dominguez@hotmail.com>
Signed-off-by: Alexander Schwartz <aschwart@redhat.com>
Co-authored-by: Alexander Schwartz <aschwart@redhat.com>
This commit is contained in:
Borja Domínguez
2025-03-17 21:17:35 +01:00
committed by GitHub
parent 0e549047d6
commit 7d7e153fb2
3 changed files with 227 additions and 32 deletions
@@ -36,8 +36,13 @@ import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.core.Response.Status;
import jakarta.ws.rs.core.StreamingOutput;
import org.eclipse.microprofile.openapi.annotations.Operation;
import org.eclipse.microprofile.openapi.annotations.enums.SchemaType;
import org.eclipse.microprofile.openapi.annotations.extensions.Extension;
import org.eclipse.microprofile.openapi.annotations.media.Content;
import org.eclipse.microprofile.openapi.annotations.media.Schema;
import org.eclipse.microprofile.openapi.annotations.parameters.Parameter;
import org.eclipse.microprofile.openapi.annotations.responses.APIResponse;
import org.eclipse.microprofile.openapi.annotations.responses.APIResponses;
import org.eclipse.microprofile.openapi.annotations.tags.Tag;
import org.jboss.logging.Logger;
import org.jboss.resteasy.reactive.NoCache;
@@ -157,7 +162,12 @@ public class RealmAdminResource {
@POST
@Produces(MediaType.APPLICATION_JSON)
@Tag(name = KeycloakOpenAPI.Admin.Tags.REALMS_ADMIN)
@Operation( summary = "Base path for importing clients under this realm.")
@Operation(summary = "Base path for importing clients under this realm.")
@APIResponses(value = {
@APIResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = ClientRepresentation.class))),
@APIResponse(responseCode = "403", description = "Forbidden"),
@APIResponse(responseCode = "404", description = "Not Found")
})
public ClientRepresentation convertClientDescription(String description) {
auth.clients().requireManage();
@@ -232,7 +242,11 @@ public class RealmAdminResource {
@Produces(MediaType.APPLICATION_JSON)
@Path("default-default-client-scopes")
@Tag(name = KeycloakOpenAPI.Admin.Tags.REALMS_ADMIN)
@Operation( summary = "Get realm default client scopes. Only name and ids are returned.")
@Operation(summary = "Get realm default client scopes. Only name and ids are returned.")
@APIResponses(value = {
@APIResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = ClientScopeRepresentation.class, type = SchemaType.ARRAY))),
@APIResponse(responseCode = "403", description = "Forbidden")
})
public Stream<ClientScopeRepresentation> getDefaultDefaultClientScopes() {
return getDefaultClientScopes(true);
}
@@ -249,12 +263,16 @@ public class RealmAdminResource {
});
}
@PUT
@NoCache
@Path("default-default-client-scopes/{clientScopeId}")
@Tag(name = KeycloakOpenAPI.Admin.Tags.REALMS_ADMIN)
@Operation()
@APIResponses(value = {
@APIResponse(responseCode = "204", description = "No Content"),
@APIResponse(responseCode = "403", description = "Forbidden"),
@APIResponse(responseCode = "404", description = "Not Found")
})
public void addDefaultDefaultClientScope(@PathParam("clientScopeId") String clientScopeId) {
addDefaultClientScope(clientScopeId,true);
}
@@ -271,12 +289,16 @@ public class RealmAdminResource {
adminEvent.operation(OperationType.CREATE).resource(ResourceType.CLIENT_SCOPE).resourcePath(session.getContext().getUri()).success();
}
@DELETE
@NoCache
@Path("default-default-client-scopes/{clientScopeId}")
@Tag(name = KeycloakOpenAPI.Admin.Tags.REALMS_ADMIN)
@Operation()
@APIResponses(value = {
@APIResponse(responseCode = "204", description = "No Content"),
@APIResponse(responseCode = "403", description = "Forbidden"),
@APIResponse(responseCode = "404", description = "Not Found")
})
public void removeDefaultDefaultClientScope(@PathParam("clientScopeId") String clientScopeId) {
auth.clients().requireManageClientScopes();
@@ -289,7 +311,6 @@ public class RealmAdminResource {
adminEvent.operation(OperationType.DELETE).resource(ResourceType.CLIENT_SCOPE).resourcePath(session.getContext().getUri()).success();
}
/**
* Get realm optional client scopes. Only name and ids are returned.
*
@@ -300,7 +321,11 @@ public class RealmAdminResource {
@Produces(MediaType.APPLICATION_JSON)
@Path("default-optional-client-scopes")
@Tag(name = KeycloakOpenAPI.Admin.Tags.REALMS_ADMIN)
@Operation( summary = "Get realm optional client scopes. Only name and ids are returned.")
@Operation(summary = "Get realm optional client scopes. Only name and ids are returned.")
@APIResponses(value = {
@APIResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = ClientScopeRepresentation.class, type = SchemaType.ARRAY))),
@APIResponse(responseCode = "403", description = "Forbidden")
})
public Stream<ClientScopeRepresentation> getDefaultOptionalClientScopes() {
return getDefaultClientScopes(false);
}
@@ -310,6 +335,11 @@ public class RealmAdminResource {
@Path("default-optional-client-scopes/{clientScopeId}")
@Tag(name = KeycloakOpenAPI.Admin.Tags.REALMS_ADMIN)
@Operation()
@APIResponses(value = {
@APIResponse(responseCode = "204", description = "No Content"),
@APIResponse(responseCode = "403", description = "Forbidden"),
@APIResponse(responseCode = "404", description = "Not Found")
})
public void addDefaultOptionalClientScope(@PathParam("clientScopeId") String clientScopeId) {
addDefaultClientScope(clientScopeId, false);
}
@@ -319,6 +349,11 @@ public class RealmAdminResource {
@Path("default-optional-client-scopes/{clientScopeId}")
@Tag(name = KeycloakOpenAPI.Admin.Tags.REALMS_ADMIN)
@Operation()
@APIResponses(value = {
@APIResponse(responseCode = "204", description = "No Content"),
@APIResponse(responseCode = "403", description = "Forbidden"),
@APIResponse(responseCode = "404", description = "Not Found")
})
public void removeDefaultOptionalClientScope(@PathParam("clientScopeId") String clientScopeId) {
removeDefaultDefaultClientScope(clientScopeId);
}
@@ -369,7 +404,11 @@ public class RealmAdminResource {
@NoCache
@Produces(MediaType.APPLICATION_JSON)
@Tag(name = KeycloakOpenAPI.Admin.Tags.REALMS_ADMIN)
@Operation( summary = "Get the top-level representation of the realm It will not include nested information like User and Client representations.")
@Operation(summary = "Get the top-level representation of the realm It will not include nested information like User and Client representations.")
@APIResponses(value = {
@APIResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = RealmRepresentation.class))),
@APIResponse(responseCode = "403", description = "Forbidden")
})
public RealmRepresentation getRealm() {
if (auth.realm().canViewRealm()) {
return ModelToRepresentation.toRepresentation(session, realm, false);
@@ -404,8 +443,16 @@ public class RealmAdminResource {
@PUT
@Consumes(MediaType.APPLICATION_JSON)
@Tag(name = KeycloakOpenAPI.Admin.Tags.REALMS_ADMIN)
@Operation( summary = "Update the top-level information of the realm Any user, roles or client information in the representation will be ignored.",
@Operation(summary = "Update the top-level information of the realm Any user, roles or client information in the representation will be ignored.",
description = "This will only update top-level attributes of the realm.")
@APIResponses(value = {
@APIResponse(responseCode = "204", description = "No Content"),
@APIResponse(responseCode = "400", description = "Bad Request"),
@APIResponse(responseCode = "403", description = "Forbidden"),
@APIResponse(responseCode = "404", description = "Not Found"),
@APIResponse(responseCode = "409", description = "Conflict"),
@APIResponse(responseCode = "500", description = "Internal Server Error")
})
public Response updateRealm(final RealmRepresentation rep) {
auth.realm().requireManageRealm();
@@ -482,7 +529,13 @@ public class RealmAdminResource {
*/
@DELETE
@Tag(name = KeycloakOpenAPI.Admin.Tags.REALMS_ADMIN)
@Operation( summary = "Delete the realm")
@Operation(summary = "Delete the realm")
@APIResponses(value = {
@APIResponse(responseCode = "204", description = "No Content"),
@APIResponse(responseCode = "400", description = "Bad Request"),
@APIResponse(responseCode = "403", description = "Forbidden"),
@APIResponse(responseCode = "404", description = "Not Found")
})
public void deleteRealm() {
auth.realm().requireManageRealm();
@@ -517,6 +570,10 @@ public class RealmAdminResource {
@Path("users-management-permissions")
@Tag(name = KeycloakOpenAPI.Admin.Tags.REALMS_ADMIN)
@Operation()
@APIResponses(value = {
@APIResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = ManagementPermissionReference.class))),
@APIResponse(responseCode = "403", description = "Forbidden")
})
public ManagementPermissionReference getUserMgmtPermissions() {
ProfileHelper.requireFeature(Profile.Feature.ADMIN_FINE_GRAINED_AUTHZ);
auth.realm().requireViewRealm();
@@ -527,7 +584,6 @@ public class RealmAdminResource {
} else {
return new ManagementPermissionReference();
}
}
@PUT
@@ -537,6 +593,10 @@ public class RealmAdminResource {
@Path("users-management-permissions")
@Tag(name = KeycloakOpenAPI.Admin.Tags.REALMS_ADMIN)
@Operation()
@APIResponses(value = {
@APIResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = ManagementPermissionReference.class))),
@APIResponse(responseCode = "403", description = "Forbidden")
})
public ManagementPermissionReference setUsersManagementPermissionsEnabled(ManagementPermissionReference ref) {
ProfileHelper.requireFeature(Profile.Feature.ADMIN_FINE_GRAINED_AUTHZ);
auth.realm().requireManageRealm();
@@ -601,7 +661,11 @@ public class RealmAdminResource {
@Produces(MediaType.APPLICATION_JSON)
@POST
@Tag(name = KeycloakOpenAPI.Admin.Tags.REALMS_ADMIN)
@Operation( summary = "Push the realm's revocation policy to any client that has an admin url associated with it.")
@Operation(summary = "Push the realm's revocation policy to any client that has an admin url associated with it.")
@APIResponses(value = {
@APIResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = GlobalRequestResult.class))),
@APIResponse(responseCode = "403", description = "Forbidden")
})
public GlobalRequestResult pushRevocation() {
auth.realm().requireManageRealm();
@@ -611,7 +675,7 @@ public class RealmAdminResource {
}
/**
* Removes all user sessions. Any client that has an admin url will also be told to invalidate any sessions
* Removes all user sessions. Any client that has an admin url will also be told to invalidate any sessions
* they have.
*
*/
@@ -619,7 +683,11 @@ public class RealmAdminResource {
@POST
@Produces(MediaType.APPLICATION_JSON)
@Tag(name = KeycloakOpenAPI.Admin.Tags.REALMS_ADMIN)
@Operation( summary = "Removes all user sessions.", description = "Any client that has an admin url will also be told to invalidate any sessions they have.")
@Operation(summary = "Removes all user sessions.", description = "Any client that has an admin url will also be told to invalidate any sessions they have.")
@APIResponses(value = {
@APIResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = GlobalRequestResult.class))),
@APIResponse(responseCode = "403", description = "Forbidden")
})
public GlobalRequestResult logoutAll() {
auth.users().requireManage();
@@ -638,7 +706,12 @@ public class RealmAdminResource {
@Path("sessions/{session}")
@DELETE
@Tag(name = KeycloakOpenAPI.Admin.Tags.REALMS_ADMIN)
@Operation( summary = "Remove a specific user session.", description = "Any client that has an admin url will also be told to invalidate this particular session.")
@Operation(summary = "Remove a specific user session.", description = "Any client that has an admin url will also be told to invalidate this particular session.")
@APIResponses(value = {
@APIResponse(responseCode = "204", description = "No Content"),
@APIResponse(responseCode = "403", description = "Forbidden"),
@APIResponse(responseCode = "404", description = "Not Found")
})
public void deleteSession(@PathParam("session") String sessionId, @DefaultValue("false") @QueryParam("isOffline") boolean offline) {
auth.users().requireManage();
@@ -667,8 +740,12 @@ public class RealmAdminResource {
@NoCache
@Produces(MediaType.APPLICATION_JSON)
@Tag(name = KeycloakOpenAPI.Admin.Tags.REALMS_ADMIN)
@Operation( summary = "Get client session stats Returns a JSON map.",
@Operation(summary = "Get client session stats Returns a JSON map.",
description = "The key is the client id, the value is the number of sessions that currently are active with that client. Only clients that actually have a session associated with them will be in this map.")
@APIResponses(value = {
@APIResponse(responseCode = "200", description = "OK"),
@APIResponse(responseCode = "403", description = "Forbidden")
})
public Stream<Map<String, String>> getClientSessionStats() {
auth.realm().requireViewRealm();
@@ -720,7 +797,11 @@ public class RealmAdminResource {
@Path("events/config")
@Produces(MediaType.APPLICATION_JSON)
@Tag(name = KeycloakOpenAPI.Admin.Tags.REALMS_ADMIN)
@Operation( summary = "Get the events provider configuration Returns JSON object with events provider configuration")
@Operation(summary = "Get the events provider configuration Returns JSON object with events provider configuration")
@APIResponses(value = {
@APIResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = RealmEventsConfigRepresentation.class))),
@APIResponse(responseCode = "403", description = "Forbidden")
})
public RealmEventsConfigRepresentation getRealmEventsConfig() {
auth.realm().requireViewEvents();
@@ -747,6 +828,10 @@ public class RealmAdminResource {
@Consumes(MediaType.APPLICATION_JSON)
@Tag(name = KeycloakOpenAPI.Admin.Tags.REALMS_ADMIN)
@Operation( description = "Update the events provider Change the events provider and/or its configuration")
@APIResponses(value = {
@APIResponse(responseCode = "204", description = "No Content"),
@APIResponse(responseCode = "403", description = "Forbidden")
})
public void updateRealmEventsConfig(final RealmEventsConfigRepresentation rep) {
auth.realm().requireManageEvents();
@@ -779,7 +864,12 @@ public class RealmAdminResource {
@NoCache
@Produces(MediaType.APPLICATION_JSON)
@Tag(name = KeycloakOpenAPI.Admin.Tags.REALMS_ADMIN)
@Operation( summary = "Get events Returns all events, or filters them based on URL query parameters listed here")
@Operation(summary = "Get events Returns all events, or filters them based on URL query parameters listed here")
@APIResponses(value = {
@APIResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = EventRepresentation.class, type = SchemaType.ARRAY))),
@APIResponse(responseCode = "400", description = "Bad Request"),
@APIResponse(responseCode = "403", description = "Forbidden")
})
public Stream<EventRepresentation> getEvents(@Parameter(description = "The types of events to return") @QueryParam("type") List<String> types,
@Parameter(description = "App or oauth client name") @QueryParam("client") String client,
@Parameter(description = "User id") @QueryParam("user") String user,
@@ -874,7 +964,12 @@ public class RealmAdminResource {
@NoCache
@Produces(MediaType.APPLICATION_JSON)
@Tag(name = KeycloakOpenAPI.Admin.Tags.REALMS_ADMIN)
@Operation( summary = "Get admin events Returns all admin events, or filters events based on URL query parameters listed here")
@Operation(summary = "Get admin events Returns all admin events, or filters events based on URL query parameters listed here")
@APIResponses(value = {
@APIResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = AdminEventRepresentation.class, type = SchemaType.ARRAY))),
@APIResponse(responseCode = "400", description = "Bad Request"),
@APIResponse(responseCode = "403", description = "Forbidden")
})
public Stream<AdminEventRepresentation> getEvents(@QueryParam("operationTypes") List<String> operationTypes, @QueryParam("authRealm") String authRealm, @QueryParam("authClient") String authClient,
@Parameter(description = "user id") @QueryParam("authUser") String authUser, @QueryParam("authIpAddress") String authIpAddress,
@QueryParam("resourcePath") String resourcePath,
@@ -970,7 +1065,11 @@ public class RealmAdminResource {
@Path("events")
@DELETE
@Tag(name = KeycloakOpenAPI.Admin.Tags.REALMS_ADMIN)
@Operation( summary = "Delete all events")
@Operation(summary = "Delete all events")
@APIResponses(value = {
@APIResponse(responseCode = "204", description = "No Content"),
@APIResponse(responseCode = "403", description = "Forbidden")
})
public void clearEvents() {
auth.realm().requireManageEvents();
@@ -985,7 +1084,11 @@ public class RealmAdminResource {
@Path("admin-events")
@DELETE
@Tag(name = KeycloakOpenAPI.Admin.Tags.REALMS_ADMIN)
@Operation( summary = "Delete all admin events")
@Operation(summary = "Delete all admin events")
@APIResponses(value = {
@APIResponse(responseCode = "204", description = "No Content"),
@APIResponse(responseCode = "403", description = "Forbidden")
})
public void clearAdminEvents() {
auth.realm().requireManageEvents();
@@ -1006,7 +1109,11 @@ public class RealmAdminResource {
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
@Deprecated
@Tag(name = KeycloakOpenAPI.Admin.Tags.REALMS_ADMIN)
@Operation( summary = "Test SMTP connection with current logged in user")
@Operation(summary = "Test SMTP connection with current logged in user")
@APIResponses(value = {
@APIResponse(responseCode = "204", description = "No Content"),
@APIResponse(responseCode = "500", description = "Internal Server Error")
})
public Response testSMTPConnection(final @Parameter(description = "SMTP server configuration") @FormParam("config") String config) throws Exception {
Map<String, String> settings = readValue(config, new TypeReference<Map<String, String>>() {
});
@@ -1019,6 +1126,10 @@ public class RealmAdminResource {
@Consumes(MediaType.APPLICATION_JSON)
@Tag(name = KeycloakOpenAPI.Admin.Tags.REALMS_ADMIN)
@Operation()
@APIResponses(value = {
@APIResponse(responseCode = "204", description = "No Content"),
@APIResponse(responseCode = "500", description = "Internal Server Error")
})
public Response testSMTPConnection(Map<String, String> settings) throws Exception {
try {
UserModel user = auth.adminAuth().getUser();
@@ -1053,17 +1164,27 @@ public class RealmAdminResource {
@Produces(MediaType.APPLICATION_JSON)
@Path("default-groups")
@Tag(name = KeycloakOpenAPI.Admin.Tags.REALMS_ADMIN)
@Operation( summary = "Get group hierarchy. Only name and ids are returned.")
@Operation(summary = "Get group hierarchy. Only name and ids are returned.")
@APIResponses(value = {
@APIResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = GroupRepresentation.class, type = SchemaType.ARRAY))),
@APIResponse(responseCode = "403", description = "Forbidden")
})
public Stream<GroupRepresentation> getDefaultGroups() {
auth.realm().requireViewRealm();
return realm.getDefaultGroupsStream().map(ModelToRepresentation::groupToBriefRepresentation);
}
@PUT
@NoCache
@Path("default-groups/{groupId}")
@Tag(name = KeycloakOpenAPI.Admin.Tags.REALMS_ADMIN)
@Operation()
@APIResponses(value = {
@APIResponse(responseCode = "204", description = "No Content"),
@APIResponse(responseCode = "403", description = "Forbidden"),
@APIResponse(responseCode = "404", description = "Not Found")
})
public void addDefaultGroup(@PathParam("groupId") String groupId) {
auth.realm().requireManageRealm();
@@ -1082,6 +1203,11 @@ public class RealmAdminResource {
@Path("default-groups/{groupId}")
@Tag(name = KeycloakOpenAPI.Admin.Tags.REALMS_ADMIN)
@Operation()
@APIResponses(value = {
@APIResponse(responseCode = "204", description = "No Content"),
@APIResponse(responseCode = "403", description = "Forbidden"),
@APIResponse(responseCode = "404", description = "Not Found")
})
public void removeDefaultGroup(@PathParam("groupId") String groupId) {
auth.realm().requireManageRealm();
@@ -1095,19 +1221,22 @@ public class RealmAdminResource {
adminEvent.operation(OperationType.DELETE).resource(ResourceType.GROUP).resourcePath(session.getContext().getUri()).success();
}
@Path("groups")
public GroupsResource getGroups() {
return new GroupsResource(realm, session, this.auth, adminEvent);
return new GroupsResource(realm, session, this.auth, adminEvent);
}
@GET
@Path("group-by-path/{path: .*}")
@NoCache
@Produces(MediaType.APPLICATION_JSON)
@Tag(name = KeycloakOpenAPI.Admin.Tags.REALMS_ADMIN)
@Operation()
@APIResponses(value = {
@APIResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = GroupRepresentation.class))),
@APIResponse(responseCode = "403", description = "Forbidden"),
@APIResponse(responseCode = "404", description = "Not Found")
})
public GroupRepresentation getGroupByPath(@PathParam("path") String path) {
GroupModel found = KeycloakModelUtils.findGroupByPath(session, realm, path);
if (found == null) {
@@ -1128,7 +1257,12 @@ public class RealmAdminResource {
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
@Tag(name = KeycloakOpenAPI.Admin.Tags.REALMS_ADMIN)
@Operation( summary = "Partial import from a JSON file to an existing realm.")
@Operation(summary = "Partial import from a JSON file to an existing realm.")
@APIResponses(value = {
@APIResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = PartialImportResults.class))),
@APIResponse(responseCode = "403", description = "Forbidden"),
@APIResponse(responseCode = "409", description = "Conflict")
})
public Response partialImport(InputStream requestBody) {
auth.realm().requireManageRealm();
try {
@@ -1182,9 +1316,13 @@ public class RealmAdminResource {
@Produces(MediaType.APPLICATION_JSON)
@POST
@Tag(name = KeycloakOpenAPI.Admin.Tags.REALMS_ADMIN)
@Operation( summary = "Partial export of existing realm into a JSON file.")
@Operation(summary = "Partial export of existing realm into a JSON file.")
@APIResponses(value = {
@APIResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = RealmRepresentation.class))),
@APIResponse(responseCode = "403", description = "Forbidden")
})
public Response partialExport(@QueryParam("exportGroupsAndRoles") Boolean exportGroupsAndRoles,
@QueryParam("exportClients") Boolean exportClients) {
@QueryParam("exportClients") Boolean exportClients) {
auth.realm().requireManageRealm();
boolean groupsAndRolesExported = exportGroupsAndRoles != null && exportGroupsAndRoles;
@@ -1230,6 +1368,10 @@ public class RealmAdminResource {
@Produces(jakarta.ws.rs.core.MediaType.APPLICATION_JSON)
@Tag(name = KeycloakOpenAPI.Admin.Tags.REALMS_ADMIN)
@Operation()
@APIResponses(value = {
@APIResponse(responseCode = "200", description = "OK"),
@APIResponse(responseCode = "403", description = "Forbidden")
})
public Stream<String> getCredentialRegistrators(){
auth.realm().requireViewRealm();
return session.getContext().getRealm().getRequiredActionProvidersStream()
@@ -20,8 +20,12 @@ package org.keycloak.services.resources.admin;
import com.fasterxml.jackson.core.type.TypeReference;
import org.eclipse.microprofile.openapi.annotations.Operation;
import org.eclipse.microprofile.openapi.annotations.enums.SchemaType;
import org.eclipse.microprofile.openapi.annotations.extensions.Extension;
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.eclipse.microprofile.openapi.annotations.responses.APIResponses;
import org.eclipse.microprofile.openapi.annotations.tags.Tag;
import org.keycloak.http.FormPartValue;
import org.keycloak.models.KeycloakSession;
@@ -72,6 +76,11 @@ public class RealmLocalizationResource {
@Consumes(MediaType.TEXT_PLAIN)
@Tag(name = KeycloakOpenAPI.Admin.Tags.REALMS_ADMIN)
@Operation()
@APIResponses(value = {
@APIResponse(responseCode = "204", description = "No Content"),
@APIResponse(responseCode = "400", description = "Bad Request"),
@APIResponse(responseCode = "403", description = "Forbidden")
})
public void saveRealmLocalizationText(@PathParam("locale") String locale, @PathParam("key") String key,
String text) {
this.auth.realm().requireManageRealm();
@@ -92,8 +101,12 @@ public class RealmLocalizationResource {
@Path("{locale}")
@Consumes(MediaType.MULTIPART_FORM_DATA)
@Tag(name = KeycloakOpenAPI.Admin.Tags.REALMS_ADMIN)
@Operation( summary = "Import localization from uploaded JSON file")
@APIResponse(responseCode = "204", description = "No Content")
@Operation(summary = "Import localization from uploaded JSON file")
@APIResponses(value = {
@APIResponse(responseCode = "204", description = "No Content"),
@APIResponse(responseCode = "400", description = "Bad Request"),
@APIResponse(responseCode = "403", description = "Forbidden")
})
public void createOrUpdateRealmLocalizationTextsFromFile(@PathParam("locale") String locale) {
this.auth.realm().requireManageRealm();
@@ -116,7 +129,10 @@ public class RealmLocalizationResource {
@Consumes(MediaType.APPLICATION_JSON)
@Tag(name = KeycloakOpenAPI.Admin.Tags.REALMS_ADMIN)
@Operation()
@APIResponse(responseCode = "204", description = "No Content")
@APIResponses(value = {
@APIResponse(responseCode = "204", description = "No Content"),
@APIResponse(responseCode = "403", description = "Forbidden")
})
public void createOrUpdateRealmLocalizationTexts(@PathParam("locale") String locale,
Map<String, String> localizationTexts) {
this.auth.realm().requireManageRealm();
@@ -127,6 +143,11 @@ public class RealmLocalizationResource {
@DELETE
@Tag(name = KeycloakOpenAPI.Admin.Tags.REALMS_ADMIN)
@Operation()
@APIResponses(value = {
@APIResponse(responseCode = "204", description = "No Content"),
@APIResponse(responseCode = "403", description = "Forbidden"),
@APIResponse(responseCode = "404", description = "Not Found")
})
public void deleteRealmLocalizationTexts(@PathParam("locale") String locale) {
this.auth.realm().requireManageRealm();
if(!realm.removeRealmLocalizationTexts(locale)) {
@@ -138,6 +159,11 @@ public class RealmLocalizationResource {
@DELETE
@Tag(name = KeycloakOpenAPI.Admin.Tags.REALMS_ADMIN)
@Operation()
@APIResponses(value = {
@APIResponse(responseCode = "204", description = "No Content"),
@APIResponse(responseCode = "403", description = "Forbidden"),
@APIResponse(responseCode = "404", description = "Not Found")
})
public void deleteRealmLocalizationText(@PathParam("locale") String locale, @PathParam("key") String key) {
this.auth.realm().requireManageRealm();
if (!session.realms().deleteLocalizationText(realm, locale, key)) {
@@ -149,6 +175,10 @@ public class RealmLocalizationResource {
@Produces(MediaType.APPLICATION_JSON)
@Tag(name = KeycloakOpenAPI.Admin.Tags.REALMS_ADMIN)
@Operation()
@APIResponses(value = {
@APIResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = String.class, type = SchemaType.ARRAY))),
@APIResponse(responseCode = "403", description = "Forbidden")
})
public Stream<String> getRealmLocalizationLocales() {
auth.requireAnyAdminRole();
@@ -160,6 +190,10 @@ public class RealmLocalizationResource {
@Produces(MediaType.APPLICATION_JSON)
@Tag(name = KeycloakOpenAPI.Admin.Tags.REALMS_ADMIN)
@Operation()
@APIResponses(value = {
@APIResponse(responseCode = "200", description = "OK"),
@APIResponse(responseCode = "403", description = "Forbidden")
})
public Map<String, String> getRealmLocalizationTexts(@PathParam("locale") String locale,
@Deprecated @QueryParam("useRealmDefaultLocaleFallback") Boolean useFallback) {
if (!AdminPermissions.realms(session, auth.adminAuth()).isAdmin()) {
@@ -186,6 +220,11 @@ public class RealmLocalizationResource {
@Produces(MediaType.TEXT_PLAIN)
@Tag(name = KeycloakOpenAPI.Admin.Tags.REALMS_ADMIN)
@Operation()
@APIResponses(value = {
@APIResponse(responseCode = "200", description = "OK"),
@APIResponse(responseCode = "403", description = "Forbidden"),
@APIResponse(responseCode = "404", description = "Not Found")
})
public String getRealmLocalizationText(@PathParam("locale") String locale, @PathParam("key") String key) {
auth.requireAnyAdminRole();
@@ -17,9 +17,13 @@
package org.keycloak.services.resources.admin;
import org.eclipse.microprofile.openapi.annotations.Operation;
import org.eclipse.microprofile.openapi.annotations.enums.SchemaType;
import org.eclipse.microprofile.openapi.annotations.extensions.Extension;
import org.eclipse.microprofile.openapi.annotations.media.Content;
import org.eclipse.microprofile.openapi.annotations.media.Schema;
import org.eclipse.microprofile.openapi.annotations.parameters.Parameter;
import org.eclipse.microprofile.openapi.annotations.responses.APIResponse;
import org.eclipse.microprofile.openapi.annotations.responses.APIResponses;
import org.eclipse.microprofile.openapi.annotations.tags.Tag;
import org.jboss.logging.Logger;
import org.jboss.resteasy.reactive.NoCache;
@@ -108,6 +112,10 @@ public class RealmsAdminResource {
@Produces(MediaType.APPLICATION_JSON)
@Tag(name = KeycloakOpenAPI.Admin.Tags.REALMS_ADMIN)
@Operation(summary = "Get accessible realms Returns a list of accessible realms. The list is filtered based on what realms the caller is allowed to view.")
@APIResponses(value = {
@APIResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = RealmRepresentation.class, type = SchemaType.ARRAY))),
@APIResponse(responseCode = "403", description = "Forbidden")
})
public Stream<RealmRepresentation> getRealms(@DefaultValue("false") @QueryParam("briefRepresentation") boolean briefRepresentation) {
Stream<RealmRepresentation> realms = session.realms().getRealmsStream()
.map(realm -> toRealmRep(realm, briefRepresentation))
@@ -136,7 +144,13 @@ public class RealmsAdminResource {
@Consumes(MediaType.APPLICATION_JSON)
@Tag(name = KeycloakOpenAPI.Admin.Tags.REALMS_ADMIN)
@Operation(summary = "Import a realm. Imports a realm from a full representation of that realm.", description = "Realm name must be unique.")
@APIResponse(responseCode = "201", description = "Created")
@APIResponses(value = {
@APIResponse(responseCode = "201", description = "Created"),
@APIResponse(responseCode = "400", description = "Bad Request"),
@APIResponse(responseCode = "403", description = "Forbidden"),
@APIResponse(responseCode = "409", description = "Conflict"),
@APIResponse(responseCode = "500", description = "Internal Server Error")
})
public Response importRealm(InputStream requestBody) {
AdminPermissions.realms(session, auth).requireCreateRealm();