diff --git a/server-spi-private/src/main/java/org/keycloak/models/utils/ModelToRepresentation.java b/server-spi-private/src/main/java/org/keycloak/models/utils/ModelToRepresentation.java index 7c65a17387..ee6ce995a3 100755 --- a/server-spi-private/src/main/java/org/keycloak/models/utils/ModelToRepresentation.java +++ b/server-spi-private/src/main/java/org/keycloak/models/utils/ModelToRepresentation.java @@ -908,6 +908,19 @@ public class ModelToRepresentation { return rep; } + public static AuthenticationExecutionRepresentation toRepresentation(AuthenticationExecutionModel model) { + AuthenticationExecutionRepresentation rep = new AuthenticationExecutionRepresentation(); + rep.setId(model.getId()); + rep.setAuthenticatorConfig(model.getAuthenticatorConfig()); + rep.setAuthenticator(model.getAuthenticator()); + rep.setFlowId(model.getFlowId()); + rep.setAuthenticatorFlow(model.isAuthenticatorFlow()); + rep.setRequirement(model.getRequirement().name()); + rep.setPriority(model.getPriority()); + rep.setParentFlow(model.getParentFlow()); + return rep; + } + public static AuthenticatorConfigRepresentation toRepresentation(AuthenticatorConfigModel model) { AuthenticatorConfigRepresentation rep = new AuthenticatorConfigRepresentation(); rep.setId(model.getId()); diff --git a/services/src/main/java/org/keycloak/services/resources/admin/AuthenticationManagementResource.java b/services/src/main/java/org/keycloak/services/resources/admin/AuthenticationManagementResource.java index 5553f6d837..cbb97ff872 100755 --- a/services/src/main/java/org/keycloak/services/resources/admin/AuthenticationManagementResource.java +++ b/services/src/main/java/org/keycloak/services/resources/admin/AuthenticationManagementResource.java @@ -91,8 +91,6 @@ import java.util.concurrent.atomic.AtomicInteger; import java.util.stream.Collectors; import java.util.stream.Stream; -import static jakarta.ws.rs.core.Response.Status.NOT_FOUND; - import org.keycloak.utils.RequiredActionHelper; import org.keycloak.utils.ReservedCharValidator; @@ -121,6 +119,7 @@ public class AuthenticationManagementResource { * Get form providers * * Returns a stream of form providers. + * @return */ @Path("/form-providers") @GET @@ -138,6 +137,7 @@ public class AuthenticationManagementResource { * Get authenticator providers * * Returns a stream of authenticator providers. + * @return */ @Path("/authenticator-providers") @GET @@ -155,6 +155,7 @@ public class AuthenticationManagementResource { * Get client authenticator providers * * Returns a stream of client authenticator providers. + * @return */ @Path("/client-authenticator-providers") @GET @@ -193,6 +194,7 @@ public class AuthenticationManagementResource { * Get form action providers * * Returns a stream of form action providers. + * @return */ @Path("/form-action-providers") @GET @@ -212,6 +214,7 @@ public class AuthenticationManagementResource { * Get authentication flows * * Returns a stream of authentication flows. + * @return */ @Path("/flows") @GET @@ -239,6 +242,7 @@ public class AuthenticationManagementResource { @Consumes(MediaType.APPLICATION_JSON) @Tag(name = KeycloakOpenAPI.Admin.Tags.AUTHENTICATION_MANAGEMENT) @Operation( summary = "Create a new authentication flow") + @APIResponse(responseCode = "201", description = "Created") public Response createFlow(@Parameter( description = "Authentication flow representation") AuthenticationFlowRepresentation flow) { auth.realm().requireManageRealm(); @@ -289,6 +293,7 @@ public class AuthenticationManagementResource { /** * Update an authentication flow * + * @param id The flow id * @param flow Authentication flow representation * @return */ @@ -299,7 +304,8 @@ public class AuthenticationManagementResource { @Produces(MediaType.APPLICATION_JSON) @Tag(name = KeycloakOpenAPI.Admin.Tags.AUTHENTICATION_MANAGEMENT) @Operation( summary = "Update an authentication flow") - public Response updateFlow(@PathParam("id") String id, AuthenticationFlowRepresentation flow) { + @APIResponse(responseCode = "204", description = "No Content") + public void updateFlow(@PathParam("id") String id, AuthenticationFlowRepresentation flow) { auth.realm().requireManageRealm(); AuthenticationFlowRepresentation existingFlow = getFlow(id); @@ -340,7 +346,6 @@ public class AuthenticationManagementResource { flow.setId(existingFlow.getId()); realm.updateAuthenticationFlow(RepresentationToModel.toModel(flow)); adminEvent.operation(OperationType.UPDATE).resourcePath(session.getContext().getUri()).representation(flow).success(); - return Response.accepted(flow).build(); } /** @@ -353,6 +358,7 @@ public class AuthenticationManagementResource { @NoCache @Tag(name = KeycloakOpenAPI.Admin.Tags.AUTHENTICATION_MANAGEMENT) @Operation( summary = "Delete an authentication flow") + @APIResponse(responseCode = "204", description = "No Content") public void deleteFlow(@Parameter(description = "Flow id") @PathParam("id") String id) { auth.realm().requireManageRealm(); @@ -379,6 +385,7 @@ public class AuthenticationManagementResource { * * @param flowAlias Name of the existing authentication flow * @param data JSON containing 'newName' attribute + * @return */ @Path("/flows/{flowAlias}/copy") @POST @@ -386,6 +393,7 @@ public class AuthenticationManagementResource { @Consumes(MediaType.APPLICATION_JSON) @Tag(name = KeycloakOpenAPI.Admin.Tags.AUTHENTICATION_MANAGEMENT) @Operation( summary = "Copy existing authentication flow under a new name The new name is given as 'newName' attribute of the passed JSON object") + @APIResponse(responseCode = "201", description = "Created") public Response copy(@Parameter(description="name of the existing authentication flow") @PathParam("flowAlias") String flowAlias, Map data) { auth.realm().requireManageRealm(); @@ -441,7 +449,7 @@ public class AuthenticationManagementResource { AuthenticatorConfigModel config = configManager.getAuthenticatorConfig(realm, execution.getAuthenticatorConfig()); if (config == null) { - logger.debugf("Authentication execution with id [%s] not found", config.getId()); + logger.debugf("Authentication execution configuration with id [%s] not found", execution.getAuthenticatorConfig()); throw new IllegalStateException("Authentication execution configuration not found"); } @@ -472,6 +480,7 @@ public class AuthenticationManagementResource { * * @param flowAlias Alias of parent authentication flow * @param data New authentication flow / execution JSON data containing 'alias', 'type', 'provider', 'priority', and 'description' attributes + * @return */ @Path("/flows/{flowAlias}/executions/flow") @POST @@ -479,6 +488,7 @@ public class AuthenticationManagementResource { @Consumes(MediaType.APPLICATION_JSON) @Tag(name = KeycloakOpenAPI.Admin.Tags.AUTHENTICATION_MANAGEMENT) @Operation( summary = "Add new flow with new execution to existing flow") + @APIResponse(responseCode = "201", description = "Created") public Response addExecutionFlow(@Parameter(description = "Alias of parent authentication flow") @PathParam("flowAlias") String flowAlias, @Parameter(description = "New authentication flow / execution JSON data containing 'alias', 'type', 'provider', 'priority', and 'description' attributes") Map data) { auth.realm().requireManageRealm(); @@ -536,6 +546,7 @@ public class AuthenticationManagementResource { * * @param flowAlias Alias of parent flow * @param data New execution JSON data containing 'provider' and 'priority' (optional) attribute + * @return */ @Path("/flows/{flowAlias}/executions/execution") @POST @@ -543,6 +554,7 @@ public class AuthenticationManagementResource { @Consumes(MediaType.APPLICATION_JSON) @Tag(name = KeycloakOpenAPI.Admin.Tags.AUTHENTICATION_MANAGEMENT) @Operation( summary="Add new authentication execution to a flow") + @APIResponse(responseCode = "201", description = "Created") public Response addExecutionToFlow(@Parameter(description = "Alias of parent flow") @PathParam("flowAlias") String flowAlias, @Parameter(description = "New execution JSON data containing 'provider' and 'priority' (optional) attribute") Map data) { auth.realm().requireManageRealm(); @@ -619,6 +631,7 @@ public class AuthenticationManagementResource { * Get authentication executions for a flow * * @param flowAlias Flow alias + * @return The list of executions */ @Path("/flows/{flowAlias}/executions") @GET @@ -626,20 +639,20 @@ public class AuthenticationManagementResource { @Produces(MediaType.APPLICATION_JSON) @Tag(name = KeycloakOpenAPI.Admin.Tags.AUTHENTICATION_MANAGEMENT) @Operation( summary = "Get authentication executions for a flow") - public Response getExecutions(@Parameter(description = "Flow alias") @PathParam("flowAlias") String flowAlias) { + public List getExecutions(@Parameter(description = "Flow alias") @PathParam("flowAlias") String flowAlias) { auth.realm().requireViewRealm(); AuthenticationFlowModel flow = realm.getFlowByAlias(flowAlias); if (flow == null) { logger.debug("flow not found: " + flowAlias); - return Response.status(NOT_FOUND).build(); + throw new NotFoundException("Flow not found"); } List result = new LinkedList<>(); int level = 0; recurseExecutions(flow, result, level); - return Response.ok(result).build(); + return result; } public void recurseExecutions(AuthenticationFlowModel flow, List result, int level) { @@ -721,6 +734,7 @@ public class AuthenticationManagementResource { * Update authentication executions of a Flow * @param flowAlias Flow alias * @param rep AuthenticationExecutionInfoRepresentation + * @return */ @Path("/flows/{flowAlias}/executions") @PUT @@ -729,7 +743,8 @@ public class AuthenticationManagementResource { @Consumes(MediaType.APPLICATION_JSON) @Tag(name = KeycloakOpenAPI.Admin.Tags.AUTHENTICATION_MANAGEMENT) @Operation( summary = "Update authentication executions of a Flow") - public Response updateExecutions(@Parameter(description = "Flow alias") @PathParam("flowAlias") String flowAlias, @Parameter(description = "AuthenticationExecutionInfoRepresentation") AuthenticationExecutionInfoRepresentation rep) { + @APIResponse(responseCode = "204", description = "No Content") + public void updateExecutions(@Parameter(description = "Flow alias") @PathParam("flowAlias") String flowAlias, @Parameter(description = "AuthenticationExecutionInfoRepresentation") AuthenticationExecutionInfoRepresentation rep) { auth.realm().requireManageRealm(); AuthenticationFlowModel flow = realm.getFlowByAlias(flowAlias); @@ -756,11 +771,13 @@ public class AuthenticationManagementResource { if (updateExecution) { realm.updateAuthenticatorExecution(model); adminEvent.operation(OperationType.UPDATE).resource(ResourceType.AUTH_EXECUTION).resourcePath(session.getContext().getUri()).representation(rep).success(); - return Response.accepted(flow).build(); + return; } //executions can't have name and description updated - if (rep.getAuthenticationFlow() == null) { return Response.accepted(flow).build();} + if (rep.getAuthenticationFlow() == null) { + return; + } //check if updating a correct flow AuthenticationFlowModel checkFlow = realm.getAuthenticationFlowById(rep.getFlowId()); @@ -792,11 +809,12 @@ public class AuthenticationManagementResource { //update the flow realm.updateAuthenticationFlow(checkFlow); adminEvent.operation(OperationType.UPDATE).resource(ResourceType.AUTH_EXECUTION).resourcePath(session.getContext().getUri()).representation(rep).success(); - return Response.accepted(flow).build(); } /** * Get Single Execution + * @param executionId The execution id + * @return */ @Path("/executions/{executionId}") @GET @@ -804,7 +822,7 @@ public class AuthenticationManagementResource { @Produces(MediaType.APPLICATION_JSON) @Tag(name = KeycloakOpenAPI.Admin.Tags.AUTHENTICATION_MANAGEMENT) @Operation( summary = "Get Single Execution") - public Response getExecution(final @PathParam("executionId") String executionId) { + public AuthenticationExecutionRepresentation getExecution(final @PathParam("executionId") String executionId) { //http://localhost:8080/auth/admin/realms/master/authentication/executions/cf26211b-9e68-4788-b754-1afd02e59d7f auth.realm().requireManageRealm(); @@ -814,13 +832,14 @@ public class AuthenticationManagementResource { throw new NotFoundException("Illegal execution"); } - return Response.ok(model.get()).build(); + return ModelToRepresentation.toRepresentation(model.get()); } /** * Add new authentication execution * * @param execution JSON model describing authentication execution + * @return */ @Path("/executions") @POST @@ -828,6 +847,7 @@ public class AuthenticationManagementResource { @Consumes(MediaType.APPLICATION_JSON) @Tag(name = KeycloakOpenAPI.Admin.Tags.AUTHENTICATION_MANAGEMENT) @Operation( summary = "Add new authentication execution") + @APIResponse(responseCode = "201", description = "Created") public Response addExecution(@Parameter(description = "JSON model describing authentication execution") AuthenticationExecutionRepresentation execution) { auth.realm().requireManageRealm(); @@ -958,6 +978,7 @@ public class AuthenticationManagementResource { @NoCache @Tag(name = KeycloakOpenAPI.Admin.Tags.AUTHENTICATION_MANAGEMENT) @Operation( summary = "Delete execution") + @APIResponse(responseCode = "204", description = "No Content") public void removeExecution(@Parameter(description = "Execution id") @PathParam("executionId") String execution) { auth.realm().requireManageRealm(); @@ -996,6 +1017,7 @@ public class AuthenticationManagementResource { @Consumes(MediaType.APPLICATION_JSON) @Tag(name = KeycloakOpenAPI.Admin.Tags.AUTHENTICATION_MANAGEMENT) @Operation( summary = "Update execution with new configuration") + @APIResponse(responseCode = "201", description = "Created") public Response newExecutionConfig(@Parameter(description = "Execution id") @PathParam("executionId") String execution, @Parameter(description = "JSON with new configuration") AuthenticatorConfigRepresentation json) { auth.realm().requireManageRealm(); @@ -1025,6 +1047,7 @@ public class AuthenticationManagementResource { * * @param execution Execution id * @param id Configuration id + * @return * @deprecated Use rather {@link #getAuthenticatorConfig(String)} */ @Path("/executions/{executionId}/config/{id}") @@ -1033,6 +1056,7 @@ public class AuthenticationManagementResource { @NoCache @Tag(name = KeycloakOpenAPI.Admin.Tags.AUTHENTICATION_MANAGEMENT) @Operation( summary = "Get execution's configuration", deprecated = true) + @Deprecated public AuthenticatorConfigRepresentation getAuthenticatorConfig(@Parameter(description = "Execution id") @PathParam("executionId") String execution, @Parameter(description = "Configuration id") @PathParam("id") String id) { auth.realm().requireViewRealm(); @@ -1048,6 +1072,7 @@ public class AuthenticationManagementResource { * Get unregistered required actions * * Returns a stream of unregistered required actions. + * @return */ @Path("unregistered-required-actions") @GET @@ -1117,6 +1142,7 @@ public class AuthenticationManagementResource { * Get required actions * * Returns a stream of required actions. + * @return */ @Path("required-actions") @GET @@ -1145,6 +1171,7 @@ public class AuthenticationManagementResource { /** * Get required action for alias * @param alias Alias of required action + * @return The required action representation */ @Path("required-actions/{alias}") @GET @@ -1174,6 +1201,7 @@ public class AuthenticationManagementResource { @Consumes(MediaType.APPLICATION_JSON) @Tag(name = KeycloakOpenAPI.Admin.Tags.AUTHENTICATION_MANAGEMENT) @Operation( summary = "Update required action") + @APIResponse(responseCode = "204", description = "No Content") public void updateRequiredAction(@Parameter(description = "Alias of required action") @PathParam("alias") String alias, @Parameter(description = "JSON describing new state of required action") RequiredActionProviderRepresentation rep) { auth.realm().requireManageRealm(); @@ -1203,6 +1231,7 @@ public class AuthenticationManagementResource { @DELETE @Tag(name = KeycloakOpenAPI.Admin.Tags.AUTHENTICATION_MANAGEMENT) @Operation( summary = "Delete required action") + @APIResponse(responseCode = "204", description = "No Content") public void removeRequiredAction(@Parameter(description = "Alias of required action") @PathParam("alias") String alias) { auth.realm().requireManageRealm(); @@ -1290,6 +1319,8 @@ public class AuthenticationManagementResource { /** * Get required actions provider's configuration description + * @param alias The alias of the required action + * @return The required action configuration representation */ @Path("required-actions/{alias}/config-description") @GET @@ -1318,6 +1349,7 @@ public class AuthenticationManagementResource { /** * Get the configuration of the RequiredAction provider in the current Realm. * @param alias Provider id + * @return The required action configuration representation */ @Path("required-actions/{alias}/config") @GET @@ -1350,6 +1382,7 @@ public class AuthenticationManagementResource { @NoCache @Tag(name = KeycloakOpenAPI.Admin.Tags.AUTHENTICATION_MANAGEMENT) @Operation( summary = "Delete RequiredAction configuration") + @APIResponse(responseCode = "204", description = "No Content") public void removeRequiredActionConfig(@Parameter(description = "Alias of required action") @PathParam("alias") String alias) { auth.realm().requireManageRealm(); @@ -1381,6 +1414,7 @@ public class AuthenticationManagementResource { @NoCache @Tag(name = KeycloakOpenAPI.Admin.Tags.AUTHENTICATION_MANAGEMENT) @Operation( summary = "Update RequiredAction configuration") + @APIResponse(responseCode = "204", description = "No Content") public void updateRequiredActionConfig(@Parameter(description = "Alias of required action") @PathParam("alias") String alias, @Parameter(description = "JSON describing new state of required action configuration") RequiredActionConfigRepresentation rep) { auth.realm().requireManageRealm(); @@ -1410,6 +1444,8 @@ public class AuthenticationManagementResource { /** * Get authenticator provider's configuration description + * @param providerId The authenticator provider id + * @return The authenticator configuration representation */ @Path("config-description/{providerId}") @GET @@ -1449,7 +1485,8 @@ public class AuthenticationManagementResource { } /** - * Get configuration descriptions for all clients + * Get configuration descriptions for all clients + * @return */ @Path("per-client-config-description") @GET @@ -1474,6 +1511,7 @@ public class AuthenticationManagementResource { /** * Create new authenticator configuration * @param rep JSON describing new authenticator configuration + * @return * @deprecated Use {@link #newExecutionConfig(String, AuthenticatorConfigRepresentation)} instead */ @Path("config") @@ -1482,6 +1520,8 @@ public class AuthenticationManagementResource { @Consumes(MediaType.APPLICATION_JSON) @Tag(name = KeycloakOpenAPI.Admin.Tags.AUTHENTICATION_MANAGEMENT) @Operation( summary = "Create new authenticator configuration", deprecated = true) + @APIResponse(responseCode = "201", description = "Created") + @Deprecated public Response createAuthenticatorConfig(@Parameter(description = "JSON describing new authenticator configuration") AuthenticatorConfigRepresentation rep) { auth.realm().requireManageRealm(); @@ -1495,6 +1535,7 @@ public class AuthenticationManagementResource { /** * Get authenticator configuration * @param id Configuration id + * @return The authenticator configuration representation */ @Path("config/{id}") @GET @@ -1522,6 +1563,7 @@ public class AuthenticationManagementResource { @NoCache @Tag(name = KeycloakOpenAPI.Admin.Tags.AUTHENTICATION_MANAGEMENT) @Operation( summary = "Delete authenticator configuration") + @APIResponse(responseCode = "204", description = "No Content") public void removeAuthenticatorConfig(@Parameter(description = "Configuration id") @PathParam("id") String id) { auth.realm().requireManageRealm(); @@ -1553,6 +1595,7 @@ public class AuthenticationManagementResource { @NoCache @Tag(name = KeycloakOpenAPI.Admin.Tags.AUTHENTICATION_MANAGEMENT) @Operation( summary = "Update authenticator configuration") + @APIResponse(responseCode = "204", description = "No Content") public void updateAuthenticatorConfig(@Parameter(description = "Configuration id") @PathParam("id") String id, @Parameter(description = "JSON describing new state of authenticator configuration") AuthenticatorConfigRepresentation rep) { auth.realm().requireManageRealm();