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.util.Base64; import javax.xml.bind.annotation.XmlRootElement; import org.gcube.com.fasterxml.jackson.databind.ObjectMapper; import org.gcube.common.authorization.client.exceptions.ObjectNotFound; import org.gcube.common.authorization.library.AuthorizationEntry; import org.gcube.common.authorization.library.provider.AccessTokenProvider; import org.gcube.common.authorization.library.provider.AuthorizationProvider; import org.gcube.common.authorization.library.provider.SecurityTokenProvider; 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.gcube.smartgears.utils.GcubeJwt; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @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("authorization header is {}",authHeader); log.trace("token header is {}",token); log.trace("scope header is {}",scope); String retrievedUser = null; String accessToken = null; if (authHeader!=null && !authHeader.isEmpty()) { if (authHeader.startsWith(BEARER_AUTH_PREFIX)) accessToken = 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())); String[] splitAuth = decodedAuth.split(":"); token = splitAuth[1]; retrievedUser = splitAuth[0]; } } //Gives priority to the umaToken if (accessToken!=null) { this.retreiveAndSetInfoUmaToken(accessToken, token, call); } else if (token!=null) this.retreiveAndSetInfoGcubeToken(token, retrievedUser, call); else if (scope!=null) ScopeProvider.instance.set(scope); } @Override public void handleResponse(ResponseEvent e) { SecurityTokenProvider.instance.reset(); AuthorizationProvider.instance.reset(); AccessTokenProvider.instance.reset(); ScopeProvider.instance.reset(); log.debug("resetting all the Thread local for this call."); } private void retreiveAndSetInfoGcubeToken(String token, String retrievedUser, RequestEvent call){ log.trace("retrieving context using token {} ", token); AuthorizationEntry authEntry = null; try{ authEntry = authorizationService().get(token); if (retrievedUser != null && authEntry.getClientInfo().getId().equals(retrievedUser)) throw new Exception("user and token owner are not the same"); }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 accessToken, String gcubeToken, RequestEvent call){ log.debug("using UMA token for authorization"); log.trace("retrieving context using uma token {} ", accessToken); AccessTokenProvider.instance.set(accessToken); SecurityTokenProvider.instance.set(gcubeToken); parseAccessTokenAndSet(accessToken); log.info("retrieved request authorization info {} in scope {} ", AuthorizationProvider.instance.get(), ScopeProvider.instance.get()); } private void parseAccessTokenAndSet(String umaToken) { String realUmaTokenEncoded = umaToken.split("\\.")[1]; String realUmaToken = new String(Base64.getDecoder().decode(realUmaTokenEncoded.getBytes())); ObjectMapper mapper = new ObjectMapper(); GcubeJwt jwt = null; try { jwt = mapper.readValue(realUmaToken, GcubeJwt.class); }catch(Exception e){ log.error("error decoding uma token",e); internal_server_error.fire("error parsing access token"); } ScopeBean scopeBean = null; try { scopeBean = new ScopeBean(jwt.getContext()); }catch(Exception e){ log.error("error decoding uma token",e); internal_server_error.fire("invalid context in access token"); } AuthorizationProvider.instance.set(new Caller(new UserInfo(jwt.getUsername(), jwt.getRoles(), jwt.getEmail(), jwt.getFirstName(), jwt.getLastName()), "token")); ScopeProvider.instance.set(scopeBean.toString()); } }