| /* |
| * Copyright (C) 2010-2011 The University of Manchester |
| * |
| * See the file "LICENSE" for license terms. |
| */ |
| package org.taverna.server.master.common; |
| |
| import static javax.ws.rs.core.UriBuilder.fromUri; |
| import static org.apache.commons.logging.LogFactory.getLog; |
| import static org.taverna.server.master.common.Namespaces.XLINK; |
| |
| import java.lang.reflect.Method; |
| import java.net.URI; |
| import java.util.Map; |
| |
| import javax.annotation.PreDestroy; |
| import javax.ws.rs.core.UriBuilder; |
| import javax.ws.rs.core.UriBuilderException; |
| import javax.ws.rs.core.UriInfo; |
| import javax.xml.bind.annotation.XmlAttribute; |
| import javax.xml.bind.annotation.XmlSchemaType; |
| import javax.xml.bind.annotation.XmlType; |
| |
| import org.apache.commons.logging.Log; |
| import org.springframework.beans.factory.annotation.Autowired; |
| import org.springframework.security.web.PortMapper; |
| |
| import edu.umd.cs.findbugs.annotations.NonNull; |
| import edu.umd.cs.findbugs.annotations.SuppressWarnings; |
| |
| /** |
| * A class that makes it simpler to work with an element with a {@link URI} in |
| * an <tt>href</tt> attribute. Done with JAXB. |
| * |
| * @author Donal Fellows |
| */ |
| @XmlType(name = "Location") |
| public class Uri { |
| static Log log = getLog("Taverna.Server.UriRewriter"); |
| private static final String SECURE_SCHEME = "https"; |
| /** |
| * This type is characterised by an attribute that is the reference to some |
| * other element. |
| */ |
| @XmlAttribute(name = "href", namespace = XLINK) |
| @XmlSchemaType(name = "anyURI") |
| public URI ref; |
| |
| /** Make a reference that points nowhere. */ |
| public Uri() { |
| } |
| |
| /** |
| * Make a reference to the given location. |
| * |
| * @param ref |
| * Where to point to. |
| */ |
| public Uri(@NonNull URI ref) { |
| this.ref = secure(ref); |
| } |
| |
| /** |
| * Make a reference from the factory with the given parameters. |
| * |
| * @param ub |
| * The configured factory. |
| * @param strings |
| * The parameters to the factory. |
| */ |
| public Uri(@NonNull UriBuilder ub, String... strings) { |
| ref = secure(ub).build((Object[]) strings); |
| } |
| |
| /** |
| * Make a reference from the factory with the given parameters. |
| * |
| * @param ui |
| * The factory factory. |
| * @param path |
| * The path to configure the factory with. |
| * @param strings |
| * The parameters to the factory. |
| */ |
| public Uri(@NonNull UriInfo ui, @NonNull String path, String... strings) { |
| this(ui, true, path, strings); |
| } |
| |
| /** |
| * Make a reference from the factory with the given parameters. |
| * |
| * @param ui |
| * The factory factory. |
| * @param secure |
| * Whether the URI should be required to use HTTPS. |
| * @param path |
| * The path to configure the factory with. |
| * @param strings |
| * The parameters to the factory. |
| */ |
| public Uri(@NonNull UriInfo ui, boolean secure, @NonNull String path, |
| String... strings) { |
| UriBuilder ub = ui.getAbsolutePathBuilder(); |
| if (secure) { |
| ub = secure(ub); |
| } |
| ref = ub.path(path).build((Object[]) strings); |
| } |
| |
| public static UriBuilder secure(UriBuilder ub) { |
| return Rewriter.getInstance().getSecuredUriBuilder(ub); |
| } |
| |
| public static UriBuilder secure(UriInfo ui) { |
| return secure(ui.getAbsolutePathBuilder()); |
| } |
| |
| public static URI secure(URI uri) { |
| URI newURI = secure(fromUri(uri)).build(); |
| log.debug("rewrote " + uri + " to " + newURI); |
| return newURI; |
| } |
| public static URI secure(URI base, String uri) { |
| URI newURI = secure(fromUri(base.resolve(uri))).build(); |
| log.debug("rewrote " + uri + " to " + newURI); |
| return newURI; |
| } |
| |
| /** |
| * A bean that allows configuration of how to rewrite generated URIs to be |
| * secure. |
| * |
| * @author Donal Fellows |
| */ |
| public static class Rewriter { |
| private static Rewriter instance; |
| private PortMapper portMapper; |
| private boolean suppress; |
| private String rewriteRE = "://[^/]+/[^/]+"; |
| private String rewriteTarget; |
| |
| static Rewriter getInstance() { |
| if (instance == null) |
| new Rewriter(); |
| return instance; |
| } |
| |
| @Autowired |
| public void setPortMapper(PortMapper portMapper) { |
| this.portMapper = portMapper; |
| } |
| |
| /** |
| * Whether to suppress rewriting of URIs to be secure. |
| * |
| * @param suppressSecurity |
| * True if no rewriting should be done. |
| */ |
| public void setSuppressSecurity(boolean suppressSecurity) { |
| suppress = suppressSecurity; |
| } |
| |
| public void setRewriteRegexp(String rewriteRegexp) { |
| this.rewriteRE = rewriteRegexp; |
| } |
| |
| /** |
| * What to rewrite the host, port and web-app name to be. |
| * |
| * @param rewriteTarget |
| * What to rewrite to, or "<tt>NONE</tt>" for no rewrite. |
| */ |
| public void setRewriteTarget(String rewriteTarget) { |
| if (rewriteTarget.isEmpty()) |
| this.rewriteTarget = null; |
| else if (rewriteTarget.equals("NONE")) |
| this.rewriteTarget = null; |
| else if (rewriteTarget.startsWith("${")) |
| this.rewriteTarget = null; |
| else |
| this.rewriteTarget = "://" + rewriteTarget; |
| } |
| |
| private Integer lookupHttpsPort(URI uri) { |
| if (portMapper != null) |
| return portMapper.lookupHttpsPort(uri.getPort()); |
| return null; |
| } |
| |
| @SuppressWarnings |
| public Rewriter() { |
| instance = this; |
| } |
| |
| @PreDestroy |
| @SuppressWarnings |
| public void done() { |
| instance = null; |
| Uri.log = null; |
| } |
| |
| @NonNull |
| URI rewrite(@NonNull String url) { |
| if (rewriteTarget != null) |
| url = url.replaceFirst(rewriteRE, rewriteTarget); |
| return URI.create(url); |
| } |
| |
| @NonNull |
| public UriBuilder getSecuredUriBuilder(@NonNull UriBuilder uribuilder) { |
| if (suppress) |
| return uribuilder.clone(); |
| UriBuilder ub = new RewritingUriBuilder(uribuilder); |
| Integer secPort = null; |
| try { |
| secPort = lookupHttpsPort(ub.build()); |
| } catch (Exception e) { |
| /* |
| * Do not log this; we know why it happens and don't actually |
| * care to do anything about it. All it does is fill up the log |
| * with pointless scariness! |
| */ |
| |
| // log.debug("failed to extract current URI port", e); |
| } |
| if (secPort == null || secPort.intValue() == -1) |
| return ub.scheme(SECURE_SCHEME); |
| return ub.scheme(SECURE_SCHEME).port(secPort); |
| } |
| |
| /** |
| * {@link UriBuilder} that applies a rewrite rule to the URIs produced |
| * by the wrapped builder. |
| * |
| * @author Donal Fellows |
| */ |
| class RewritingUriBuilder extends UriBuilder { |
| private UriBuilder wrapped; |
| |
| RewritingUriBuilder(UriBuilder builder) { |
| wrapped = builder.clone(); |
| } |
| |
| private URI rewrite(URI uri) { |
| return Rewriter.this.rewrite(uri.toString()); |
| } |
| |
| @Override |
| public UriBuilder clone() { |
| return new RewritingUriBuilder(wrapped); |
| } |
| |
| @Override |
| public URI buildFromMap(Map<String, ? extends Object> values) |
| throws IllegalArgumentException, UriBuilderException { |
| return rewrite(wrapped.buildFromMap(values)); |
| } |
| |
| @Override |
| public URI buildFromEncodedMap(Map<String, ? extends Object> values) |
| throws IllegalArgumentException, UriBuilderException { |
| return rewrite(wrapped.buildFromEncodedMap(values)); |
| } |
| |
| @Override |
| public URI build(Object... values) throws IllegalArgumentException, |
| UriBuilderException { |
| return rewrite(wrapped.build(values)); |
| } |
| |
| @Override |
| public URI buildFromEncoded(Object... values) |
| throws IllegalArgumentException, UriBuilderException { |
| return rewrite(wrapped.buildFromEncoded(values)); |
| } |
| |
| @Override |
| public UriBuilder uri(URI uri) throws IllegalArgumentException { |
| wrapped.uri(uri); |
| return this; |
| } |
| |
| @Override |
| public UriBuilder scheme(String scheme) |
| throws IllegalArgumentException { |
| wrapped.scheme(scheme); |
| return this; |
| } |
| |
| @Override |
| public UriBuilder schemeSpecificPart(String ssp) |
| throws IllegalArgumentException { |
| wrapped.schemeSpecificPart(ssp); |
| return this; |
| } |
| |
| @Override |
| public UriBuilder userInfo(String ui) { |
| wrapped.userInfo(ui); |
| return this; |
| } |
| |
| @Override |
| public UriBuilder host(String host) throws IllegalArgumentException { |
| wrapped.host(host); |
| return this; |
| } |
| |
| @Override |
| public UriBuilder port(int port) throws IllegalArgumentException { |
| wrapped.port(port); |
| return this; |
| } |
| |
| @Override |
| public UriBuilder replacePath(String path) { |
| wrapped.replacePath(path); |
| return this; |
| } |
| |
| @Override |
| public UriBuilder path(String path) throws IllegalArgumentException { |
| wrapped.path(path); |
| return this; |
| } |
| |
| @Override |
| public UriBuilder path( |
| @java.lang.SuppressWarnings("rawtypes") Class resource) |
| throws IllegalArgumentException { |
| wrapped.path(resource); |
| return this; |
| } |
| |
| @Override |
| public UriBuilder path( |
| @java.lang.SuppressWarnings("rawtypes") Class resource, |
| String method) throws IllegalArgumentException { |
| wrapped.path(resource, method); |
| return this; |
| } |
| |
| @Override |
| public UriBuilder path(Method method) |
| throws IllegalArgumentException { |
| wrapped.path(method); |
| return this; |
| } |
| |
| @Override |
| public UriBuilder segment(String... segments) |
| throws IllegalArgumentException { |
| wrapped.segment(segments); |
| return this; |
| } |
| |
| @Override |
| public UriBuilder replaceMatrix(String matrix) |
| throws IllegalArgumentException { |
| wrapped.replaceMatrix(matrix); |
| return this; |
| } |
| |
| @Override |
| public UriBuilder matrixParam(String name, Object... values) |
| throws IllegalArgumentException { |
| wrapped.matrixParam(name, values); |
| return this; |
| } |
| |
| @Override |
| public UriBuilder replaceMatrixParam(String name, Object... values) |
| throws IllegalArgumentException { |
| wrapped.replaceMatrixParam(name, values); |
| return this; |
| } |
| |
| @Override |
| public UriBuilder replaceQuery(String query) |
| throws IllegalArgumentException { |
| wrapped.replaceQuery(query); |
| return this; |
| } |
| |
| @Override |
| public UriBuilder queryParam(String name, Object... values) |
| throws IllegalArgumentException { |
| wrapped.queryParam(name, values); |
| return this; |
| } |
| |
| @Override |
| public UriBuilder replaceQueryParam(String name, Object... values) |
| throws IllegalArgumentException { |
| wrapped.replaceQueryParam(name, values); |
| return this; |
| } |
| |
| @Override |
| public UriBuilder fragment(String fragment) { |
| wrapped.fragment(fragment); |
| return this; |
| } |
| } |
| } |
| } |