diff --git a/server-spi-private/src/main/java/org/keycloak/models/Constants.java b/server-spi-private/src/main/java/org/keycloak/models/Constants.java index 560b63cb6b1..41b077be71a 100755 --- a/server-spi-private/src/main/java/org/keycloak/models/Constants.java +++ b/server-spi-private/src/main/java/org/keycloak/models/Constants.java @@ -130,6 +130,10 @@ public final class Constants { public static final String GENERATE = "GENERATE"; public static final int DEFAULT_MAX_RESULTS = 100; + /** + * Used by {@code DefaultValue} annotation for when a REST endpoints max size default is set by {@link #DEFAULT_MAX_RESULTS}. + */ + public static final String DEFAULT_MAX_RESULTS_STR = "" + DEFAULT_MAX_RESULTS; // Delimiter to be used in the configuration of authenticators (and some other components) in case that we need to save // multiple values into single string diff --git a/services/src/main/java/org/keycloak/authorization/admin/PolicyService.java b/services/src/main/java/org/keycloak/authorization/admin/PolicyService.java index cd05297ab92..ab2488a7786 100644 --- a/services/src/main/java/org/keycloak/authorization/admin/PolicyService.java +++ b/services/src/main/java/org/keycloak/authorization/admin/PolicyService.java @@ -26,6 +26,7 @@ import java.util.stream.Collectors; import jakarta.ws.rs.BadRequestException; import jakarta.ws.rs.Consumes; +import jakarta.ws.rs.DefaultValue; import jakarta.ws.rs.GET; import jakarta.ws.rs.POST; import jakarta.ws.rs.Path; @@ -216,7 +217,7 @@ public class PolicyService { @QueryParam("owner") String owner, @QueryParam("fields") String fields, @QueryParam("first") Integer firstResult, - @QueryParam("max") Integer maxResult) { + @QueryParam("max") @DefaultValue(Constants.DEFAULT_MAX_RESULTS_STR) Integer maxResult) { if (auth != null) { this.auth.realm().requireViewAuthorization(resourceServer); } diff --git a/services/src/main/java/org/keycloak/authorization/admin/ResourceSetService.java b/services/src/main/java/org/keycloak/authorization/admin/ResourceSetService.java index fc8a8cf8822..16ab292cae8 100644 --- a/services/src/main/java/org/keycloak/authorization/admin/ResourceSetService.java +++ b/services/src/main/java/org/keycloak/authorization/admin/ResourceSetService.java @@ -31,6 +31,7 @@ import java.util.stream.Collectors; import jakarta.ws.rs.Consumes; import jakarta.ws.rs.DELETE; +import jakarta.ws.rs.DefaultValue; import jakarta.ws.rs.GET; import jakarta.ws.rs.NotFoundException; import jakarta.ws.rs.POST; @@ -402,7 +403,7 @@ public class ResourceSetService { @QueryParam("exactName") Boolean exactName, @QueryParam("deep") Boolean deep, @QueryParam("first") Integer firstResult, - @QueryParam("max") Integer maxResult) { + @QueryParam("max") @DefaultValue(Constants.DEFAULT_MAX_RESULTS_STR) Integer maxResult) { return find(id, name, uri, owner, type, scope, matchingUri, exactName, deep, firstResult, maxResult, (BiFunction) (resource, deep1) -> toRepresentation(resource, resourceServer, authorization, deep1)); } @@ -416,7 +417,7 @@ public class ResourceSetService { @QueryParam("exactName") Boolean exactName, @QueryParam("deep") Boolean deep, @QueryParam("first") Integer firstResult, - @QueryParam("max") Integer maxResult, + @QueryParam("max") @DefaultValue(Constants.DEFAULT_MAX_RESULTS_STR) Integer maxResult, BiFunction toRepresentation) { requireView(); diff --git a/services/src/main/java/org/keycloak/services/resources/admin/ClientResource.java b/services/src/main/java/org/keycloak/services/resources/admin/ClientResource.java index 9bbe16947c2..e901ffaa529 100755 --- a/services/src/main/java/org/keycloak/services/resources/admin/ClientResource.java +++ b/services/src/main/java/org/keycloak/services/resources/admin/ClientResource.java @@ -24,6 +24,7 @@ import java.util.stream.Stream; import jakarta.ws.rs.BadRequestException; import jakarta.ws.rs.Consumes; import jakarta.ws.rs.DELETE; +import jakarta.ws.rs.DefaultValue; import jakarta.ws.rs.GET; import jakarta.ws.rs.NotFoundException; import jakarta.ws.rs.POST; @@ -569,8 +570,8 @@ public class ClientResource { @NoCache @Produces(MediaType.APPLICATION_JSON) @Tag(name = KeycloakOpenAPI.Admin.Tags.CLIENTS) - @Operation( summary = "Get user sessions for client Returns a list of user sessions associated with this client\n") - public Stream getUserSessions(@Parameter(description = "Paging offset") @QueryParam("first") Integer firstResult, @Parameter(description = "Maximum results size (defaults to 100)") @QueryParam("max") Integer maxResults) { + @Operation( summary = "Get user sessions for client. Returns a list of user sessions associated with this client.\n") + public Stream getUserSessions(@Parameter(description = "Paging offset") @QueryParam("first") Integer firstResult, @Parameter(description = "Maximum results size.") @QueryParam("max") @DefaultValue(Constants.DEFAULT_MAX_RESULTS_STR) Integer maxResults) { auth.clients().requireView(client); return session.sessions() .readOnlyStreamUserSessions(client.getRealm(), client, computeFirstResult(firstResult), computeMaxResults(maxResults)) @@ -616,8 +617,8 @@ public class ClientResource { @NoCache @Produces(MediaType.APPLICATION_JSON) @Tag(name = KeycloakOpenAPI.Admin.Tags.CLIENTS) - @Operation( summary = "Get offline sessions for client Returns a list of offline user sessions associated with this client") - public Stream getOfflineUserSessions(@Parameter(description = "Paging offset") @QueryParam("first") Integer firstResult, @Parameter(description = "Maximum results size (defaults to 100)") @QueryParam("max") Integer maxResults) { + @Operation( summary = "Get offline sessions for client. Returns a list of offline user sessions associated with this client") + public Stream getOfflineUserSessions(@Parameter(description = "Paging offset") @QueryParam("first") Integer firstResult, @Parameter(description = "Maximum results size.") @QueryParam("max") @DefaultValue(Constants.DEFAULT_MAX_RESULTS_STR) Integer maxResults) { auth.clients().requireView(client); return session.sessions() .readOnlyStreamOfflineUserSessions(client.getRealm(), client, computeFirstResult(firstResult), computeMaxResults(maxResults)) diff --git a/services/src/main/java/org/keycloak/services/resources/admin/RealmAdminResource.java b/services/src/main/java/org/keycloak/services/resources/admin/RealmAdminResource.java index 8c9f424f3d0..226dee90a27 100644 --- a/services/src/main/java/org/keycloak/services/resources/admin/RealmAdminResource.java +++ b/services/src/main/java/org/keycloak/services/resources/admin/RealmAdminResource.java @@ -902,7 +902,7 @@ public class RealmAdminResource { @Parameter(description = "To (inclusive) date (yyyy-MM-dd) or time in Epoch timestamp millis (number of milliseconds since January 1, 1970, 00:00:00 GMT)") @QueryParam("dateTo") String dateTo, @Parameter(description = "IP Address") @QueryParam("ipAddress") String ipAddress, @Parameter(description = "Paging offset") @QueryParam("first") Integer firstResult, - @Parameter(description = "Maximum results size (defaults to 100)") @QueryParam("max") Integer maxResults, + @Parameter(description = "Maximum results size") @QueryParam("max") @DefaultValue(Constants.DEFAULT_MAX_RESULTS_STR) Integer maxResults, @Parameter(description = "The direction to sort events by (asc or desc)") @QueryParam("direction") String direction) { auth.realm().requireViewEvents(); diff --git a/services/src/main/java/org/keycloak/services/resources/admin/RoleContainerResource.java b/services/src/main/java/org/keycloak/services/resources/admin/RoleContainerResource.java index 5f3475f6485..19efe40a3ab 100755 --- a/services/src/main/java/org/keycloak/services/resources/admin/RoleContainerResource.java +++ b/services/src/main/java/org/keycloak/services/resources/admin/RoleContainerResource.java @@ -564,7 +564,7 @@ public class RoleContainerResource extends RoleResource { * * @param roleName the role name. * @param firstResult first result to return. Ignored if negative or {@code null}. - * @param maxResults maximum number of results to return. Ignored if negative or {@code null}. + * @param maxResults maximum number of results to return. Unbounded if negative. * @param briefRepresentation Boolean which defines whether brief representations are returned (default: false) * @return a non-empty {@code Stream} of users. */ @@ -582,7 +582,7 @@ public class RoleContainerResource extends RoleResource { public Stream getUsersInRole(final @Parameter(description = "the role name.") @PathParam("role-name") String roleName, @Parameter(description = "Boolean which defines whether brief representations are returned (default: false)") @QueryParam("briefRepresentation") Boolean briefRepresentation, @Parameter(description = "first result to return. Ignored if negative or {@code null}.") @QueryParam("first") Integer firstResult, - @Parameter(description = "maximum number of results to return. Ignored if negative or {@code null}.") @QueryParam("max") Integer maxResults) { + @Parameter(description = "Maximum number of results to return. Unbounded if negative.") @QueryParam("max") @DefaultValue(Constants.DEFAULT_MAX_RESULTS_STR) Integer maxResults) { auth.roles().requireView(roleContainer); auth.users().requireQuery(); @@ -608,7 +608,7 @@ public class RoleContainerResource extends RoleResource { * * @param roleName the role name. * @param firstResult first result to return. Ignored if negative or {@code null}. - * @param maxResults maximum number of results to return. Ignored if negative or {@code null}. + * @param maxResults maximum number of results to return. Unbounded if negative. * @param briefRepresentation if false, return a full representation of the {@code GroupRepresentation} objects. * @return a non-empty {@code Stream} of groups. */ @@ -624,9 +624,9 @@ public class RoleContainerResource extends RoleResource { @APIResponse(responseCode = "404", description = "Not Found") }) public Stream getGroupsInRole(final @Parameter(description = "the role name.") @PathParam("role-name") String roleName, - @Parameter(description = "first result to return. Ignored if negative or {@code null}.") @QueryParam("first") Integer firstResult, - @Parameter(description = "maximum number of results to return. Ignored if negative or {@code null}.") @QueryParam("max") Integer maxResults, - @Parameter(description = "if false, return a full representation of the {@code GroupRepresentation} objects.") @QueryParam("briefRepresentation") @DefaultValue("true") boolean briefRepresentation) { + @Parameter(description = "First result to return. Ignored if negative or {@code null}.") @QueryParam("first") Integer firstResult, + @Parameter(description = "Maximum number of results to return. Unbounded if negative.") @QueryParam(Constants.DEFAULT_MAX_RESULTS_STR) Integer maxResults, + @Parameter(description = "If false, return a full representation of the {@code GroupRepresentation} objects.") @QueryParam("briefRepresentation") @DefaultValue("true") boolean briefRepresentation) { auth.roles().requireView(roleContainer); firstResult = firstResult != null ? firstResult : 0;