package it.inaf.oats.vospace; import it.inaf.ia2.aa.ServletRapClient; import it.inaf.ia2.aa.data.User; import it.inaf.ia2.rap.client.call.TokenExchangeRequest; import it.inaf.oats.vospace.datamodel.NodeProperties; import static it.inaf.oats.vospace.datamodel.NodeUtils.urlEncodePath; import it.inaf.oats.vospace.exception.InternalFaultException; import it.inaf.oats.vospace.exception.NodeNotFoundException; import it.inaf.oats.vospace.exception.PermissionDeniedException; import it.inaf.oats.vospace.persistence.LocationDAO; import it.inaf.oats.vospace.persistence.NodeDAO; import it.inaf.oats.vospace.persistence.model.Location; import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; import java.util.List; import javax.servlet.http.HttpServletRequest; import net.ivoa.xml.uws.v1.ExecutionPhase; import net.ivoa.xml.uws.v1.JobSummary; import net.ivoa.xml.uws.v1.ResultReference; import net.ivoa.xml.vospace.v2.Node; import net.ivoa.xml.vospace.v2.Protocol; import net.ivoa.xml.vospace.v2.Transfer; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; @Service public class UriService { @Value("${vospace-authority}") private String authority; @Value("${file-service-url}") private String fileServiceUrl; @Autowired private NodeDAO nodeDao; @Autowired private LocationDAO locationDAO; @Autowired private HttpServletRequest servletRequest; @Autowired private ServletRapClient rapClient; public void setTransferJobResult(JobSummary job, Transfer transfer) { List results = new ArrayList<>(); ResultReference result = new ResultReference(); result.setHref(getEndpoint(job, transfer)); results.add(result); job.setResults(results); job.setPhase(ExecutionPhase.COMPLETED); } public void setSyncTransferEndpoints(JobSummary job) { Transfer transfer = getTransfer(job); Protocol protocol = transfer.getProtocols().get(0); if (!"ivo://ivoa.net/vospace/core#httpget".equals(protocol.getUri()) && !"ivo://ivoa.net/vospace/core#httpput".equals(protocol.getUri())) { throw new IllegalStateException("Unsupported protocol " + protocol.getUri()); } protocol.setEndpoint(getEndpoint(job, transfer)); } private String getEndpoint(JobSummary job, Transfer transfer) { String relativePath = transfer.getTarget().substring("vos://".length() + authority.length()); Node node = nodeDao.listNode(relativePath).orElseThrow(() -> new NodeNotFoundException(relativePath)); Location location = locationDAO.getNodeLocation(relativePath).orElseThrow(() -> new InternalFaultException("No registered location found for vos_path " + relativePath)); String endpoint; switch (location.getType()) { case PORTAL: String fileName = nodeDao.getNodeOsName(relativePath); endpoint = "http://" + location.getSource().getHostname() + location.getSource().getBasePath(); if (!endpoint.endsWith("/")) { endpoint += "/"; } endpoint += fileName; break; default: endpoint = fileServiceUrl + urlEncodePath(relativePath); } endpoint += "?jobId=" + job.getJobId(); if (!"true".equals(NodeProperties.getNodePropertyByURI(node, NodeProperties.PUBLIC_READ_URI))) { endpoint += "&token=" + getEndpointToken(fileServiceUrl + relativePath); } return endpoint; } private String getEndpointToken(String endpoint) { String token = ((User) servletRequest.getUserPrincipal()).getAccessToken(); if (token == null) { throw new PermissionDeniedException("Token is null"); } TokenExchangeRequest exchangeRequest = new TokenExchangeRequest() .setSubjectToken(token) .setResource(endpoint); // TODO: add audience and scope return rapClient.exchangeToken(exchangeRequest, servletRequest); } public void setNodeRemoteLocation(String nodeUri, String contentUri) { URL url; try { url = new URL(contentUri); } catch (MalformedURLException ex) { throw new InternalFaultException(ex); } Location location = locationDAO.findPortalLocation(url.getHost()).orElseThrow(() -> new InternalFaultException("No registered location found for host " + url.getHost())); String vosPath = nodeUri.replaceAll("vos://[^/]+", ""); String fileName = url.getPath().substring(url.getPath().lastIndexOf("/") + 1); nodeDao.setNodeLocation(vosPath, location.getId(), fileName); } public Transfer getTransfer(JobSummary job) { List jobPayload = job.getJobInfo().getAny(); if (jobPayload.isEmpty()) { throw new IllegalStateException("Empty job payload for job " + job.getJobId()); } if (jobPayload.size() > 1) { throw new IllegalStateException("Multiple objects in job payload not supported"); } if (!(jobPayload.get(0) instanceof Transfer)) { throw new IllegalStateException(jobPayload.get(0).getClass().getCanonicalName() + " not supported as job payload. Job id: " + job.getJobId()); } return (Transfer) job.getJobInfo().getAny().get(0); } }