package org.gcube.keycloak.avatar; import java.io.InputStream; import java.util.List; import org.jboss.resteasy.annotations.cache.NoCache; import org.jboss.resteasy.plugins.providers.multipart.MultipartFormDataInput; import org.jboss.resteasy.spi.ResteasyProviderFactory; import org.keycloak.http.HttpRequest; import org.keycloak.models.KeycloakSession; import org.keycloak.services.resources.Cors; import org.keycloak.services.resources.RealmsResource; import jakarta.ws.rs.Consumes; import jakarta.ws.rs.GET; import jakarta.ws.rs.NotAuthorizedException; import jakarta.ws.rs.OPTIONS; import jakarta.ws.rs.POST; import jakarta.ws.rs.Path; import jakarta.ws.rs.Produces; import jakarta.ws.rs.core.Context; import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.core.Response; import jakarta.ws.rs.core.UriBuilder; import jakarta.ws.rs.core.UriInfo; public class AvatarResource extends AbstractAvatarResource { // public static final String STATE_CHECKER_ATTRIBUTE = "state_checker"; // public static final String STATE_CHECKER_PARAMETER = "stateChecker"; public AvatarResource(KeycloakSession session) { super(session); } @Path("/admin") public AvatarAdminResource admin() { AvatarAdminResource service = new AvatarAdminResource(session); ResteasyProviderFactory.getInstance().injectProperties(service); service.init(); return service; } @OPTIONS public Response handleCorsPreflight(@Context final HttpRequest request) { logger.info("Received CORS preflight request for ext/user; request is " + request); return Cors.add(request, Response.ok()) .preflight() .allowAllOrigins() .allowedMethods("GET", "POST", "DELETE") .exposedHeaders("Location") .auth() .build(); } @GET @Produces({ "image/png", "image/jpeg", "image/gif" }) public Response downloadCurrentUserAvatarImage(@Context final HttpRequest request) { if (auth == null) { logger.debug("Unhautorized call to get avatar"); throw new NotAuthorizedException("Bearer"); } logger.debugf("Getting avatar for user %s in realm %s", auth.getUser(), auth.getSession().getRealm()); return Cors .add(request, Response.fromResponse(fetchAndCreateResponse(auth.getSession().getRealm(), auth.getUser()))) .allowAllOrigins() .allowedMethods("GET", "POST", "DELETE") .exposedHeaders("Location") .auth() .build(); } @POST @NoCache @Consumes(MediaType.MULTIPART_FORM_DATA) public Response uploadCurrentUserAvatarImage(MultipartFormDataInput input, @Context UriInfo uriInfo) { if (auth == null) { throw new NotAuthorizedException("Bearer"); } // if (!isValidStateChecker(input)) { // throw new ForbiddenException("State"); // } logger.debugf("Uploading new avatar for user %s in realm %s", auth.getUser(), auth.getSession().getRealm()); Response response = null; try { InputStream imageInputStream = input.getFormDataPart(AVATAR_IMAGE_PARAMETER, InputStream.class, null); saveUserImage(auth.getSession().getRealm(), auth.getUser(), imageInputStream); if (uriInfo.getQueryParameters().containsKey("account")) { UriBuilder uriBuilder = RealmsResource.accountUrl(session.getContext().getUri().getBaseUriBuilder()); for (String parameterName : uriInfo.getQueryParameters().keySet()) { List parameterValues = uriInfo.getQueryParameters().get(parameterName); for (String parameterValue : parameterValues) { uriBuilder.queryParam(parameterName, parameterValue); } } response = Response.seeOther(uriBuilder.build(auth.getSession().getRealm().getName())).build(); } else { response = Response.noContent().build(); } } catch (Exception ex) { response = Response.serverError().build(); } return response; } // private boolean isValidStateChecker(MultipartFormDataInput input) { // try { // String actualStateChecker = input.getFormDataPart(STATE_CHECKER_PARAMETER, String.class, null); // String requiredStateChecker = (String) session.getAttribute(STATE_CHECKER_ATTRIBUTE); // // return Objects.equals(requiredStateChecker, actualStateChecker); // } catch (Exception ex) { // return false; // } // } }