SLING-11128 : Escape tenant id
diff --git a/.gitignore b/.gitignore
index 5b783ed..38f5ca4 100644
--- a/.gitignore
+++ b/.gitignore
@@ -14,4 +14,5 @@
.vlt
.DS_Store
jcr.log
+.vscode
atlassian-ide-plugin.xml
diff --git a/pom.xml b/pom.xml
index 0181a30..b1779fe 100644
--- a/pom.xml
+++ b/pom.xml
@@ -21,14 +21,13 @@
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.apache.sling</groupId>
- <artifactId>sling</artifactId>
- <version>34</version>
+ <artifactId>sling-bundle-parent</artifactId>
+ <version>46</version>
<relativePath />
</parent>
<artifactId>org.apache.sling.tenant</artifactId>
<version>1.1.5-SNAPSHOT</version>
- <packaging>bundle</packaging>
<name>Apache Sling Tenant</name>
<description>
@@ -42,11 +41,15 @@
<tag>HEAD</tag>
</scm>
+ <properties>
+ <project.build.outputTimestamp>1</project.build.outputTimestamp>
+ </properties>
+
<build>
<plugins>
<plugin>
<groupId>org.apache.sling</groupId>
- <artifactId>maven-sling-plugin</artifactId>
+ <artifactId>sling-maven-plugin</artifactId>
<executions>
<execution>
<id>generate-adapter-metadata</id>
@@ -57,11 +60,6 @@
</execution>
</executions>
</plugin>
- <plugin>
- <groupId>org.apache.felix</groupId>
- <artifactId>maven-bundle-plugin</artifactId>
- <extensions>true</extensions>
- </plugin>
</plugins>
</build>
@@ -69,7 +67,13 @@
<dependency>
<groupId>org.apache.sling</groupId>
<artifactId>org.apache.sling.api</artifactId>
- <version>2.5.0</version>
+ <version>2.22.0</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.sling</groupId>
+ <artifactId>org.apache.sling.xss</artifactId>
+ <version>2.2.14</version>
<scope>provided</scope>
</dependency>
<dependency>
@@ -81,11 +85,13 @@
<dependency>
<groupId>org.osgi</groupId>
<artifactId>org.osgi.service.component.annotations</artifactId>
- <scope>provided</scope>
+ <version>1.4.0</version>
+ <scope>provided</scope>
</dependency>
<dependency>
<groupId>org.osgi</groupId>
- <artifactId>org.osgi.service.metatype.annotations</artifactId>
+ <artifactId>org.osgi.service.metatype.annotations</artifactId>
+ <version>1.4.0</version>
<scope>provided</scope>
</dependency>
<dependency>
@@ -101,7 +107,8 @@
<dependency>
<groupId>org.osgi</groupId>
<artifactId>osgi.core</artifactId>
- <scope>provided</scope>
+ <version>6.0.0</version>
+ <scope>provided</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
@@ -109,7 +116,8 @@
</dependency>
<dependency>
<groupId>org.osgi</groupId>
- <artifactId>org.osgi.annotation.versioning</artifactId>
+ <artifactId>org.osgi.annotation.versioning</artifactId>
+ <version>1.1.0</version>
<scope>provided</scope>
</dependency>
<!-- Webconsole -->
diff --git a/src/main/java/org/apache/sling/tenant/internal/TenantProviderImpl.java b/src/main/java/org/apache/sling/tenant/internal/TenantProviderImpl.java
index ab4e12a..bcd021c 100644
--- a/src/main/java/org/apache/sling/tenant/internal/TenantProviderImpl.java
+++ b/src/main/java/org/apache/sling/tenant/internal/TenantProviderImpl.java
@@ -43,6 +43,7 @@
import org.apache.sling.tenant.internal.console.WebConsolePlugin;
import org.apache.sling.tenant.spi.TenantCustomizer;
import org.apache.sling.tenant.spi.TenantManagerHook;
+import org.apache.sling.xss.XSSAPI;
import org.osgi.framework.BundleContext;
import org.osgi.framework.Constants;
import org.osgi.framework.Filter;
@@ -54,6 +55,7 @@
import org.osgi.service.component.annotations.Reference;
import org.osgi.service.component.annotations.ReferenceCardinality;
import org.osgi.service.component.annotations.ReferencePolicy;
+import org.osgi.service.component.annotations.ReferencePolicyOption;
import org.osgi.service.metatype.annotations.AttributeDefinition;
import org.osgi.service.metatype.annotations.Designate;
import org.osgi.service.metatype.annotations.ObjectClassDefinition;
@@ -119,18 +121,21 @@
private String tenantRootPath = RESOURCE_TENANT_ROOT;
- @Reference
- private ResourceResolverFactory factory;
+ private final ResourceResolverFactory factory;
private TenantAdapterFactory adapterFactory;
private WebConsolePlugin plugin;
@Activate
- protected void activate(final BundleContext bundleContext, final Configuration configuration) {
+ public TenantProviderImpl(final BundleContext bundleContext,
+ final @Reference(policyOption = ReferencePolicyOption.GREEDY) XSSAPI xss,
+ final @Reference ResourceResolverFactory resourceResolverFactory,
+ final Configuration configuration) {
+ this.factory = resourceResolverFactory;
this.tenantRootPath = configuration.tenant_root();
this.adapterFactory = new TenantAdapterFactory(bundleContext, this, configuration.tenant_path_matcher());
- this.plugin = new WebConsolePlugin(bundleContext, this);
+ this.plugin = new WebConsolePlugin(bundleContext, this, xss);
}
@Deactivate
@@ -347,7 +352,6 @@
});
}
- @SuppressWarnings("serial")
private Resource createTenantResource(final ResourceResolver resolver, final String tenantId,
final Map<String, Object> properties) throws PersistenceException {
@@ -384,7 +388,17 @@
}
private Resource getTenantResource(final ResourceResolver resolver, final String tenantId) {
- return resolver.getResource(tenantRootPath + "/" + tenantId);
+ Resource rsrc = resolver.getResource(tenantRootPath + "/" + tenantId);
+ if ( rsrc == null ) {
+ // this is a hack for special characters that otherwise would need escaping before getResource() is called
+ for(final Resource r : resolver.getResource(tenantRootPath).getChildren()) {
+ if ( tenantId.equals(r.getName())) {
+ rsrc = r;
+ break;
+ }
+ }
+ }
+ return rsrc;
}
private void customizeTenant(final Resource tenantRes, final Tenant tenant, boolean isCreate) {
diff --git a/src/main/java/org/apache/sling/tenant/internal/console/WebConsolePlugin.java b/src/main/java/org/apache/sling/tenant/internal/console/WebConsolePlugin.java
index fb7871e..d028b15 100644
--- a/src/main/java/org/apache/sling/tenant/internal/console/WebConsolePlugin.java
+++ b/src/main/java/org/apache/sling/tenant/internal/console/WebConsolePlugin.java
@@ -20,6 +20,7 @@
import java.io.IOException;
import java.io.PrintWriter;
+import java.net.URLEncoder;
import java.util.Dictionary;
import java.util.HashMap;
import java.util.Hashtable;
@@ -32,9 +33,11 @@
import org.apache.sling.tenant.Tenant;
import org.apache.sling.tenant.internal.TenantProviderImpl;
+import org.apache.sling.xss.XSSAPI;
import org.osgi.framework.BundleContext;
import org.osgi.framework.Constants;
import org.osgi.framework.ServiceRegistration;
+import org.slf4j.LoggerFactory;
/**
* This is a webconsole plugin displaying the active queues, some statistics and
@@ -61,17 +64,11 @@
private TenantProviderImpl tenantProvider;
- private final ServiceRegistration<?> service;
+ private final ServiceRegistration<Servlet> service;
- /** Escape the output for html. */
- private String escape(final String text) {
- if (text == null) {
- return "";
- }
- return text.replace("&", "&").replace("<", "<").replace(">", ">");
- }
+ private final XSSAPI xss;
- public WebConsolePlugin(final BundleContext bundleContext, final TenantProviderImpl tenantProvider) {
+ public WebConsolePlugin(final BundleContext bundleContext, final TenantProviderImpl tenantProvider, final XSSAPI xss) {
this.tenantProvider = tenantProvider;
Dictionary<String, Object> props = new Hashtable<String, Object>();
@@ -79,16 +76,13 @@
props.put("felix.webconsole.label", LABEL);
props.put("felix.webconsole.title", TITLE);
props.put("felix.webconsole.category", CATEGORY);
- // props.put("felix.webconsole.configprinter.modes", new String[]{"zip",
- // "txt"});
- this.service = bundleContext.registerService(Servlet.class.getCanonicalName(), this, props);
+ this.xss = xss;
+ this.service = bundleContext.registerService(Servlet.class, this, props);
}
public void dispose() {
- if (this.service != null) {
- this.service.unregister();
- }
+ this.service.unregister();
}
@Override
@@ -113,16 +107,15 @@
if (msg == null) {
redirectTo = path;
} else {
- redirectTo = path + "?message=" + msg;
+ redirectTo = path.concat("?message=").concat(URLEncoder.encode(msg, "UTF-8"));
}
- resp.sendRedirect(redirectTo);
+ resp.sendRedirect(resp.encodeRedirectURL(redirectTo));
}
- private void removeTenant(HttpServletRequest request) {
+ private void removeTenant(final HttpServletRequest request) {
final String tenantId = request.getParameter(REQ_PRM_TENANT_ID);
final Tenant tenant = this.tenantProvider.getTenant(tenantId);
-
if (tenant != null) {
this.tenantProvider.remove(tenant);
}
@@ -130,10 +123,9 @@
private void printForm(final PrintWriter pw, final Tenant t, final String buttonLabel, final String cmd) {
pw.printf("<button class='ui-state-default ui-corner-all' onclick='javascript:cmdsubmit(\"%s\", \"%s\");'>"
- + "%s</button>", cmd, (t != null ? t.getId() : ""), buttonLabel);
+ + "%s</button>", cmd, (t != null ? xss.encodeForJSString(t.getId()) : ""), xss.encodeForHTML(buttonLabel));
}
- @SuppressWarnings("serial")
private Tenant createTenant(HttpServletRequest request) {
final String tenantName = request.getParameter(REQ_PRM_TENANT_NAME);
final String tenantId = request.getParameter(REQ_PRM_TENANT_ID);
@@ -189,19 +181,19 @@
pw.printf("<p class='statline ui-state-highlight'>Registered Tenants</p>");
}
pw.println("<div class='ui-widget-header ui-corner-top buttonGroup'>");
- pw.printf("<span style='float: left; margin-left: 1em'>Tenant : %s </span>", escape(tenant.getName()));
+ pw.printf("<span style='float: left; margin-left: 1em'>Tenant : %s </span>", xss.encodeForHTML(tenant.getName()));
this.printForm(pw, tenant, "Remove", "remove");
pw.println("</div>");
pw.println("<table class='nicetable'><tbody>");
- pw.printf("<tr><td style='width: 30%%;'>Identifier</td><td>%s</td></tr>", escape(tenant.getId()));
- pw.printf("<tr><td style='width: 30%%;'>Name</td><td>%s</td></tr>", escape(tenant.getName()));
- pw.printf("<tr><td style='width: 30%%;'>Description</td><td>%s</td></tr>", escape(tenant.getDescription()));
+ pw.printf("<tr><td style='width: 30%%;'>Identifier</td><td>%s</td></tr>", xss.encodeForHTML(tenant.getId()));
+ pw.printf("<tr><td style='width: 30%%;'>Name</td><td>%s</td></tr>", xss.encodeForHTML(tenant.getName()));
+ pw.printf("<tr><td style='width: 30%%;'>Description</td><td>%s</td></tr>", xss.encodeForHTML(tenant.getDescription()));
pw.println("</tbody></table>");
}
// no existing tenants
if (count == 0) {
- pw.printf("<p class='statline ui-state-highlight'>There are not registered tenants</p>");
+ pw.printf("<p class='statline ui-state-highlight'>There are no registered tenants</p>");
}
}
}
diff --git a/src/test/java/org/apache/sling/tenant/internal/TenantProviderImplTest.java b/src/test/java/org/apache/sling/tenant/internal/TenantProviderImplTest.java
index 1628fe5..0f47ec8 100644
--- a/src/test/java/org/apache/sling/tenant/internal/TenantProviderImplTest.java
+++ b/src/test/java/org/apache/sling/tenant/internal/TenantProviderImplTest.java
@@ -35,13 +35,11 @@
@Test
public void testListTenantsWithoutTenantRoot() throws Exception {
- TenantProviderImpl provider = new TenantProviderImpl();
final ResourceResolverFactory rrf = Mockito.mock(ResourceResolverFactory.class);
final BundleContext context = Mockito.mock(BundleContext.class);
final ResourceResolver rr = Mockito.mock(ResourceResolver.class);
Mockito.when(rrf.getServiceResourceResolver(
Mockito.anyMapOf(String.class, Object.class))).thenReturn(rr);
- set(provider, "factory", rrf);
TenantProviderImpl.Configuration configuration = new TenantProviderImpl.Configuration() {
@Override
public Class<? extends Annotation> annotationType() {
@@ -56,16 +54,9 @@
return new String[] {};
}
};
- provider.activate(context, configuration);
+ TenantProviderImpl provider = new TenantProviderImpl(context, null, rrf, configuration);
Iterator<Tenant> tenants = provider.getTenants();
TestCase.assertNotNull(tenants);
TestCase.assertFalse(tenants.hasNext());
}
-
- private static void set(Object o, String name, Object value) throws Exception {
- final Field f = o.getClass().getDeclaredField(name);
- f.setAccessible(true);
- f.set(o, value);
- }
-
}