This is an automated email from the ASF dual-hosted git repository.

mpetrov 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 74810b063e5 IGNITE-21021 Removed ADMIN_OPS permissions check for cache 
operations executed via Control Utility. (#11077)
74810b063e5 is described below

commit 74810b063e59769bfb02c79f6dc368542286d6b8
Author: Mikhail Petrov <[email protected]>
AuthorDate: Wed Dec 6 13:29:29 2023 +0300

    IGNITE-21021 Removed ADMIN_OPS permissions check for cache operations 
executed via Control Utility. (#11077)
---
 .../SecurityCommandHandlerPermissionsTest.java     | 177 +++++++++++++++++++++
 .../testsuites/IgniteControlUtilityTestSuite2.java |   5 +-
 .../internal/management/cache/CacheCreateTask.java |   9 ++
 .../internal/management/cache/CacheScanTask.java   |   9 ++
 .../internal/management/cache/CacheStopTask.java   |  10 ++
 .../internal/processors/cache/ClearCachesTask.java |  10 ++
 6 files changed, 219 insertions(+), 1 deletion(-)

diff --git 
a/modules/control-utility/src/test/java/org/apache/ignite/internal/commandline/SecurityCommandHandlerPermissionsTest.java
 
b/modules/control-utility/src/test/java/org/apache/ignite/internal/commandline/SecurityCommandHandlerPermissionsTest.java
new file mode 100644
index 00000000000..48eba72bd38
--- /dev/null
+++ 
b/modules/control-utility/src/test/java/org/apache/ignite/internal/commandline/SecurityCommandHandlerPermissionsTest.java
@@ -0,0 +1,177 @@
+/*
+ * 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.commandline;
+
+import java.security.Permissions;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import org.apache.ignite.Ignite;
+import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.internal.IgniteEx;
+import org.apache.ignite.internal.processors.security.impl.TestSecurityData;
+import 
org.apache.ignite.internal.processors.security.impl.TestSecurityPluginProvider;
+import org.apache.ignite.plugin.security.SecurityPermission;
+import org.apache.ignite.plugin.security.SecurityPermissionSet;
+import org.apache.ignite.plugin.security.SecurityPermissionSetBuilder;
+import org.apache.ignite.util.GridCommandHandlerAbstractTest;
+import org.junit.Test;
+import org.junit.runners.Parameterized;
+
+import static java.util.Arrays.asList;
+import static 
org.apache.ignite.internal.commandline.ArgumentParser.CMD_PASSWORD;
+import static org.apache.ignite.internal.commandline.ArgumentParser.CMD_USER;
+import static 
org.apache.ignite.internal.commandline.CommandHandler.EXIT_CODE_OK;
+import static 
org.apache.ignite.internal.commandline.CommandHandler.EXIT_CODE_UNEXPECTED_ERROR;
+import static org.apache.ignite.internal.util.IgniteUtils.resolveIgnitePath;
+import static 
org.apache.ignite.plugin.security.SecurityPermission.CACHE_CREATE;
+import static 
org.apache.ignite.plugin.security.SecurityPermission.CACHE_DESTROY;
+import static org.apache.ignite.plugin.security.SecurityPermission.CACHE_READ;
+import static 
org.apache.ignite.plugin.security.SecurityPermission.CACHE_REMOVE;
+import static 
org.apache.ignite.plugin.security.SecurityPermissionSetBuilder.ALL_PERMISSIONS;
+import static 
org.apache.ignite.plugin.security.SecurityPermissionSetBuilder.NO_PERMISSIONS;
+import static 
org.apache.ignite.plugin.security.SecurityPermissionSetBuilder.systemPermissions;
+
+/** */
+public class SecurityCommandHandlerPermissionsTest extends 
GridCommandHandlerAbstractTest {
+    /** */
+    private static final String TEST_NO_PERMISSIONS_LOGIN = 
"no-permissions-login";
+
+    /** */
+    private static final String TEST_LOGIN = "cli-admin-login";
+
+    /** */
+    private static final String DEFAULT_PWD = "pwd";
+
+    /** */
+    @Parameterized.Parameters(name = "cmdHnd={0}")
+    public static List<String> commandHandlers() {
+        return Collections.singletonList(CLI_CMD_HND);
+    }
+
+    /** {@inheritDoc} */
+    @Override protected void beforeTest() throws Exception {
+        super.beforeTest();
+
+        persistenceEnable(false);
+
+        injectTestSystemOut();
+    }
+
+    /** {@inheritDoc} */
+    @Override protected void afterTest() throws Exception {
+        super.afterTest();
+
+        stopAllGrids();
+    }
+
+    /** */
+    @Test
+    public void testCacheScan() throws Exception {
+        checkCommandPermissions(asList("--cache", "scan", DEFAULT_CACHE_NAME), 
cachePermission(CACHE_READ));
+    }
+
+    /** */
+    @Test
+    public void testCacheDestroy() throws Exception {
+        checkCommandPermissions(asList("--cache", "destroy", "--caches", 
DEFAULT_CACHE_NAME), systemPermissions(CACHE_DESTROY));
+    }
+
+    /** */
+    @Test
+    public void testCacheClear() throws Exception {
+        checkCommandPermissions(asList("--cache", "clear", "--caches", 
DEFAULT_CACHE_NAME), cachePermission(CACHE_REMOVE));
+    }
+
+    /** */
+    @Test
+    public void testCacheCreate() throws Exception {
+        String ccfgPath = resolveIgnitePath(
+            
"modules/control-utility/src/test/resources/config/cache/cache-create-correct.xml"
+        ).getAbsolutePath();
+
+        checkCommandPermissions(
+            asList("--cache", "create", "--springxmlconfig", ccfgPath),
+            systemPermissions(CACHE_CREATE)
+        );
+    }
+
+    /** */
+    protected IgniteEx startGrid(int idx, TestSecurityData... userData) throws 
Exception {
+        String login = getTestIgniteInstanceName(idx);
+
+        IgniteConfiguration cfg = 
getConfiguration(getTestIgniteInstanceName(idx));
+
+        cfg.setPluginProviders(new TestSecurityPluginProvider(login, 
DEFAULT_PWD, ALL_PERMISSIONS, false, userData));
+
+        return startGrid(cfg);
+    }
+
+    /** */
+    private void checkCommandPermissions(Collection<String> cmdArgs, 
SecurityPermissionSet reqPerms) throws Exception {
+        Ignite ignite = startGrid(
+            0,
+            userData(TEST_NO_PERMISSIONS_LOGIN, NO_PERMISSIONS),
+            userData(TEST_LOGIN, reqPerms)
+        );
+
+        ignite.createCache(DEFAULT_CACHE_NAME);
+
+        assertEquals(EXIT_CODE_UNEXPECTED_ERROR, 
execute(enrichWithConnectionArguments(cmdArgs, TEST_NO_PERMISSIONS_LOGIN)));
+
+        // We are losing command failure cause for --cache clear commnad. See 
IGNITE-21023 for more details.
+        if (!cmdArgs.containsAll(Arrays.asList("--cache", "clear")))
+            assertTrue(testOut.toString().contains("Authorization failed"));
+
+        assertEquals(EXIT_CODE_OK, 
execute(enrichWithConnectionArguments(cmdArgs, TEST_LOGIN)));
+    }
+
+    /** */
+    List<String> enrichWithConnectionArguments(Collection<String> cmdArgs, 
String login) {
+        List<String> args = new ArrayList<>();
+
+        args.add(CMD_USER);
+        args.add(login);
+        args.add(CMD_PASSWORD);
+        args.add(DEFAULT_PWD);
+
+        args.addAll(cmdArgs);
+
+        return args;
+    }
+
+    /** */
+    private SecurityPermissionSet cachePermission(SecurityPermission... perms) 
{
+        return SecurityPermissionSetBuilder.create()
+            .defaultAllowAll(false)
+            .appendCachePermissions(DEFAULT_CACHE_NAME, perms)
+            .build();
+    }
+
+    /** */
+    private TestSecurityData userData(String login, SecurityPermissionSet 
perms) {
+        return new TestSecurityData(
+            login,
+            DEFAULT_PWD,
+            perms,
+            new Permissions()
+        );
+    }
+}
diff --git 
a/modules/control-utility/src/test/java/org/apache/ignite/testsuites/IgniteControlUtilityTestSuite2.java
 
b/modules/control-utility/src/test/java/org/apache/ignite/testsuites/IgniteControlUtilityTestSuite2.java
index 409a75db2a8..3c9d373bb4a 100644
--- 
a/modules/control-utility/src/test/java/org/apache/ignite/testsuites/IgniteControlUtilityTestSuite2.java
+++ 
b/modules/control-utility/src/test/java/org/apache/ignite/testsuites/IgniteControlUtilityTestSuite2.java
@@ -17,6 +17,7 @@
 
 package org.apache.ignite.testsuites;
 
+import 
org.apache.ignite.internal.commandline.SecurityCommandHandlerPermissionsTest;
 import 
org.apache.ignite.internal.commandline.indexreader.IgniteIndexReaderTest;
 import org.apache.ignite.util.CacheMetricsCommandTest;
 import org.apache.ignite.util.CdcCommandTest;
@@ -69,7 +70,9 @@ import org.junit.runners.Suite;
     IgniteIndexReaderTest.class,
 
     CdcCommandTest.class,
-    CdcResendCommandTest.class
+    CdcResendCommandTest.class,
+
+    SecurityCommandHandlerPermissionsTest.class
 })
 public class IgniteControlUtilityTestSuite2 {
 }
diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/management/cache/CacheCreateTask.java
 
b/modules/core/src/main/java/org/apache/ignite/internal/management/cache/CacheCreateTask.java
index b8435492328..df9831db903 100644
--- 
a/modules/core/src/main/java/org/apache/ignite/internal/management/cache/CacheCreateTask.java
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/management/cache/CacheCreateTask.java
@@ -33,9 +33,11 @@ import 
org.apache.ignite.internal.util.spring.IgniteSpringHelper;
 import org.apache.ignite.internal.util.typedef.F;
 import org.apache.ignite.internal.visor.VisorJob;
 import org.apache.ignite.internal.visor.VisorOneNodeTask;
+import org.apache.ignite.plugin.security.SecurityPermissionSet;
 import org.apache.ignite.resources.IgniteInstanceResource;
 
 import static org.apache.ignite.internal.IgniteComponentType.SPRING;
+import static 
org.apache.ignite.plugin.security.SecurityPermissionSetBuilder.NO_PERMISSIONS;
 
 /**
  * Task to create caches from Spring XML configuration.
@@ -93,5 +95,12 @@ public class CacheCreateTask extends 
VisorOneNodeTask<CacheCreateCommandArg, Set
 
             return 
caches.stream().map(Cache::getName).collect(Collectors.toCollection(TreeSet::new));
         }
+
+        /** {@inheritDoc} */
+        @Override public SecurityPermissionSet requiredPermissions() {
+            // This task does nothing but delegates the call to the Ignite 
public API.
+            // Therefore, it is safe to execute task without any additional 
permissions check.
+            return NO_PERMISSIONS;
+        }
     }
 }
diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/management/cache/CacheScanTask.java
 
b/modules/core/src/main/java/org/apache/ignite/internal/management/cache/CacheScanTask.java
index 92a37f163f1..b419177d46d 100644
--- 
a/modules/core/src/main/java/org/apache/ignite/internal/management/cache/CacheScanTask.java
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/management/cache/CacheScanTask.java
@@ -37,9 +37,11 @@ import org.apache.ignite.internal.util.typedef.internal.S;
 import org.apache.ignite.internal.util.typedef.internal.SB;
 import org.apache.ignite.internal.visor.VisorJob;
 import org.apache.ignite.internal.visor.VisorOneNodeTask;
+import org.apache.ignite.plugin.security.SecurityPermissionSet;
 
 import static java.lang.Math.min;
 import static org.apache.ignite.cache.query.Query.DFLT_PAGE_SIZE;
+import static 
org.apache.ignite.plugin.security.SecurityPermissionSetBuilder.NO_PERMISSIONS;
 
 /**
  * Task that scan cache entries.
@@ -105,6 +107,13 @@ public class CacheScanTask extends 
VisorOneNodeTask<CacheScanCommandArg, CacheSc
             return new CacheScanTaskResult(titles, entries);
         }
 
+        /** {@inheritDoc} */
+        @Override public SecurityPermissionSet requiredPermissions() {
+            // This task does nothing but delegates the call to the Ignite 
public API.
+            // Therefore, it is safe to execute task without any additional 
permissions check.
+            return NO_PERMISSIONS;
+        }
+
         /**
          * @param o Source object.
          * @return String representation of object class.
diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/management/cache/CacheStopTask.java
 
b/modules/core/src/main/java/org/apache/ignite/internal/management/cache/CacheStopTask.java
index b606f05b4bd..cb7a6973996 100644
--- 
a/modules/core/src/main/java/org/apache/ignite/internal/management/cache/CacheStopTask.java
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/management/cache/CacheStopTask.java
@@ -26,6 +26,9 @@ import org.apache.ignite.internal.util.typedef.F;
 import org.apache.ignite.internal.util.typedef.internal.S;
 import org.apache.ignite.internal.visor.VisorJob;
 import org.apache.ignite.internal.visor.VisorOneNodeTask;
+import org.apache.ignite.plugin.security.SecurityPermissionSet;
+
+import static 
org.apache.ignite.plugin.security.SecurityPermissionSetBuilder.NO_PERMISSIONS;
 
 /**
  * Task that stop specified caches on specified node.
@@ -72,6 +75,13 @@ public class CacheStopTask extends 
VisorOneNodeTask<CacheDestroyCommandArg, Void
             return null;
         }
 
+        /** {@inheritDoc} */
+        @Override public SecurityPermissionSet requiredPermissions() {
+            // This task does nothing but delegates the call to the Ignite 
public API.
+            // Therefore, it is safe to execute task without any additional 
permissions check.
+            return NO_PERMISSIONS;
+        }
+
         /** {@inheritDoc} */
         @Override public String toString() {
             return S.toString(CacheStopJob.class, this);
diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/ClearCachesTask.java
 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/ClearCachesTask.java
index 48313ad4cfa..6e755de653f 100644
--- 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/ClearCachesTask.java
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/ClearCachesTask.java
@@ -26,9 +26,12 @@ import 
org.apache.ignite.internal.management.cache.CacheClearCommandArg;
 import org.apache.ignite.internal.processors.task.GridInternal;
 import org.apache.ignite.internal.visor.VisorJob;
 import org.apache.ignite.internal.visor.VisorOneNodeTask;
+import org.apache.ignite.plugin.security.SecurityPermissionSet;
 import org.apache.ignite.resources.IgniteInstanceResource;
 import org.jetbrains.annotations.Nullable;
 
+import static 
org.apache.ignite.plugin.security.SecurityPermissionSetBuilder.NO_PERMISSIONS;
+
 /** Clears specified caches. */
 @GridInternal
 public class ClearCachesTask extends VisorOneNodeTask<CacheClearCommandArg, 
ClearCachesTaskResult> {
@@ -73,6 +76,13 @@ public class ClearCachesTask extends 
VisorOneNodeTask<CacheClearCommandArg, Clea
             return new ClearCachesTaskResult(clearedCaches, nonExistentCaches);
         }
 
+        /** {@inheritDoc} */
+        @Override public SecurityPermissionSet requiredPermissions() {
+            // This task does nothing but delegates the call to the Ignite 
public API.
+            // Therefore, it is safe to execute task without any additional 
permissions check.
+            return NO_PERMISSIONS;
+        }
+
         /** */
         @IgniteInstanceResource
         public void setIgnite(Ignite ignite) {

Reply via email to