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 userRoles = new ArrayList(); roles.forEach((e)->userRoles.add(e.asString())); AuthorizationProvider.instance.set(new Caller(new UserInfo(username, userRoles), "token")); ScopeProvider.instance.set(scopeBean.toString()); } }