You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by al...@apache.org on 2020/01/30 14:34:07 UTC
[ignite] branch master updated: IGNITE-12282 Access restriction to
the internal package of Ignite - Fixes #7137.
This is an automated email from the ASF dual-hosted git repository.
alexpl pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ignite.git
The following commit(s) were added to refs/heads/master by this push:
new 906fa9e IGNITE-12282 Access restriction to the internal package of Ignite - Fixes #7137.
906fa9e is described below
commit 906fa9eed60c45954559c02fee5214dd43a53d7c
Author: d.garus <ga...@gmail.com>
AuthorDate: Thu Jan 30 17:25:38 2020 +0300
IGNITE-12282 Access restriction to the internal package of Ignite - Fixes #7137.
Signed-off-by: Aleksey Plekhanov <pl...@gmail.com>
---
.../deployment/GridDeploymentClassLoader.java | 5 +
.../security/IgniteSecurityProcessor.java | 49 ++++++-
.../processors/security/SecurityUtils.java | 3 +
.../security/sandbox/AbstractSandboxTest.java | 44 +++++++
.../AccessToClassesInsideInternalPackageTest.java | 141 +++++++++++++++++++++
.../sandbox/DoPrivilegedOnRemoteNodeTest.java | 38 +-----
.../ignite/testsuites/SecurityTestSuite.java | 4 +-
7 files changed, 248 insertions(+), 36 deletions(-)
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/managers/deployment/GridDeploymentClassLoader.java b/modules/core/src/main/java/org/apache/ignite/internal/managers/deployment/GridDeploymentClassLoader.java
index 29fb531..bb5458c 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/managers/deployment/GridDeploymentClassLoader.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/managers/deployment/GridDeploymentClassLoader.java
@@ -47,6 +47,8 @@ import org.apache.ignite.internal.util.typedef.internal.U;
import org.apache.ignite.lang.IgniteUuid;
import org.jetbrains.annotations.Nullable;
+import static org.apache.ignite.internal.processors.security.SecurityUtils.IGNITE_INTERNAL_PACKAGE;
+
/**
* Class loader that is able to resolve task subclasses and resources
* by requesting remote node. Every class that could not be resolved
@@ -62,6 +64,9 @@ class GridDeploymentClassLoader extends ClassLoader implements GridDeploymentInf
static {
Permissions perms = new Permissions();
+ perms.add(new RuntimePermission("accessClassInPackage." + IGNITE_INTERNAL_PACKAGE));
+ perms.add(new RuntimePermission("accessClassInPackage." + IGNITE_INTERNAL_PACKAGE + ".*"));
+
perms.setReadOnly();
PROTECTION_DOMAIN = new ProtectionDomain(null, perms);
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/security/IgniteSecurityProcessor.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/security/IgniteSecurityProcessor.java
index ca23498..c8f8868 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/security/IgniteSecurityProcessor.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/security/IgniteSecurityProcessor.java
@@ -17,10 +17,12 @@
package org.apache.ignite.internal.processors.security;
+import java.security.Security;
import java.util.Collection;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicInteger;
import org.apache.ignite.IgniteCheckedException;
import org.apache.ignite.cluster.ClusterNode;
import org.apache.ignite.internal.GridKernalContext;
@@ -45,6 +47,7 @@ import org.jetbrains.annotations.Nullable;
import static org.apache.ignite.events.EventType.EVT_NODE_FAILED;
import static org.apache.ignite.events.EventType.EVT_NODE_LEFT;
+import static org.apache.ignite.internal.processors.security.SecurityUtils.IGNITE_INTERNAL_PACKAGE;
import static org.apache.ignite.internal.processors.security.SecurityUtils.MSG_SEC_PROC_CLS_IS_INVALID;
import static org.apache.ignite.internal.processors.security.SecurityUtils.hasSecurityManager;
import static org.apache.ignite.internal.processors.security.SecurityUtils.nodeSecurityContext;
@@ -56,6 +59,9 @@ public class IgniteSecurityProcessor implements IgniteSecurity, GridProcessor {
/** Internal attribute name constant. */
public static final String ATTR_GRID_SEC_PROC_CLASS = "grid.security.processor.class";
+ /** Number of started nodes with the sandbox enabled. */
+ private static final AtomicInteger SANDBOXED_NODES_COUNTER = new AtomicInteger();
+
/** Current security context. */
private final ThreadLocal<SecurityContext> curSecCtx = ThreadLocal.withInitial(this::localSecurityContext);
@@ -175,8 +181,11 @@ public class IgniteSecurityProcessor implements IgniteSecurity, GridProcessor {
secPrc.start();
- if (hasSecurityManager() && secPrc.sandboxEnabled())
+ if (hasSecurityManager() && secPrc.sandboxEnabled()) {
sandbox = new AccessControllerSandbox(this);
+
+ updatePackageAccessProperty();
+ }
else {
if (secPrc.sandboxEnabled()) {
ctx.log(getClass()).warning("GridSecurityProcessor#sandboxEnabled returns true, " +
@@ -188,11 +197,49 @@ public class IgniteSecurityProcessor implements IgniteSecurity, GridProcessor {
}
}
+ /**
+ * Updates the package access property to specify the internal Ignite package.
+ */
+ private void updatePackageAccessProperty() {
+ synchronized (SANDBOXED_NODES_COUNTER) {
+ if (SANDBOXED_NODES_COUNTER.getAndIncrement() == 0) {
+ String packAccess = Security.getProperty("package.access");
+
+ if (!F.isEmpty(packAccess)) {
+ if (!packAccess.contains(IGNITE_INTERNAL_PACKAGE))
+ Security.setProperty("package.access", packAccess + ',' + IGNITE_INTERNAL_PACKAGE);
+ }
+ else
+ Security.setProperty("package.access", IGNITE_INTERNAL_PACKAGE);
+ }
+ }
+ }
+
/** {@inheritDoc} */
@Override public void stop(boolean cancel) throws IgniteCheckedException {
+ clearPackageAccessProperty();
+
secPrc.stop(cancel);
}
+ /**
+ *
+ */
+ private void clearPackageAccessProperty() {
+ if (hasSecurityManager() && secPrc.sandboxEnabled()) {
+ synchronized (SANDBOXED_NODES_COUNTER) {
+ if (SANDBOXED_NODES_COUNTER.decrementAndGet() == 0) {
+ String packAccess = Security.getProperty("package.access");
+
+ if (packAccess.equals(IGNITE_INTERNAL_PACKAGE))
+ Security.setProperty("package.access", null);
+ else if (packAccess.contains(',' + IGNITE_INTERNAL_PACKAGE))
+ Security.setProperty("package.access", packAccess.replace(',' + IGNITE_INTERNAL_PACKAGE, ""));
+ }
+ }
+ }
+ }
+
/** {@inheritDoc} */
@Override public void onKernalStart(boolean active) throws IgniteCheckedException {
ctx.event().addDiscoveryEventListener(
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/security/SecurityUtils.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/security/SecurityUtils.java
index 298eddb..b7e84d7 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/security/SecurityUtils.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/security/SecurityUtils.java
@@ -52,6 +52,9 @@ public class SecurityUtils {
"is not equal to remote node's grid security processor class " +
"[locNodeId=%s, rmtNodeId=%s, locCls=%s, rmtCls=%s]";
+ /** Ignite internal package. */
+ public static final String IGNITE_INTERNAL_PACKAGE = "org.apache.ignite.internal";
+
/** Default serialization version. */
private static final int DFLT_SERIALIZE_VERSION = isSecurityCompatibilityMode() ? 1 : 2;
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/security/sandbox/AbstractSandboxTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/security/sandbox/AbstractSandboxTest.java
index 1bee9060..8af4a75 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/security/sandbox/AbstractSandboxTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/security/sandbox/AbstractSandboxTest.java
@@ -17,14 +17,23 @@
package org.apache.ignite.internal.processors.security.sandbox;
+import java.io.File;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
import java.security.AllPermission;
import java.security.CodeSource;
import java.security.PermissionCollection;
import java.security.Permissions;
import java.security.Policy;
import java.util.PropertyPermission;
+import javax.tools.JavaCompiler;
+import javax.tools.ToolProvider;
import org.apache.ignite.Ignite;
import org.apache.ignite.internal.processors.security.AbstractSecurityTest;
+import org.apache.ignite.lang.IgniteCallable;
import org.apache.ignite.testframework.GridTestUtils;
import static org.apache.ignite.plugin.security.SecurityPermissionSetBuilder.ALLOW_ALL;
@@ -125,4 +134,39 @@ public abstract class AbstractSandboxTest extends AbstractSecurityTest {
assertNull(System.getProperty(PROP_NAME));
}
+
+ /**
+ * Creates instance of IgniteCallable from passed src string.
+ */
+ protected <T> IgniteCallable<T> callable(Path srcTmpDir, String clsName, String src) {
+ try {
+ URLClassLoader clsLdr = prepareClassLoader(srcTmpDir, clsName + ".java", src);
+
+ Class<?> cls = clsLdr.loadClass(clsName);
+
+ return (IgniteCallable<T>)cls.newInstance();
+ }
+ catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Prepares class loader.
+ */
+ private URLClassLoader prepareClassLoader(Path srcTmpDir, String clsName, String src) throws Exception {
+ Files.createDirectories(srcTmpDir);
+
+ File srcFile = new File(srcTmpDir.toFile(), clsName);
+
+ Path srcFilePath = Files.write(srcFile.toPath(), src.getBytes(StandardCharsets.UTF_8));
+
+ JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
+
+ compiler.run(null, null, null, srcFilePath.toString());
+
+ assertTrue("Failed to remove source file.", srcFile.delete());
+
+ return new URLClassLoader(new URL[] {srcTmpDir.toUri().toURL()});
+ }
}
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/security/sandbox/AccessToClassesInsideInternalPackageTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/security/sandbox/AccessToClassesInsideInternalPackageTest.java
new file mode 100644
index 0000000..edddb4d
--- /dev/null
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/security/sandbox/AccessToClassesInsideInternalPackageTest.java
@@ -0,0 +1,141 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.processors.security.sandbox;
+
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.security.AccessControlException;
+import java.security.Permissions;
+import org.apache.ignite.Ignite;
+import org.apache.ignite.IgniteCompute;
+import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.internal.util.typedef.internal.U;
+import org.apache.ignite.lang.IgniteCallable;
+import org.apache.ignite.spi.deployment.local.LocalDeploymentSpi;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.apache.ignite.internal.processors.security.SecurityUtils.IGNITE_INTERNAL_PACKAGE;
+import static org.apache.ignite.plugin.security.SecurityPermissionSetBuilder.ALLOW_ALL;
+import static org.apache.ignite.testframework.GridTestUtils.assertThrowsWithCause;
+
+/**
+ * The test shows: a subject that does not have appropriate {@code accessClassInPackage.{internal_package_name}} runtime
+ * permissions cannot create an object (T2 class) from an internal package and does not have access to static methods of
+ * internal classes.
+ */
+public class AccessToClassesInsideInternalPackageTest extends AbstractSandboxTest {
+ /** */
+ private static final String CREATE_INSTANCE_CLS_NAME = "TestIgniteCallable";
+
+ /** Callable that creates an instance of T2 from internal Ignite package. */
+ private static final String CREATE_INSTANCE_SRC = "import org.apache.ignite.lang.IgniteCallable;\n" +
+ "import org.apache.ignite.internal.util.typedef.T2;\n" +
+ "\n" +
+ "public class TestIgniteCallable implements IgniteCallable {\n" +
+ " public Object call() throws Exception {\n" +
+ " return new T2<>(\"a\", \"b\");\n" +
+ " }" +
+ "}";
+
+ /** */
+ private static final String CALL_INTERNAL_CLASS_METHOD_CLS_NAME = "TestInternalUtilsCallable";
+
+ /** Callable that calls a static class method from internal Ignite package. */
+ private static final String CALL_INTERNAL_CLASS_METHOD_SRC =
+ "import org.apache.ignite.internal.IgnitionEx;\n" +
+ "import org.apache.ignite.lang.IgniteCallable;\n" +
+ "\n" +
+ "public class TestInternalUtilsCallable implements IgniteCallable {\n" +
+ " @Override public Object call() throws Exception {\n" +
+ " return IgnitionEx.isDaemon();\n" +
+ " }\n" +
+ "}";
+
+ /** Node that has access to internal Ignite package. */
+ private static final String ALLOWED = "allowed";
+
+ /** Node that does not have access to internal Ignite package. */
+ private static final String FORBIDDEN = "forbidden";
+
+ /** */
+ private Path srcTmpDir;
+
+ /** */
+ @Test
+ public void testCreateInstance() {
+ IgniteCallable<Object> c = callable(srcTmpDir, CREATE_INSTANCE_CLS_NAME, CREATE_INSTANCE_SRC);
+
+ assertNotNull(compute(grid(ALLOWED)).call(c));
+
+ assertThrowsWithCause(() -> compute(grid(FORBIDDEN)).call(c), AccessControlException.class);
+ }
+
+ /** */
+ @Test
+ public void testCallStaticMethod() {
+ IgniteCallable<Object> c = callable(srcTmpDir, CALL_INTERNAL_CLASS_METHOD_CLS_NAME,
+ CALL_INTERNAL_CLASS_METHOD_SRC);
+
+ assertNotNull(compute(grid(ALLOWED)).call(c));
+
+ assertThrowsWithCause(() -> compute(grid(FORBIDDEN)).call(c), AccessControlException.class);
+ }
+
+ /** {@inheritDoc} */
+ @Override protected void prepareCluster() throws Exception {
+ Ignite srv = startGrid("srv", ALLOW_ALL, false);
+
+ Permissions perms = new Permissions();
+
+ perms.add(new RuntimePermission("accessClassInPackage." + IGNITE_INTERNAL_PACKAGE));
+ perms.add(new RuntimePermission("accessClassInPackage." + IGNITE_INTERNAL_PACKAGE + ".*"));
+
+ startGrid(ALLOWED, ALLOW_ALL, perms, false);
+
+ startGrid(FORBIDDEN, ALLOW_ALL, false);
+
+ srv.cluster().active(true);
+ }
+
+ /** {@inheritDoc} */
+ @Override protected IgniteConfiguration getConfiguration(String igniteInstanceName) throws Exception {
+ return super.getConfiguration(igniteInstanceName)
+ .setDeploymentSpi(new LocalDeploymentSpi());
+ }
+
+ /** */
+ @Before
+ public void setUp() throws Exception {
+ srcTmpDir = Files.createTempDirectory(getClass().getSimpleName());
+ }
+
+ /** */
+ @After
+ public void tearDown() {
+ U.delete(srcTmpDir);
+ }
+
+ /**
+ * @return IgniteCompute with the filter that allows SRV node only.
+ */
+ private IgniteCompute compute(Ignite node) {
+ return node.compute(node.cluster().forNodeId(grid(SRV).localNode().id()));
+ }
+}
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/security/sandbox/DoPrivilegedOnRemoteNodeTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/security/sandbox/DoPrivilegedOnRemoteNodeTest.java
index a5f46ef..6b80d9a 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/security/sandbox/DoPrivilegedOnRemoteNodeTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/security/sandbox/DoPrivilegedOnRemoteNodeTest.java
@@ -17,17 +17,11 @@
package org.apache.ignite.internal.processors.security.sandbox;
-import java.io.File;
import java.io.IOException;
import java.lang.reflect.Proxy;
-import java.net.URL;
-import java.net.URLClassLoader;
-import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.security.AccessControlException;
-import javax.tools.JavaCompiler;
-import javax.tools.ToolProvider;
import org.apache.ignite.Ignite;
import org.apache.ignite.IgniteCompute;
import org.apache.ignite.configuration.IgniteConfiguration;
@@ -110,13 +104,15 @@ public class DoPrivilegedOnRemoteNodeTest extends AbstractSandboxTest {
/** */
@Test
public void testDoPrivilegedIgniteCallable() throws Exception {
- checkCallable(clientCompute(), callable("TestDoPrivilegedIgniteCallable", CALLABLE_DO_PRIVELEGED_SRC));
+ checkCallable(clientCompute(),
+ callable(srcTmpDir, "TestDoPrivilegedIgniteCallable", CALLABLE_DO_PRIVELEGED_SRC));
}
/** */
@Test
public void testSecurityUtilsCallable() throws Exception {
- checkCallable(clientCompute(), callable("TestSecurityUtilsCallable", CALLABLE_SECURITY_UTILS_SRC));
+ checkCallable(clientCompute(),
+ callable(srcTmpDir, "TestSecurityUtilsCallable", CALLABLE_SECURITY_UTILS_SRC));
}
/** */
@@ -146,32 +142,6 @@ public class DoPrivilegedOnRemoteNodeTest extends AbstractSandboxTest {
}
/** */
- IgniteCallable<String> callable(String clsName, String src) {
- try {
- Files.createDirectories(srcTmpDir);
-
- File srcFile = new File(srcTmpDir.toFile(), clsName + ".java");
-
- Path srcFilePath = Files.write(srcFile.toPath(), src.getBytes(StandardCharsets.UTF_8));
-
- JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
-
- compiler.run(null, null, null, srcFilePath.toString());
-
- assertTrue("Failed to remove source file.", srcFile.delete());
-
- URLClassLoader clsLdr = new URLClassLoader(new URL[] {srcTmpDir.toUri().toURL()});
-
- Class<?> cls = clsLdr.loadClass(clsName);
-
- return (IgniteCallable<String>)cls.newInstance();
- }
- catch (Exception e) {
- throw new RuntimeException(e);
- }
- }
-
- /** */
abstract static class TestRunnable implements IgniteRunnable{
/** */
@IgniteInstanceResource
diff --git a/modules/core/src/test/java/org/apache/ignite/testsuites/SecurityTestSuite.java b/modules/core/src/test/java/org/apache/ignite/testsuites/SecurityTestSuite.java
index eb8c88b..270c533 100644
--- a/modules/core/src/test/java/org/apache/ignite/testsuites/SecurityTestSuite.java
+++ b/modules/core/src/test/java/org/apache/ignite/testsuites/SecurityTestSuite.java
@@ -35,6 +35,7 @@ import org.apache.ignite.internal.processors.security.compute.closure.Distribute
import org.apache.ignite.internal.processors.security.compute.closure.ExecutorServiceRemoteSecurityContextCheckTest;
import org.apache.ignite.internal.processors.security.datastreamer.DataStreamerPermissionCheckTest;
import org.apache.ignite.internal.processors.security.datastreamer.closure.DataStreamerRemoteSecurityContextCheckTest;
+import org.apache.ignite.internal.processors.security.sandbox.AccessToClassesInsideInternalPackageTest;
import org.apache.ignite.internal.processors.security.sandbox.CacheSandboxTest;
import org.apache.ignite.internal.processors.security.sandbox.ComputeSandboxTest;
import org.apache.ignite.internal.processors.security.sandbox.DataStreamerSandboxTest;
@@ -75,7 +76,8 @@ import org.junit.runners.Suite;
ComputeSandboxTest.class,
DoPrivilegedOnRemoteNodeTest.class,
IgniteOperationsInsideSandboxTest.class,
- SecuritySubjectPermissionsTest.class
+ SecuritySubjectPermissionsTest.class,
+ AccessToClassesInsideInternalPackageTest.class,
})
public class SecurityTestSuite {
}