Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue #215 forward header support #216

Merged
merged 7 commits into from
Sep 5, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import javax.ws.rs.core.Response.ResponseBuilder;
import javax.ws.rs.core.Response.Status;

import com.epimorphics.lda.specs.APISpec;
import org.apache.log4j.PropertyConfigurator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand Down Expand Up @@ -366,7 +367,8 @@ static class Mutable<T> {
log.debug("handling request '{}'", requestUri);
//
try {
URI ru = makeRequestURI(ui, match, requestUri);
APISpec apiSpec = match.getEndpoint().getSpec().getAPISpec();
URI ru = makeRequestURI(ui, apiSpec.getEnableForwardHeaders(), apiSpec.getBase(), servletRequest);
APIEndpoint ep = match.getEndpoint();
boolean needsVaryAccept = formatName == null && queryParams.containsKey( "_format" ) == false;

Expand Down Expand Up @@ -515,10 +517,34 @@ private String getSeqID(HttpServletResponse servletResponse) {
catch (NoSuchMethodError e) { return "none"; }
}

public static URI makeRequestURI(UriInfo ui, Match match, URI requestUri) {
String base = match.getEndpoint().getSpec().getAPISpec().getBase();
if (base == null) return requestUri;
return URIUtils.resolveAgainstBase( requestUri, URIUtils.newURI( base ), ui.getPath() );
public static URI makeRequestURI(UriInfo ui, Boolean enableForwardHeaders, String base, HttpServletRequest request) {
URI requestUri = ui.getRequestUri();

base = base == null ? "" : base;
URI baseUri = URIUtils.newURI(base);
UriBuilder builder = UriBuilder.fromUri(baseUri);

if (enableForwardHeaders) {
String prot = request.getHeader("X-Forwarded-Proto");
String host = request.getHeader("X-Forwarded-Host");

if (baseUri.getScheme() == null && prot != null) {
builder.scheme(prot);
}
if (baseUri.getHost() == null && host != null) {
URI hostUri = URIUtils.newURI("//" + host);
builder.host(hostUri.getHost()).port(hostUri.getPort());
}

baseUri = builder.build();

if (baseUri.getScheme() != null && baseUri.getHost() == null) {
builder.host(requestUri.getHost()).port(requestUri.getPort());
baseUri = builder.build();
}
}

return URIUtils.resolveAgainstBase( requestUri, baseUri, ui.getPath() );
}

private static String MATCHES_SCHEME = "[a-zA-Z][-.+A-Za-z0-9]+:";
Expand Down
7 changes: 7 additions & 0 deletions elda-lda/src/main/java/com/epimorphics/lda/specs/APISpec.java
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,8 @@ public class APISpec extends SpecCommon {
protected final String graphTemplate;

protected final boolean purging;

protected final Boolean enableForwardHeaders;

protected final MetaConfig metaConfig;

Expand Down Expand Up @@ -142,6 +144,7 @@ public APISpec( MetaConfig mc, String prefixPath, String appName, FileManager fm
this.cacheExpiryMilliseconds = PropertyExpiryTimes.getSecondsValue( root, ELDA_API.cacheExpiryTime, -1) * 1000;
this.enableCounting = RDFUtils.getOptionalBooleanValue( root, ELDA_API.enableCounting, Boolean.FALSE );
this.propertyExpiryTimes = PropertyExpiryTimes.assemble( root.getModel() );
this.enableForwardHeaders = RDFUtils.getBooleanValue(root, ELDA_API.enableForwardHeaders, true);
//
this.metaConfig = new MetaConfig(root, mc);
//
Expand Down Expand Up @@ -386,5 +389,9 @@ public PropertyExpiryTimes getPropertyExpiryTimes() {
public String getGraphTemplate() {
return graphTemplate;
}

public Boolean getEnableForwardHeaders() {
return enableForwardHeaders;
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,8 @@ public class ELDA_API extends API {
* should be dropped from a query parameter filter value.</p>
*/
public static final Property purgeFilterValues = m_model.createProperty( "http://www.epimorphics.com/vocabularies/lda#purgeFilterValues" );

public static final Property enableForwardHeaders = m_model.createProperty( "http://www.epimorphics.com/vocabularies/lda#enableForwardHeaders" );

/** <p></p> */
public static final Property replaceStartBy = m_model.createProperty( "http://www.epimorphics.com/vocabularies/lda#replaceStartBy" );
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/*
See lda-top/LICENCE (or https://raw.github.com/epimorphics/elda/master/LICENCE)
for the licence for this software.

(c) Copyright 2011 Epimorphics Limited
$Id$
*/

package com.epimorphics.lda.apispec.tests;

import static org.junit.Assert.assertEquals;

import org.junit.Test;

import com.epimorphics.jsonrdf.utils.ModelIOUtils;
import com.epimorphics.lda.specs.APISpec;
import com.hp.hpl.jena.rdf.model.Model;
import com.hp.hpl.jena.rdf.model.Resource;

public class TestAPISpecExtractsProperties {
@Test public void testExtractsBase() {
Model spec = ModelIOUtils.modelFromTurtle(new StringBuffer()
.append(":s a api:API")
.append("; api:sparqlEndpoint <http://example.com/none>")
.append("; api:base 'to/be/expunged'")
.append(".")
.toString()
);

Resource s = spec.getResource( spec.expandPrefix( ":s" ) );
APISpec a = SpecUtil.specFrom( s );
assertEquals( "to/be/expunged", a.getBase() );
}

@Test public void testExtractsEnableForwardHeaders() {
Model spec = ModelIOUtils.modelFromTurtle(new StringBuffer()
.append(":s a api:API")
.append("; api:sparqlEndpoint <http://example.com/none>")
.append("; elda:enableForwardHeaders false")
.append(".")
.toString()
);

Resource s = spec.getResource( spec.expandPrefix( ":s" ) );
APISpec a = SpecUtil.specFrom( s );
assertEquals( false, a.getEnableForwardHeaders() );
}

@Test public void testExtractsEnableForwardHeaders_DefaultsToTrue() {
Model spec = ModelIOUtils.modelFromTurtle(new StringBuffer()
.append(":s a api:API")
.append("; api:sparqlEndpoint <http://example.com/none>")
.append(".")
.toString()
);

Resource s = spec.getResource( spec.expandPrefix( ":s" ) );
APISpec a = SpecUtil.specFrom( s );
assertEquals( true, a.getEnableForwardHeaders() );
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
package com.epimorphics.lda.restlets;

import com.epimorphics.util.URIUtils;
import org.junit.Test;

import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.core.UriInfo;
import java.net.URI;

import static org.junit.Assert.*;
import static org.mockito.Mockito.*;

public class RouterRestletTest {
@Test
public void makeRequestURI_WithoutBase_WithoutForward_ReturnsRequestUri() {
URI result = new RequestURIScenario().run();
assertEquals("http://test.org/request", result.toString());
}

@Test
public void makeRequestURI_WithoutBase_WithForward_ReturnsForwardUri() {
URI result = new RequestURIScenario()
.withForward("https", "proxy.net")
.run();
assertEquals("https://proxy.net/request", result.toString());
}

@Test
public void makeRequestURI_WithoutBase_WithForwardPort_ReturnsForwardUri() {
URI result = new RequestURIScenario()
.withForward("https", "proxy.net:9090")
.run();
assertEquals("https://proxy.net:9090/request", result.toString());
}

@Test
public void makeRequestURI_WithAbsoluteBase_WithoutForward_ReturnsBaseUri() {
URI result = new RequestURIScenario()
.withBase("https://proxy.net")
.run();
assertEquals("https://proxy.net/request", result.toString());
}

@Test
public void makeRequestURI_WithAbsoluteBase_WithForward_ReturnsBaseUri() {
URI result = new RequestURIScenario()
.withBase("https://proxy.net")
.withForward("ftp", "forward.com")
.run();
assertEquals("https://proxy.net/request", result.toString());
}

@Test
public void makeRequestURI_WithRelativeBase_WithoutForward_ReturnsRequestUri() {
URI result = new RequestURIScenario()
.withBase("/test/path")
.run();
assertEquals("http://test.org/test/path/request", result.toString());
}

@Test
public void makeRequestURI_WithRelativeBasePath_WithForward_ReturnsForwardUri() {
URI result = new RequestURIScenario()
.withBase("/test/path")
.withForward("https", "proxy.net")
.run();
assertEquals("https://proxy.net/test/path/request", result.toString());
}

@Test
public void makeRequestURI_WithRelativeBaseHost_WithForward_ReturnsForwardUri() {
URI result = new RequestURIScenario()
.withBase("//proxy.net/test/path")
.withForward("https", "forward.com")
.run();
assertEquals("https://proxy.net/test/path/request", result.toString());
}

@Test
public void makeRequestURI_WithRelativeBaseHost_WithForwardProtoOnly_ReturnsForwardUri() {
URI result = new RequestURIScenario()
.withBase("/test/path")
.withForward("https", null)
.run();
assertEquals("https://test.org/test/path/request", result.toString());
}

@Test
public void makeRequestURI_ForwardHeadersDisabled_WithAbsoluteBase_ReturnsBaseUri() {
URI result = new RequestURIScenario()
.withEnabled(false)
.withForward("https", "proxy.net")
.withBase("http://base.com")
.run();
assertEquals("http://base.com/request", result.toString());
}

@Test
public void makeRequestURI_ForwardHeadersDisabled_WithRelativeBase_ReturnsBaseUri() {
URI result = new RequestURIScenario()
.withEnabled(false)
.withForward("https", "proxy.net")
.withBase("/test/path")
.run();
assertEquals("http://test.org/test/path/request", result.toString());
}

@Test
public void makeRequestURI_ForwardHeadersDisabled_WithoutBase_ReturnsRequestUri() {
URI result = new RequestURIScenario()
.withEnabled(false)
.withForward("https", "proxy.net")
.run();
assertEquals("http://test.org/request", result.toString());
}

class RequestURIScenario {
private final UriInfo ui = mock(UriInfo.class);
private Boolean enabled = true;
private String base;
private URI requestUri = URIUtils.newURI("http://test.org/request");
private final HttpServletRequest request = mock(HttpServletRequest.class);

RequestURIScenario() {
when(ui.getRequestUri()).thenReturn(requestUri);
when(ui.getPath()).thenReturn("/request");
}

RequestURIScenario withEnabled(Boolean enabled) {
this.enabled = enabled;
return this;
}

RequestURIScenario withBase(String base) {
this.base = base;
return this;
}

RequestURIScenario withForward(String proto, String host) {
when(request.getHeader("X-Forwarded-Proto")).thenReturn(proto);
when(request.getHeader("X-Forwarded-Host")).thenReturn(host);
return this;
}

URI run() {
return RouterRestlet.makeRequestURI(ui, enabled, base, request);
}
}
}