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 {
 }