Skip to content

Commit

Permalink
URL rewriting: enforce application paths. Currently properties disabl…
Browse files Browse the repository at this point in the history
…e this features, but this should be soon enabled by default.
  • Loading branch information
ebruchez committed Apr 21, 2010
1 parent c692e8d commit bdb0096
Show file tree
Hide file tree
Showing 7 changed files with 76 additions and 32 deletions.
Expand Up @@ -1129,13 +1129,13 @@ private void handleFile(ASTWhen when, final ASTOutput request, final String mime
// Use XPath function to decode the resource URI before passing it to the resource server
addInput(new ASTInput("config",
new ASTHrefAggregate("path", new ASTHrefXPointer(new ASTHrefId(request),
"p:decode-resource-uri(/request/request-path)"))
"p:decode-resource-uri(/request/request-path, true())"))
));
} else {
// Pass the path as is
// Path is not versioned
addInput(new ASTInput("config",
new ASTHrefAggregate("path", new ASTHrefXPointer(new ASTHrefId(request),
"string(/request/request-path)"))
"p:decode-resource-uri(/request/request-path, false())"))
));
}

Expand Down
Expand Up @@ -112,8 +112,9 @@ public static String rewriteServiceURI(String uri, boolean absolute) {
StandardFunction.arg(e, 1, BuiltInAtomicType.STRING, StaticProperty.EXACTLY_ONE, null);

// p:decode-resource-uri()
e = register("{" + PipelineProcessor.PIPELINE_NAMESPACE_URI + "}decode-resource-uri", DecodeResourceURI.class, 0, 1, 1, BuiltInAtomicType.STRING, StaticProperty.EXACTLY_ONE);
e = register("{" + PipelineProcessor.PIPELINE_NAMESPACE_URI + "}decode-resource-uri", DecodeResourceURI.class, 0, 2, 2, BuiltInAtomicType.STRING, StaticProperty.EXACTLY_ONE);
StandardFunction.arg(e, 0, BuiltInAtomicType.STRING, StaticProperty.EXACTLY_ONE, null);
StandardFunction.arg(e, 1, BuiltInAtomicType.BOOLEAN, StaticProperty.EXACTLY_ONE, null);

// === XSLT 2.0 function
e = register("format-date", FormatDate.class, StandardNames.XS_DATE, 2, 5, BuiltInAtomicType.STRING, StaticProperty.EXACTLY_ONE);
Expand Down
Expand Up @@ -15,6 +15,7 @@

import org.orbeon.oxf.util.URLRewriterUtils;
import org.orbeon.saxon.expr.Expression;
import org.orbeon.saxon.expr.ExpressionTool;
import org.orbeon.saxon.expr.ExpressionVisitor;
import org.orbeon.saxon.expr.XPathContext;
import org.orbeon.saxon.functions.SystemFunction;
Expand All @@ -35,12 +36,12 @@ public Expression preEvaluate(ExpressionVisitor visitor) throws XPathException {

@Override
public Item evaluateItem(XPathContext xpathContext) throws XPathException {
// Get URI
final Expression uriExpression = argument[0];
final String uri = uriExpression.evaluateAsString(xpathContext).toString();
// Evaluate parameters
final String uri = argument[0].evaluateAsString(xpathContext).toString();
final boolean isVersioned = ExpressionTool.effectiveBooleanValue(argument[1].iterate(xpathContext));

// Get property value
final String rewrittenURI = URLRewriterUtils.decodeResourceURI(uri);
final String rewrittenURI = URLRewriterUtils.decodeResourceURI(uri, isVersioned);
return StringValue.makeStringValue(rewrittenURI);
}
}
60 changes: 46 additions & 14 deletions src/java/org/orbeon/oxf/util/URLRewriterUtils.java
Expand Up @@ -39,6 +39,8 @@ public class URLRewriterUtils {
public static final boolean RESOURCES_VERSIONED_DEFAULT = false;

private static final String REWRITING_PLATFORM_PATHS_PROPERTY = "oxf.url-rewriting.platform-paths";
private static final String REWRITING_APP_PATHS_PROPERTY = "oxf.url-rewriting.app-paths";
private static final String REWRITING_APP_PREFIX_PROPERTY = "oxf.url-rewriting.app-prefix";
private static final String REWRITING_STRATEGY_PROPERTY_PREFIX = "oxf.url-rewriting.strategy.";
private static final String REWRITING_CONTEXT_PROPERTY_PREFIX = "oxf.url-rewriting.";
private static final String REWRITING_CONTEXT_PROPERTY_SUFFIX = ".context";
Expand Down Expand Up @@ -335,26 +337,56 @@ public static boolean isPlatformPath(String absolutePathNoContext) {
}

/**
* Decode a versioned absolute path with no context, depending on whether there is an app version or not.
* Check if the given path is an application path, assuming it is not already a platform path.
*
* @param absolutePathNoContext path to check
* @return true iif path is a platform path
*/
public static boolean isNonPlatformPathAppPath(String absolutePathNoContext) {
final String regexp = Properties.instance().getPropertySet().getString(REWRITING_APP_PATHS_PROPERTY, null);
// TODO: do not compile the regexp every time
return regexp != null && new Perl5MatchProcessor().match(regexp, absolutePathNoContext).matches;
}

/**
* Decode an absolute path with no context, depending on whether there is an app version or not.
*
* @param absolutePathNoContext path
* @param isVersioned whether the resource is versioned or not
* @return decoded path, or initial path if no decoding needed
*/
public static String decodeResourceURI(String absolutePathNoContext) {
final boolean hasApplicationVersion = URLRewriterUtils.getApplicationResourceVersion() != null;
if (hasApplicationVersion) {
// Remove version on any path
return removeVersionPrefix(absolutePathNoContext);
} else {
// Try to remove version then test for platform path
final String pathWithVersionRemoved = removeVersionPrefix(absolutePathNoContext);
if (isPlatformPath(pathWithVersionRemoved)) {
// This was a versioned platform path
return pathWithVersionRemoved;
public static String decodeResourceURI(String absolutePathNoContext, boolean isVersioned) {
if (isVersioned) {
// Versioned case
final boolean hasApplicationVersion = URLRewriterUtils.getApplicationResourceVersion() != null;
if (hasApplicationVersion) {
// Remove version on any path
return prependAppPathIfNeeded(removeVersionPrefix(absolutePathNoContext));
} else {
// Not a versioned platform path, return as is
return absolutePathNoContext;
// Try to remove version then test for platform path
final String pathWithVersionRemoved = removeVersionPrefix(absolutePathNoContext);
if (isPlatformPath(pathWithVersionRemoved)) {
// This was a versioned platform path
return pathWithVersionRemoved;
} else {
// Not a versioned platform path
// Don't remove version
return prependAppPathIfNeeded(absolutePathNoContext);
}
}
} else {
// Non-versioned case
return prependAppPathIfNeeded(absolutePathNoContext);
}
}

private static String prependAppPathIfNeeded(String path) {
if (isPlatformPath(path) || isNonPlatformPathAppPath(path)) {
// Path doesn't need adjustment
return path;
} else {
// Adjust to make an app path
return Properties.instance().getPropertySet().getString(REWRITING_APP_PREFIX_PROPERTY, "") + path;
}
}

Expand Down
4 changes: 3 additions & 1 deletion src/resources-packaged/ops/unit-tests/properties.xml
Expand Up @@ -29,7 +29,9 @@

<property as="xs:boolean" name="oxf.xforms.host-language-avts" value="true"/>

<property as="xs:string" name="oxf.url-rewriting.platform-paths" value="^/(ops/|config/|xbl/orbeon/|forms/orbeon/|apps/fr/|xforms-server)(.*)$"/>
<property as="xs:string" name="oxf.url-rewriting.platform-paths" value="^/(ops/|config/|xbl/orbeon/|forms/orbeon/|apps/fr/|xforms-server).*$"/>
<property as="xs:string" name="oxf.url-rewriting.app-paths" value="^/(apps|xbl|forms)/.*$"/>
<property as="xs:string" name="oxf.url-rewriting.app-prefix" value="/apps"/>
<property as="xs:anyURI" name="oxf.url-rewriting.service.base-uri" value="http://example.org/cool/service"/>

<property as="xs:NMTOKENS" name="oxf.xforms.logging.debug"
Expand Down
5 changes: 4 additions & 1 deletion src/resources/config/properties-base.xml
Expand Up @@ -23,7 +23,10 @@
<property as="xs:boolean" name="oxf.resources.versioned" value="false"/>
<property as="xs:string" name="oxf.resources.version-number" value="3.1415"/>

<property as="xs:string" name="oxf.url-rewriting.platform-paths" value="^/(ops/|config/|xbl/orbeon/|forms/orbeon/|apps/fr/|xforms-server)(.*)$"/>
<property as="xs:string" name="oxf.url-rewriting.platform-paths" value="^/(ops/|config/|xbl/orbeon/|forms/orbeon/|apps/fr/|xforms-server).*$"/>
<!-- TODO: Uncomment this properties once we are confident -->
<!--<property as="xs:string" name="oxf.url-rewriting.app-paths" value="^/(apps|xbl|forms)/.*$"/>-->
<!--<property as="xs:string" name="oxf.url-rewriting.app-prefix" value="/apps"/>-->
<property as="xs:anyURI" name="oxf.url-rewriting.service.base-uri" value=""/>
<property as="xs:string" name="oxf.url-rewriting.strategy.servlet" value="servlet"/>
<!-- TODO: support for base context for servlet rewriting strategy -->
Expand Down
21 changes: 13 additions & 8 deletions test/src/org/orbeon/oxf/util/URLRewriterTest.java
Expand Up @@ -321,37 +321,42 @@ public void testDecodeResourceURI() {
// Make sure this is recognized as a platform path
assertTrue(URLRewriterUtils.isPlatformPath(path));
// Just decoding
assertEquals(path, URLRewriterUtils.decodeResourceURI(versionedPath));
assertEquals(path, URLRewriterUtils.decodeResourceURI(versionedPath, true));
// Encoding/decoding
assertEquals(path, URLRewriterUtils.decodeResourceURI(URLRewriterUtils.rewriteResourceURL(directRequest, path,
URLRewriterUtils.MATCH_ALL_PATH_MATCHERS, ExternalContext.Response.REWRITE_MODE_ABSOLUTE_PATH_NO_CONTEXT)));
URLRewriterUtils.MATCH_ALL_PATH_MATCHERS, ExternalContext.Response.REWRITE_MODE_ABSOLUTE_PATH_NO_CONTEXT), true));
}

// Check non-platform paths
final String[] customPaths = { "/opsla", "/configuration", "/xbl/acme/bar", "/forms/acme/bar", "/apps/myapp/bar", "/xforms-foo" };
final String[] decodedCustomPaths = { "/apps/opsla", "/apps/configuration", "/xbl/acme/bar", "/forms/acme/bar", "/apps/myapp/bar", "/apps/xforms-foo" };
final String appVersion = URLRewriterUtils.getApplicationResourceVersion();
int i = 0;
for (final String path: customPaths) {
// Make sure this is recognized as a non-platform path
assertFalse(URLRewriterUtils.isPlatformPath(path));

final String decodedCustomPath = decodedCustomPaths[i];

if (appVersion != null) {
// Case where there is an app version number

final String versionedPath = "/" + appVersion + path;
// Just decoding
assertEquals(path, URLRewriterUtils.decodeResourceURI(versionedPath));
assertEquals(decodedCustomPath, URLRewriterUtils.decodeResourceURI(versionedPath, true));
// Encoding/decoding
assertEquals(path, URLRewriterUtils.decodeResourceURI(URLRewriterUtils.rewriteResourceURL(directRequest, path,
URLRewriterUtils.MATCH_ALL_PATH_MATCHERS, ExternalContext.Response.REWRITE_MODE_ABSOLUTE_PATH_NO_CONTEXT)));
assertEquals(decodedCustomPath, URLRewriterUtils.decodeResourceURI(URLRewriterUtils.rewriteResourceURL(directRequest, path,
URLRewriterUtils.MATCH_ALL_PATH_MATCHERS, ExternalContext.Response.REWRITE_MODE_ABSOLUTE_PATH_NO_CONTEXT), true));
} else {
// Case where there is NO app version number

// Just decoding
assertEquals(path, URLRewriterUtils.decodeResourceURI(path));
assertEquals(decodedCustomPath, URLRewriterUtils.decodeResourceURI(path, true));
// Encoding/decoding
assertEquals(path, URLRewriterUtils.decodeResourceURI(URLRewriterUtils.rewriteResourceURL(directRequest, path,
URLRewriterUtils.MATCH_ALL_PATH_MATCHERS, ExternalContext.Response.REWRITE_MODE_ABSOLUTE_PATH_NO_CONTEXT)));
assertEquals(decodedCustomPath, URLRewriterUtils.decodeResourceURI(URLRewriterUtils.rewriteResourceURL(directRequest, path,
URLRewriterUtils.MATCH_ALL_PATH_MATCHERS, ExternalContext.Response.REWRITE_MODE_ABSOLUTE_PATH_NO_CONTEXT), true));
}
i++;
}
}
}
Expand Down

0 comments on commit bdb0096

Please sign in to comment.