common-smartgears/src/main/java/org/gcube/smartgears/handlers/application/request/RequestContextRetriever.java

163 lines
6.1 KiB
Java

package org.gcube.smartgears.handlers.application.request;
import static org.gcube.common.authorization.client.Constants.authorizationService;
import static org.gcube.smartgears.Constants.scope_header;
import static org.gcube.smartgears.Constants.token_header;
import static org.gcube.smartgears.handlers.application.request.RequestError.internal_server_error;
import static org.gcube.smartgears.handlers.application.request.RequestError.invalid_request_error;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Base64;
import java.util.List;
import javax.xml.bind.annotation.XmlRootElement;
import org.gcube.common.authorization.client.exceptions.ObjectNotFound;
import org.gcube.common.authorization.library.AuthorizationEntry;
import org.gcube.common.authorization.library.provider.AuthorizationProvider;
import org.gcube.common.authorization.library.provider.SecurityTokenProvider;
import org.gcube.common.authorization.library.provider.UmaJWTProvider;
import org.gcube.common.authorization.library.provider.UserInfo;
import org.gcube.common.authorization.library.utils.Caller;
import org.gcube.common.scope.api.ScopeProvider;
import org.gcube.common.scope.impl.ScopeBean;
import org.gcube.smartgears.Constants;
import org.gcube.smartgears.handlers.application.RequestEvent;
import org.gcube.smartgears.handlers.application.RequestHandler;
import org.gcube.smartgears.handlers.application.ResponseEvent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.eclipsesource.json.Json;
import com.eclipsesource.json.JsonArray;
import com.eclipsesource.json.JsonObject;
@XmlRootElement(name = Constants.request_context_retriever)
public class RequestContextRetriever extends RequestHandler {
private static Logger log = LoggerFactory.getLogger(RequestContextRetriever.class);
private static final String BEARER_AUTH_PREFIX ="Bearer";
private static final String BASIC_AUTH_PREFIX ="Basic";
@Override
public String getName() {
return Constants.request_context_retriever;
}
@Override
public void handleRequest(RequestEvent call) {
String token = call.request().getParameter(token_header)==null? call.request().getHeader(token_header):call.request().getParameter(token_header);
String scope = call.request().getParameter(scope_header)==null? call.request().getHeader(scope_header):call.request().getParameter(scope_header);
String authHeader = call.request().getHeader(Constants.authorization_header);
log.trace("auth header is {}",authHeader);
String umaToken = null;
if (authHeader!=null && !authHeader.isEmpty()) {
if (authHeader.startsWith(BEARER_AUTH_PREFIX))
umaToken = authHeader.substring(BEARER_AUTH_PREFIX.length()).trim();
else if (token==null && authHeader.startsWith(BASIC_AUTH_PREFIX)) {
String basicAuthToken = authHeader.substring(BASIC_AUTH_PREFIX.length()).trim();
String decodedAuth = new String(Base64.getDecoder().decode(basicAuthToken.getBytes()));
token = decodedAuth.split(":")[1];
}
}
//Gives priority to the token
if (umaToken!=null) {
this.retreiveAndSetInfoUmaToken(umaToken, token, call);
} else if (token!=null)
this.retreiveAndSetInfoGcubeToken(token, call);
else if (scope!=null)
ScopeProvider.instance.set(scope);
}
@Override
public void handleResponse(ResponseEvent e) {
SecurityTokenProvider.instance.reset();
AuthorizationProvider.instance.reset();
UmaJWTProvider.instance.reset();
ScopeProvider.instance.reset();
log.debug("resetting all the Thread local for this call.");
}
private void retreiveAndSetInfoGcubeToken(String token, RequestEvent call){
log.trace("retrieving context using token {} ", token);
AuthorizationEntry authEntry = null;
try{
authEntry = authorizationService().get(token);
}catch(ObjectNotFound onf){
log.warn("rejecting call to {}, invalid token {}",call.context().name(),token);
invalid_request_error.fire(call.context().name()+" invalid token : "+token);
}catch(Exception e){
log.error("error contacting authorization service",e);
internal_server_error.fire("error contacting authorization service");
}
AuthorizationProvider.instance.set(new Caller(authEntry.getClientInfo(), authEntry.getQualifier()));
SecurityTokenProvider.instance.set(token);
ScopeProvider.instance.set(authEntry.getContext());
log.info("retrieved request authorization info {} in scope {} ", AuthorizationProvider.instance.get(), authEntry.getContext());
}
private void retreiveAndSetInfoUmaToken(String umaToken, String gcubeToken, RequestEvent call){
log.debug("using UMA token for authorization");
log.trace("retrieving context using uma token {} ", umaToken);
UmaJWTProvider.instance.set(umaToken);
SecurityTokenProvider.instance.set(gcubeToken);
parseUmaTokenAndSet(umaToken);
log.info("retrieved request authorization info {} in scope {} ", AuthorizationProvider.instance.get(), ScopeProvider.instance.get());
}
private void parseUmaTokenAndSet(String umaToken) {
String realUmaTokenEncoded = umaToken.split("\\.")[1];
String realUmaToken = new String(Base64.getDecoder().decode(realUmaTokenEncoded.getBytes()));
JsonObject object = Json.parse(realUmaToken).asObject();
String username = object.get("preferred_username").asString();
String scope = object.getString("aud", null);
log.trace("token related context is {}", scope);
JsonObject resource = object.get("resource_access").asObject();
log.trace("resource access is {}", resource.toString());
JsonObject scopeObject = resource.get(scope).asObject();
ScopeBean scopeBean = null;
try {
String decodedName = URLDecoder.decode(scope, StandardCharsets.UTF_8.toString());
scopeBean = new ScopeBean(decodedName);
}catch(Exception e){
log.error("error decoding uma token",e);
internal_server_error.fire("error contacting authorization service");
}
JsonArray roles = scopeObject.get("roles").asArray();
List<String> userRoles = new ArrayList<String>();
roles.forEach((e)->userRoles.add(e.asString()));
AuthorizationProvider.instance.set(new Caller(new UserInfo(username, userRoles), "token"));
ScopeProvider.instance.set(scopeBean.toString());
}
}