Changed auth code
This commit is contained in:
parent
bcd09ff218
commit
a0bf4ee541
|
@ -2,6 +2,8 @@ package org.gcube.keycloak.avatar;
|
||||||
|
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
|
||||||
|
import javax.ws.rs.NotFoundException;
|
||||||
|
import javax.ws.rs.core.Response;
|
||||||
import javax.ws.rs.core.StreamingOutput;
|
import javax.ws.rs.core.StreamingOutput;
|
||||||
|
|
||||||
import org.apache.commons.io.IOUtils;
|
import org.apache.commons.io.IOUtils;
|
||||||
|
@ -11,6 +13,9 @@ import org.jboss.logging.Logger;
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.models.RealmModel;
|
import org.keycloak.models.RealmModel;
|
||||||
import org.keycloak.models.UserModel;
|
import org.keycloak.models.UserModel;
|
||||||
|
import org.keycloak.services.managers.AppAuthManager;
|
||||||
|
import org.keycloak.services.managers.AuthenticationManager;
|
||||||
|
import org.keycloak.services.managers.AuthenticationManager.AuthResult;
|
||||||
|
|
||||||
public abstract class AbstractAvatarResource {
|
public abstract class AbstractAvatarResource {
|
||||||
|
|
||||||
|
@ -21,9 +26,22 @@ public abstract class AbstractAvatarResource {
|
||||||
public static final Class<?> DEFAULT_IMPLEMENTATION = FileAvatarStorageProvider.class;
|
public static final Class<?> DEFAULT_IMPLEMENTATION = FileAvatarStorageProvider.class;
|
||||||
|
|
||||||
protected KeycloakSession session;
|
protected KeycloakSession session;
|
||||||
|
protected AuthenticationManager.AuthResult auth;
|
||||||
|
|
||||||
public AbstractAvatarResource(KeycloakSession session) {
|
public AbstractAvatarResource(KeycloakSession session) {
|
||||||
this.session = session;
|
this.session = session;
|
||||||
|
auth = authenticate(session);
|
||||||
|
}
|
||||||
|
|
||||||
|
private AuthResult authenticate(KeycloakSession session) {
|
||||||
|
logger.debug("Authenticating with bearer token");
|
||||||
|
AuthResult auth = new AppAuthManager().authenticateBearerToken(session);
|
||||||
|
|
||||||
|
if (auth == null) {
|
||||||
|
logger.debug("Authenticating with identity cookie");
|
||||||
|
auth = new AppAuthManager().authenticateIdentityCookie(session, session.getContext().getRealm());
|
||||||
|
}
|
||||||
|
return auth;
|
||||||
}
|
}
|
||||||
|
|
||||||
public AvatarStorageProvider getAvatarStorageProvider() {
|
public AvatarStorageProvider getAvatarStorageProvider() {
|
||||||
|
@ -55,4 +73,13 @@ public abstract class AbstractAvatarResource {
|
||||||
return is != null ? output -> IOUtils.copy(is, output) : null;
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,6 @@ import javax.ws.rs.Consumes;
|
||||||
import javax.ws.rs.ForbiddenException;
|
import javax.ws.rs.ForbiddenException;
|
||||||
import javax.ws.rs.GET;
|
import javax.ws.rs.GET;
|
||||||
import javax.ws.rs.NotAuthorizedException;
|
import javax.ws.rs.NotAuthorizedException;
|
||||||
import javax.ws.rs.NotFoundException;
|
|
||||||
import javax.ws.rs.POST;
|
import javax.ws.rs.POST;
|
||||||
import javax.ws.rs.Path;
|
import javax.ws.rs.Path;
|
||||||
import javax.ws.rs.PathParam;
|
import javax.ws.rs.PathParam;
|
||||||
|
@ -14,66 +13,34 @@ import javax.ws.rs.Produces;
|
||||||
import javax.ws.rs.core.Context;
|
import javax.ws.rs.core.Context;
|
||||||
import javax.ws.rs.core.HttpHeaders;
|
import javax.ws.rs.core.HttpHeaders;
|
||||||
import javax.ws.rs.core.MediaType;
|
import javax.ws.rs.core.MediaType;
|
||||||
import javax.ws.rs.core.MultivaluedMap;
|
|
||||||
import javax.ws.rs.core.Response;
|
import javax.ws.rs.core.Response;
|
||||||
|
|
||||||
import org.gcube.keycloak.avatar.storage.AvatarStorageProvider;
|
import org.gcube.keycloak.avatar.storage.AvatarStorageProvider;
|
||||||
import org.jboss.resteasy.annotations.cache.NoCache;
|
import org.jboss.resteasy.annotations.cache.NoCache;
|
||||||
import org.jboss.resteasy.plugins.providers.multipart.MultipartFormDataInput;
|
import org.jboss.resteasy.plugins.providers.multipart.MultipartFormDataInput;
|
||||||
import org.keycloak.common.ClientConnection;
|
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.KeycloakSession;
|
||||||
import org.keycloak.models.RealmModel;
|
import org.keycloak.models.RealmModel;
|
||||||
import org.keycloak.models.UserModel;
|
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 {
|
public class AvatarAdminResource extends AbstractAvatarResource {
|
||||||
|
|
||||||
private AdminPermissionEvaluator realmAuth;
|
|
||||||
|
|
||||||
@Context
|
@Context
|
||||||
private AvatarStorageProvider avatarStorageProvider;
|
private AvatarStorageProvider avatarStorageProvider;
|
||||||
|
|
||||||
private AppAuthManager authManager;
|
|
||||||
// private TokenManager tokenManager;
|
|
||||||
|
|
||||||
@Context
|
@Context
|
||||||
private HttpHeaders httpHeaders;
|
private HttpHeaders httpHeaders;
|
||||||
|
|
||||||
@Context
|
@Context
|
||||||
private ClientConnection clientConnection;
|
private ClientConnection clientConnection;
|
||||||
|
|
||||||
private AdminAuth auth;
|
|
||||||
|
|
||||||
public AvatarAdminResource(KeycloakSession session) {
|
public AvatarAdminResource(KeycloakSession session) {
|
||||||
super(session);
|
super(session);
|
||||||
authManager = new AppAuthManager();
|
|
||||||
// tokenManager = new TokenManager();
|
// tokenManager = new TokenManager();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void init() {
|
public void init() {
|
||||||
RealmModel realm = session.getContext().getRealm();
|
checkRealmAdmin();
|
||||||
|
|
||||||
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
|
@GET
|
||||||
|
@ -81,10 +48,8 @@ public class AvatarAdminResource extends AbstractAvatarResource {
|
||||||
@Produces({ "image/png", "image/jpeg", "image/gif" })
|
@Produces({ "image/png", "image/jpeg", "image/gif" })
|
||||||
public Response downloadUserAvatarImage(@PathParam("user_id") String userId) {
|
public Response downloadUserAvatarImage(@PathParam("user_id") String userId) {
|
||||||
try {
|
try {
|
||||||
canViewUsers();
|
|
||||||
UserModel user = session.users().getUserById(userId, session.getContext().getRealm());
|
UserModel user = session.users().getUserById(userId, session.getContext().getRealm());
|
||||||
return Response.ok(fetchUserImage(session.getContext().getRealm(), user)).build();
|
return fetchAndCreateResponse(session.getContext().getRealm(), user);
|
||||||
|
|
||||||
} catch (ForbiddenException e) {
|
} catch (ForbiddenException e) {
|
||||||
return Response.status(Response.Status.FORBIDDEN).entity(e.getMessage()).build();
|
return Response.status(Response.Status.FORBIDDEN).entity(e.getMessage()).build();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
@ -102,7 +67,6 @@ public class AvatarAdminResource extends AbstractAvatarResource {
|
||||||
if (auth == null) {
|
if (auth == null) {
|
||||||
return Response.status(Response.Status.UNAUTHORIZED).build();
|
return Response.status(Response.Status.UNAUTHORIZED).build();
|
||||||
}
|
}
|
||||||
canManageUsers();
|
|
||||||
|
|
||||||
RealmModel realm = session.getContext().getRealm();
|
RealmModel realm = session.getContext().getRealm();
|
||||||
UserModel user = session.users().getUserById(userId, session.getContext().getRealm());
|
UserModel user = session.users().getUserById(userId, session.getContext().getRealm());
|
||||||
|
@ -119,59 +83,13 @@ public class AvatarAdminResource extends AbstractAvatarResource {
|
||||||
return Response.ok().build();
|
return Response.ok().build();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected AdminAuth authenticateRealmAdminRequest() {
|
private void checkRealmAdmin() {
|
||||||
String tokenString = authManager.extractAuthorizationHeaderToken(httpHeaders);
|
if (auth == null) {
|
||||||
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");
|
throw new NotAuthorizedException("Bearer");
|
||||||
}
|
} else if (auth.getToken().getRealmAccess() == null
|
||||||
AccessToken token;
|
|| !auth.getToken().getRealmAccess().isUserInRole("admin")) {
|
||||||
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) {
|
throw new ForbiddenException("Does not have realm admin role");
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,23 +7,18 @@ import javax.ws.rs.Consumes;
|
||||||
import javax.ws.rs.ForbiddenException;
|
import javax.ws.rs.ForbiddenException;
|
||||||
import javax.ws.rs.GET;
|
import javax.ws.rs.GET;
|
||||||
import javax.ws.rs.NotAuthorizedException;
|
import javax.ws.rs.NotAuthorizedException;
|
||||||
import javax.ws.rs.NotFoundException;
|
|
||||||
import javax.ws.rs.POST;
|
import javax.ws.rs.POST;
|
||||||
import javax.ws.rs.Path;
|
import javax.ws.rs.Path;
|
||||||
import javax.ws.rs.Produces;
|
import javax.ws.rs.Produces;
|
||||||
import javax.ws.rs.core.Context;
|
import javax.ws.rs.core.Context;
|
||||||
import javax.ws.rs.core.MediaType;
|
import javax.ws.rs.core.MediaType;
|
||||||
import javax.ws.rs.core.Response;
|
import javax.ws.rs.core.Response;
|
||||||
import javax.ws.rs.core.StreamingOutput;
|
|
||||||
import javax.ws.rs.core.UriInfo;
|
import javax.ws.rs.core.UriInfo;
|
||||||
|
|
||||||
import org.jboss.resteasy.annotations.cache.NoCache;
|
import org.jboss.resteasy.annotations.cache.NoCache;
|
||||||
import org.jboss.resteasy.plugins.providers.multipart.MultipartFormDataInput;
|
import org.jboss.resteasy.plugins.providers.multipart.MultipartFormDataInput;
|
||||||
import org.jboss.resteasy.spi.ResteasyProviderFactory;
|
import org.jboss.resteasy.spi.ResteasyProviderFactory;
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.services.managers.AppAuthManager;
|
|
||||||
import org.keycloak.services.managers.AuthenticationManager;
|
|
||||||
import org.keycloak.services.managers.AuthenticationManager.AuthResult;
|
|
||||||
import org.keycloak.services.resources.RealmsResource;
|
import org.keycloak.services.resources.RealmsResource;
|
||||||
|
|
||||||
public class AvatarResource extends AbstractAvatarResource {
|
public class AvatarResource extends AbstractAvatarResource {
|
||||||
|
@ -31,21 +26,8 @@ public class AvatarResource extends AbstractAvatarResource {
|
||||||
public static final String STATE_CHECKER_ATTRIBUTE = "state_checker";
|
public static final String STATE_CHECKER_ATTRIBUTE = "state_checker";
|
||||||
public static final String STATE_CHECKER_PARAMETER = "stateChecker";
|
public static final String STATE_CHECKER_PARAMETER = "stateChecker";
|
||||||
|
|
||||||
private final AuthenticationManager.AuthResult auth;
|
|
||||||
|
|
||||||
public AvatarResource(KeycloakSession session) {
|
public AvatarResource(KeycloakSession session) {
|
||||||
super(session);
|
super(session);
|
||||||
auth = authenticate(session);
|
|
||||||
}
|
|
||||||
|
|
||||||
private AuthResult authenticate(KeycloakSession session) {
|
|
||||||
logger.debug("Authenticating with bearer token");
|
|
||||||
AuthResult auth = new AppAuthManager().authenticateBearerToken(session, session.getContext().getRealm());
|
|
||||||
if (auth == null) {
|
|
||||||
logger.debug("Authenticating with identity cookie");
|
|
||||||
auth = new AppAuthManager().authenticateIdentityCookie(session, session.getContext().getRealm());
|
|
||||||
}
|
|
||||||
return auth;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Path("/admin")
|
@Path("/admin")
|
||||||
|
@ -64,11 +46,7 @@ public class AvatarResource extends AbstractAvatarResource {
|
||||||
throw new NotAuthorizedException("Bearer");
|
throw new NotAuthorizedException("Bearer");
|
||||||
}
|
}
|
||||||
logger.debugf("Getting avatar for user %s in realm %s", auth.getUser(), auth.getSession().getRealm());
|
logger.debugf("Getting avatar for user %s in realm %s", auth.getUser(), auth.getSession().getRealm());
|
||||||
StreamingOutput so = fetchUserImage(auth.getSession().getRealm(), auth.getUser());
|
return fetchAndCreateResponse(auth.getSession().getRealm(), auth.getUser());
|
||||||
if (so == null) {
|
|
||||||
throw new NotFoundException("Avatar image not found");
|
|
||||||
}
|
|
||||||
return Response.ok(so).build();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@POST
|
@POST
|
||||||
|
|
Loading…
Reference in New Issue