Skip to content

Commit

Permalink
When adding and removing ResourceLinks dynamically, ensure that the g…
Browse files Browse the repository at this point in the history
…lobal resource is only visible via the ResourceLinkFactory when it is meant to be.

git-svn-id: https://svn.apache.org/repos/asf/tomcat/tc8.5.x/trunk@1757272 13f79535-47bb-0310-9956-ffa450edef68
  • Loading branch information
markt-asf committed Aug 22, 2016
1 parent 987cc4d commit d6b5600
Show file tree
Hide file tree
Showing 4 changed files with 172 additions and 0 deletions.
19 changes: 19 additions & 0 deletions java/org/apache/catalina/core/NamingContextListener.java
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
import org.apache.catalina.ContainerEvent;
import org.apache.catalina.ContainerListener;
import org.apache.catalina.Context;
import org.apache.catalina.Engine;
import org.apache.catalina.Host;
import org.apache.catalina.Lifecycle;
import org.apache.catalina.LifecycleEvent;
Expand All @@ -58,6 +59,7 @@
import org.apache.naming.ResourceRef;
import org.apache.naming.ServiceRef;
import org.apache.naming.TransactionRef;
import org.apache.naming.factory.ResourceLinkFactory;
import org.apache.tomcat.util.descriptor.web.ContextEjb;
import org.apache.tomcat.util.descriptor.web.ContextEnvironment;
import org.apache.tomcat.util.descriptor.web.ContextHandler;
Expand Down Expand Up @@ -316,6 +318,11 @@ public void lifecycleEvent(LifecycleEvent event) {
registry.unregisterComponent(objectName);
}
}

javax.naming.Context global = getGlobalNamingContext();
if (global != null) {
ResourceLinkFactory.deregisterGlobalResourceAccess(global);
}
} finally {
objectNames.clear();

Expand Down Expand Up @@ -1152,6 +1159,17 @@ public void addResourceLink(ContextResourceLink resourceLink) {
log.error(sm.getString("naming.bindFailed", e));
}

ResourceLinkFactory.registerGlobalResourceAccess(
getGlobalNamingContext(), resourceLink.getName(), resourceLink.getGlobal());
}


private javax.naming.Context getGlobalNamingContext() {
if (container instanceof Context) {
Engine e = (Engine) ((Context) container).getParent().getParent();
return e.getService().getServer().getGlobalNamingContext();
}
return null;
}


Expand Down Expand Up @@ -1269,6 +1287,7 @@ public void removeResourceLink(String name) {
log.error(sm.getString("naming.unbindFailed", e));
}

ResourceLinkFactory.deregisterGlobalResourceAccess(getGlobalNamingContext(), name);
}


Expand Down
61 changes: 61 additions & 0 deletions java/org/apache/naming/factory/ResourceLinkFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,10 @@
*/
package org.apache.naming.factory;

