package org.gcube.keycloak.avatar; import java.io.InputStream; import java.lang.reflect.InvocationTargetException; import org.apache.commons.io.IOUtils; import org.gcube.keycloak.avatar.storage.AvatarStorageProvider; import org.gcube.keycloak.avatar.storage.file.FileAvatarStorageProvider; import org.jboss.logging.Logger; import org.keycloak.models.KeycloakSession; import org.keycloak.models.RealmModel; import org.keycloak.models.UserModel; import org.keycloak.services.managers.AppAuthManager; import org.keycloak.services.managers.AuthenticationManager; import org.keycloak.services.managers.AuthenticationManager.AuthResult; import jakarta.ws.rs.NotFoundException; import jakarta.ws.rs.core.Response; import jakarta.ws.rs.core.StreamingOutput; public abstract class AbstractAvatarResource { protected static final Logger logger = Logger.getLogger(AbstractAvatarResource.class); protected static final String AVATAR_IMAGE_PARAMETER = "image"; public static final Class DEFAULT_IMPLEMENTATION = FileAvatarStorageProvider.class; protected KeycloakSession session; protected AuthenticationManager.AuthResult auth; public AbstractAvatarResource(KeycloakSession session) { this.session = session; auth = authenticate(session); } private AuthResult authenticate(KeycloakSession session) { logger.debug("Authenticating with bearer token"); AuthResult auth = this.auth = new AppAuthManager.BearerTokenAuthenticator(session).authenticate(); if (auth == null) { logger.debug("Authenticating with identity cookie"); auth = new AppAuthManager().authenticateIdentityCookie(session, session.getContext().getRealm()); } return auth; } public AvatarStorageProvider getAvatarStorageProvider() { AvatarStorageProvider asp = lookupAvatarStorageProvider(session); if (asp == null) { logger.warnf("Provider not found via SPI configuration, defaulting to: %s", DEFAULT_IMPLEMENTATION.getName()); try { asp = (AvatarStorageProvider) DEFAULT_IMPLEMENTATION.getDeclaredConstructor().newInstance(); } catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException | NoSuchMethodException | SecurityException e) { logger.error("Cannot instatiate storage implementation class", e); } } return asp; } protected AvatarStorageProvider lookupAvatarStorageProvider(KeycloakSession keycloakSession) { return keycloakSession.getProvider(AvatarStorageProvider.class); } protected void saveUserImage(RealmModel realm, UserModel user, InputStream imageInputStream) { getAvatarStorageProvider().saveAvatarImage(realm, user, imageInputStream); } protected StreamingOutput fetchUserImage(RealmModel realm, UserModel user) { AvatarStorageProvider asp = getAvatarStorageProvider(); InputStream is = asp.loadAvatarImage(realm, user); return is != null ? output -> IOUtils.copy(is, output) : null; } protected Response fetchAndCreateResponse(RealmModel realm, UserModel user) { StreamingOutput so = fetchUserImage(realm, user); if (so == null) { throw new NotFoundException("Avatar image not found"); } return Response.ok(so).build(); } }