keycloak-d4science-spi-parent/avatar-realm-resource/src/main/java/org/gcube/keycloak/avatar/AvatarAdminResource.java

178 lines
6.6 KiB
Java

package org.gcube.keycloak.avatar;
import java.io.InputStream;
import javax.ws.rs.Consumes;
import javax.ws.rs.ForbiddenException;
import javax.ws.rs.GET;
import javax.ws.rs.NotAuthorizedException;
import javax.ws.rs.NotFoundException;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.Response;
import org.gcube.keycloak.avatar.storage.AvatarStorageProvider;
import org.jboss.resteasy.annotations.cache.NoCache;
import org.jboss.resteasy.plugins.providers.multipart.MultipartFormDataInput;
import org.keycloak.common.ClientConnection;
import org.keycloak.jose.jws.JWSInput;
import org.keycloak.jose.jws.JWSInputException;
import org.keycloak.models.ClientModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
import org.keycloak.models.UserModel;
import org.keycloak.representations.AccessToken;
import org.keycloak.services.managers.AppAuthManager;
import org.keycloak.services.managers.AuthenticationManager;
import org.keycloak.services.managers.RealmManager;
import org.keycloak.services.resources.admin.AdminAuth;
import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator;
import org.keycloak.services.resources.admin.permissions.AdminPermissions;
public class AvatarAdminResource extends AbstractAvatarResource {
private AdminPermissionEvaluator realmAuth;
@Context
private AvatarStorageProvider avatarStorageProvider;
private AppAuthManager authManager;
// private TokenManager tokenManager;
@Context
private HttpHeaders httpHeaders;
@Context
private ClientConnection clientConnection;
private AdminAuth auth;
public AvatarAdminResource(KeycloakSession session) {
super(session);
authManager = new AppAuthManager();
// tokenManager = new TokenManager();
}
public void init() {
RealmModel realm = session.getContext().getRealm();
auth = authenticateRealmAdminRequest();
RealmManager realmManager = new RealmManager(session);
if (realm == null)
throw new NotFoundException("Realm not found");
if (!auth.getRealm().equals(realmManager.getKeycloakAdminstrationRealm()) && !auth.getRealm().equals(realm)) {
throw new org.keycloak.services.ForbiddenException();
}
realmAuth = AdminPermissions.evaluator(session, realm, auth);
session.getContext().setRealm(realm);
}
@GET
@Path("/{user_id}")
@Produces({ "image/png", "image/jpeg", "image/gif" })
public Response downloadUserAvatarImage(@PathParam("user_id") String userId) {
try {
canViewUsers();
UserModel user = session.users().getUserById(userId, session.getContext().getRealm());
return Response.ok(fetchUserImage(session.getContext().getRealm(), user)).build();
} catch (ForbiddenException e) {
return Response.status(Response.Status.FORBIDDEN).entity(e.getMessage()).build();
} catch (Exception e) {
logger.error("error getting user avatar", e);
return Response.serverError().entity(e.getMessage()).build();
}
}
@POST
@NoCache
@Path("/{user_id}")
@Consumes(MediaType.MULTIPART_FORM_DATA)
public Response uploadUserAvatarImage(@PathParam("user_id") String userId, MultipartFormDataInput input) {
try {
if (auth == null) {
return Response.status(Response.Status.UNAUTHORIZED).build();
}
canManageUsers();
RealmModel realm = session.getContext().getRealm();
UserModel user = session.users().getUserById(userId, session.getContext().getRealm());
InputStream imageInputStream = input.getFormDataPart(AVATAR_IMAGE_PARAMETER, InputStream.class, null);
saveUserImage(realm, user, imageInputStream);
} catch (ForbiddenException e) {
return Response.status(Response.Status.FORBIDDEN).entity(e.getMessage()).build();
} catch (Exception e) {
logger.error("error saving user avatar", e);
return Response.serverError().entity(e.getMessage()).build();
}
return Response.ok().build();
}
protected AdminAuth authenticateRealmAdminRequest() {
String tokenString = authManager.extractAuthorizationHeaderToken(httpHeaders);
MultivaluedMap<String, String> queryParameters = session.getContext().getUri().getQueryParameters();
if (tokenString == null && queryParameters.containsKey("access_token")) {
tokenString = queryParameters.getFirst("access_token");
}
if (tokenString == null) {
throw new NotAuthorizedException("Bearer");
}
AccessToken token;
try {
JWSInput input = new JWSInput(tokenString);
token = input.readJsonContent(AccessToken.class);
} catch (JWSInputException e) {
throw new NotAuthorizedException("Bearer token format error");
}
String realmName = token.getIssuer().substring(token.getIssuer().lastIndexOf('/') + 1);
RealmManager realmManager = new RealmManager(session);
RealmModel realm = realmManager.getRealmByName(realmName);
if (realm == null) {
throw new NotAuthorizedException("Unknown realm in token");
}
session.getContext().setRealm(realm);
AuthenticationManager.AuthResult authResult = authManager.authenticateBearerToken(tokenString, session, realm,
session.getContext().getUri(), clientConnection, httpHeaders);
if (authResult == null) {
logger.debug("Token not valid");
throw new NotAuthorizedException("Bearer");
}
ClientModel client = realm.getClientByClientId(token.getIssuedFor());
if (client == null) {
throw new NotFoundException("Could not find client for authorization");
}
return new AdminAuth(realm, authResult.getToken(), authResult.getUser(), client);
}
private void canViewUsers() {
if (!realmAuth.users().canView()) {
String message = "user does not have permission to view users";
logger.info(message);
throw new ForbiddenException(message);
}
}
private void canManageUsers() {
if (!realmAuth.users().canManage()) {
String message = "user does not have permission to manage users";
logger.info(message);
throw new ForbiddenException(message);
}
}
}