modules/enterprise/binding/src/main/java/org/rhq/bindings/script/BaseRhqSchemeScriptSourceProvider.java
| 7 -
modules/enterprise/scripting/api/src/main/java/org/rhq/scripting/ScriptSourceProvider.java
| 16 ++
modules/enterprise/server/client-api/src/main/java/org/rhq/enterprise/client/RhqDownloadsScriptSourceProvider.java
| 66 ++++++++--
modules/enterprise/server/client-api/src/test/java/org/rhq/enterprise/client/test/RhqDownloadsScriptSourceProviderTest.java
| 4
modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/core/CoreServer.java
| 27 +++-
5 files changed, 102 insertions(+), 18 deletions(-)
New commits:
commit eeffaed93e68612eb6a88226479702d4f373e510
Author: Lukas Krejci <lkrejci(a)redhat.com>
Date: Tue May 28 03:11:56 2013 +0200
[BZ 967622 - Server CLI script can't require modules from rhq://downloads]
This was primarily caused by a new permission required by EAP 6.1 we've
switched to. To access the ModelControllerClient, the code now needs a
RuntimePermission("canAccessModelController").
We need the ModelControllerClient when determining the EAR installation
dir, which we in turn need when determining where to locate the scripts
in the "rhq://downloads" location. This is done while running a script,
which is done in a restricted access control context which does not and
should not have that permission.
The minimal fix is to wrap the getting of the ModelControllerClient in a
privileged action but some more "defensive" code was added in the
RhqDownloadScriptSourceProvider, too, to guard against different times it
might get instantiated during the script execution.
Javadocs were updated to warn about the security considerations when
writing a script source provider available on the server side.
diff --git
a/modules/enterprise/binding/src/main/java/org/rhq/bindings/script/BaseRhqSchemeScriptSourceProvider.java
b/modules/enterprise/binding/src/main/java/org/rhq/bindings/script/BaseRhqSchemeScriptSourceProvider.java
index 4c6756f..87241ef 100644
---
a/modules/enterprise/binding/src/main/java/org/rhq/bindings/script/BaseRhqSchemeScriptSourceProvider.java
+++
b/modules/enterprise/binding/src/main/java/org/rhq/bindings/script/BaseRhqSchemeScriptSourceProvider.java
@@ -55,8 +55,11 @@ public abstract class BaseRhqSchemeScriptSourceProvider implements
ScriptSourceP
* The base implementation of the {@link #getScriptSource(URI)} method
* only checks that the scheme of the URI is "rhq" and that the scheme
* specific part starts with "//".
- *
- * @param scriptUri
+ * <p/>
+ * Please follow the general suggestions mentioned in {@link
ScriptSourceProvider#getScriptSource(java.net.URI)}
+ * docs.
+ *
+ * @param scriptUri the URI to load the script from
* @return the reader of the script or null if the script could not be
* found using the URI
*
diff --git
a/modules/enterprise/scripting/api/src/main/java/org/rhq/scripting/ScriptSourceProvider.java
b/modules/enterprise/scripting/api/src/main/java/org/rhq/scripting/ScriptSourceProvider.java
index e65f793..fb0f606 100644
---
a/modules/enterprise/scripting/api/src/main/java/org/rhq/scripting/ScriptSourceProvider.java
+++
b/modules/enterprise/scripting/api/src/main/java/org/rhq/scripting/ScriptSourceProvider.java
@@ -29,14 +29,26 @@ import java.net.URI;
* <p>
* Implementations of this interface can be located using the {@link
ScriptSourceProviderFactory}
* if they are registered in META-INF/services.
- *
+ * <p/>
+ * Note that instances of this class can be created and called in an access control
context with limited privileges.
+ * If you need to make safe calls that require privileges not granted to a script run in
the RHQ server (by default this
+ * is determined by the {@code org.rhq.bindings.StandardScriptPermissions} class), make
sure to call such actions with
+ * elevated permissions through
+ * {@link
java.security.AccessController#doPrivileged(java.security.PrivilegedExceptionAction)} or
any of its
+ * derivatives.
+ * <p/>
+ * For example JNDI look-ups are not allowed by default for the scripts, so if your
provider needs to perform some
+ * JNDI lookups to locate the script to include, you need to wrap any code that does a
JNDI look-up as above.
+ *
* @author Lukas Krejci
*/
public interface ScriptSourceProvider {
/**
* Returns the reader of the source of the script specified by given location.
- *
+ * <p/>
+ * Review the class description for the security considerations.
+ *
* @param location the location of the script
* @return the reader of the script source or null if it could not be found
*/
diff --git
a/modules/enterprise/server/client-api/src/main/java/org/rhq/enterprise/client/RhqDownloadsScriptSourceProvider.java
b/modules/enterprise/server/client-api/src/main/java/org/rhq/enterprise/client/RhqDownloadsScriptSourceProvider.java
index 1cbbe39..23e8fb5 100644
---
a/modules/enterprise/server/client-api/src/main/java/org/rhq/enterprise/client/RhqDownloadsScriptSourceProvider.java
+++
b/modules/enterprise/server/client-api/src/main/java/org/rhq/enterprise/client/RhqDownloadsScriptSourceProvider.java
@@ -26,6 +26,11 @@ import java.io.FileNotFoundException;
import java.io.InputStreamReader;
import java.io.Reader;
import java.net.URI;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+import java.util.concurrent.Callable;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -45,20 +50,67 @@ public class RhqDownloadsScriptSourceProvider extends
BaseRhqSchemeScriptSourceP
private CoreServerMBean coreServer;
+ /**
+ * A bunch of methods optionally enclosed in privileged actions to ensure that we can
access the information
+ * inside RHQ server even though it might not be accessible in the access control
context the scripts run in
+ * in the RHQ server.
+ */
+ private static class SecurityActions {
+ private SecurityActions() {
+
+ }
+
+ private static CoreServerMBean lookupCoreServer() {
+ if (System.getSecurityManager() == null) {
+ return LookupUtil.getCoreServer();
+ } else {
+ return AccessController.doPrivileged(new
PrivilegedAction<CoreServerMBean>() {
+ @Override
+ public CoreServerMBean run() {
+ return LookupUtil.getCoreServer();
+ }
+ });
+ }
+ }
+
+ private static File getDownloadDir(final CoreServerMBean coreServer) {
+ File earDeployDir;
+ if (System.getSecurityManager() == null) {
+ earDeployDir = coreServer.getEarDeploymentDir();
+ } else {
+ earDeployDir = AccessController.doPrivileged(new
PrivilegedAction<File>() {
+ @Override
+ public File run() {
+ return coreServer.getEarDeploymentDir();
+ }
+ });
+ }
+ File downloadDir = new File(earDeployDir, "rhq-downloads");
+ return downloadDir;
+ }
+ }
+
public RhqDownloadsScriptSourceProvider() {
- this(LookupUtil.getCoreServer());
+ //we need to do a safe JNDI lookup, but we may run in unprivileged context...
+ this(SecurityActions.lookupCoreServer());
}
-
+
+ /**
+ * This is meant only for testing purposes.
+ *
+ * @param coreServerMBean the CoreServer MBean to use
+ */
public RhqDownloadsScriptSourceProvider(CoreServerMBean coreServerMBean) {
super(AUTHORITY);
this.coreServer = coreServerMBean;
}
-
+
@Override
protected Reader doGetScriptSource(URI scriptUri) {
String path = scriptUri.getPath().substring(1); //remove the leading /
- File downloadsDir = getDownloadHomeDir();
+ //We're going to be doing an MBean call here which the scripts don't have
privs for by default
+ File downloadsDir = SecurityActions.getDownloadDir(coreServer);
File scriptDownloads = new File(downloadsDir, "script-modules");
File file = new File(scriptDownloads, path);
@@ -69,10 +121,4 @@ public class RhqDownloadsScriptSourceProvider extends
BaseRhqSchemeScriptSourceP
return null;
}
}
-
- private File getDownloadHomeDir() {
- File earDeployDir = this.coreServer.getEarDeploymentDir();
- File downloadDir = new File(earDeployDir, "rhq-downloads");
- return downloadDir;
- }
}
diff --git
a/modules/enterprise/server/client-api/src/test/java/org/rhq/enterprise/client/test/RhqDownloadsScriptSourceProviderTest.java
b/modules/enterprise/server/client-api/src/test/java/org/rhq/enterprise/client/test/RhqDownloadsScriptSourceProviderTest.java
index e62dd32..1b366ba 100644
---
a/modules/enterprise/server/client-api/src/test/java/org/rhq/enterprise/client/test/RhqDownloadsScriptSourceProviderTest.java
+++
b/modules/enterprise/server/client-api/src/test/java/org/rhq/enterprise/client/test/RhqDownloadsScriptSourceProviderTest.java
@@ -85,8 +85,8 @@ public class RhqDownloadsScriptSourceProviderTest {
try {
String contents = StreamUtil.slurp(rdr);
assertEquals(contents, EXPECTED_CONTENTS, "Unexpected script
loaded");
- } finally {
- rdr.close();
+ } finally {
+ StreamUtil.safeClose(rdr);
}
}
}
diff --git
a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/core/CoreServer.java
b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/core/CoreServer.java
index 9a60f12..b74b704 100644
---
a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/core/CoreServer.java
+++
b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/core/CoreServer.java
@@ -22,6 +22,8 @@ import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.lang.management.ManagementFactory;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
import java.util.Date;
import java.util.HashMap;
import java.util.Properties;
@@ -69,6 +71,24 @@ public class CoreServer implements CoreServerMBean {
*/
private static final String PROP_BUILD_DATE = "Build-Date";
+ private static class SecurityActions {
+ private SecurityActions() {
+
+ }
+
+ private static ModelControllerClient getModelControllerClient() {
+ if (System.getSecurityManager() == null) {
+ return ManagementService.getClient();
+ } else {
+ return AccessController.doPrivileged(new
PrivilegedAction<ModelControllerClient>() {
+ @Override
+ public ModelControllerClient run() {
+ return ManagementService.getClient();
+ }
+ });
+ }
+ }
+ }
private Properties buildProps;
private Date bootTime;
@@ -136,7 +156,10 @@ public class CoreServer implements CoreServerMBean {
@Override
public File getEarDeploymentDir() {
- ModelControllerClient mcc = ManagementService.getClient();
+ //Getting model controller client requires privs our callers might not have, but
we want to provide this
+ //function even to them.
+ ModelControllerClient mcc = SecurityActions.getModelControllerClient();
+
try {
DeploymentJBossASClient client = new DeploymentJBossASClient(mcc);
String earPath = client.getDeploymentPath(RHQConstants.EAR_FILE_NAME);
@@ -229,4 +252,4 @@ public class CoreServer implements CoreServerMBean {
return buildProps;
}
-}
\ No newline at end of file
+}
Show replies by date