import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import javax.naming.Context;
import javax.naming.Name;
Expand All @@ -41,6 +44,8 @@ public class ResourceLinkFactory implements ObjectFactory {
*/
private static Context globalContext = null;

private static Map<ClassLoader,Map<String,String>> globalResourceRegistrations =
new ConcurrentHashMap<>();

// --------------------------------------------------------- Public Methods

Expand All @@ -59,6 +64,56 @@ public static void setGlobalContext(Context newGlobalContext) {
}


public static void registerGlobalResourceAccess(Context globalContext, String localName,
String globalName) {
validateGlobalContext(globalContext);
ClassLoader cl = Thread.currentThread().getContextClassLoader();
Map<String,String> registrations = globalResourceRegistrations.get(cl);
if (registrations == null) {
// Web application initialization is single threaded so this is
// safe.
registrations = new HashMap<>();
globalResourceRegistrations.put(cl, registrations);
}
registrations.put(localName, globalName);
}


public static void deregisterGlobalResourceAccess(Context globalContext, String localName) {
validateGlobalContext(globalContext);
ClassLoader cl = Thread.currentThread().getContextClassLoader();
Map<String,String> registrations = globalResourceRegistrations.get(cl);
if (registrations != null) {
registrations.remove(localName);
}
}


public static void deregisterGlobalResourceAccess(Context globalContext) {
validateGlobalContext(globalContext);
ClassLoader cl = Thread.currentThread().getContextClassLoader();
globalResourceRegistrations.remove(cl);
}


private static void validateGlobalContext(Context globalContext) {
if (ResourceLinkFactory.globalContext != null &&
ResourceLinkFactory.globalContext != globalContext) {
throw new SecurityException("Caller provided invalid global context");
}
}


private static boolean validateGlobalResourceAccess(String globalName) {
ClassLoader cl = Thread.currentThread().getContextClassLoader();
Map<String,String> registrations = globalResourceRegistrations.get(cl);
if (registrations != null && registrations.containsValue(globalName)) {
return true;
}
return false;
}


// -------------------------------------------------- ObjectFactory Methods

/**
Expand All @@ -82,6 +137,12 @@ public Object getObjectInstance(Object obj, Name name, Context nameCtx,
RefAddr refAddr = ref.get(ResourceLinkRef.GLOBALNAME);
if (refAddr != null) {
globalName = refAddr.getContent().toString();
// When running under a security manager confirm that the current
// web application has really been configured to access the specified
// global resource
if (!validateGlobalResourceAccess(globalName)) {
return null;
}
Object result = null;
result = globalContext.lookup(globalName);
// Check the expected type
Expand Down
87 changes: 87 additions & 0 deletions test/org/apache/naming/TestNamingContext.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
package org.apache.naming;

import javax.naming.Context;
import javax.naming.NamingException;

import org.apache.catalina.startup.Tomcat;
import org.apache.catalina.startup.TomcatBaseTest;
import org.apache.naming.factory.ResourceLinkFactory;
import org.apache.tomcat.util.descriptor.web.ContextEnvironment;
import org.apache.tomcat.util.descriptor.web.ContextResourceLink;
import org.junit.Assert;
import org.junit.Test;

public class TestNamingContext extends TomcatBaseTest {

private static final String COMP_ENV = "comp/env";
private static final String GLOBAL_NAME = "global";
private static final String LOCAL_NAME = "local";
private static final String DATA = "Cabbage";


@Test
public void testGlobalNaming() throws Exception {
Tomcat tomcat = getTomcatInstance();
tomcat.enableNaming();

org.apache.catalina.Context ctx = tomcat.addContext("", null);

tomcat.start();

Context webappInitial = ContextBindings.getContext(ctx);

// Nothing added at the moment so should be null
Object obj = doLookup(webappInitial, COMP_ENV + "/" + LOCAL_NAME);
Assert.assertNull(obj);

ContextEnvironment ce = new ContextEnvironment();
ce.setName(GLOBAL_NAME);
ce.setValue(DATA);
ce.setType(DATA.getClass().getName());

tomcat.getServer().getGlobalNamingResources().addEnvironment(ce);

// No link so still should be null
obj = doLookup(webappInitial, COMP_ENV + "/" + LOCAL_NAME);
Assert.assertNull(obj);

// Now add a resource link to the context
ContextResourceLink crl = new ContextResourceLink();
crl.setGlobal(GLOBAL_NAME);
crl.setName(LOCAL_NAME);
crl.setType(DATA.getClass().getName());
ctx.getNamingResources().addResourceLink(crl);

// Link exists so should be OK now
obj = doLookup(webappInitial, COMP_ENV + "/" + LOCAL_NAME);
Assert.assertEquals(DATA, obj);

// Try shortcut
ResourceLinkFactory factory = new ResourceLinkFactory();
ResourceLinkRef rlr = new ResourceLinkRef(DATA.getClass().getName(), GLOBAL_NAME, null, null);
obj = factory.getObjectInstance(rlr, null, null, null);
Assert.assertEquals(DATA, obj);

// Remove the link
ctx.getNamingResources().removeResourceLink(LOCAL_NAME);

// No link so should be null
obj = doLookup(webappInitial, COMP_ENV + "/" + LOCAL_NAME);
Assert.assertNull(obj);

// Shortcut should fail too
obj = factory.getObjectInstance(rlr, null, null, null);
Assert.assertNull(obj);
}


private Object doLookup(Context context, String name) {
Object result = null;
try {
result = context.lookup(name);
} catch (NamingException nnfe) {
// Ignore
}
return result;
}
}
5 changes: 5 additions & 0 deletions webapps/docs/changelog.xml
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,11 @@
>CVE-2016-5388</a>) by default and to provide a mechanism that can be
used to mitigate any future, similar issues. (markt)
</add>
<add>
When adding and removing <code>ResourceLink</code>s dynamically, ensure
that the global resource is only visible via the
<code>ResourceLinkFactory</code> when it is meant to be. (markt)
</add>
</changelog>
</subsection>
<subsection name="Coyote">
Expand Down

0 comments on commit d6b5600

Please sign in to comment.