You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@karaf.apache.org by ff...@apache.org on 2014/05/06 10:47:36 UTC

git commit: [KARAF-2934]Role-based security for Shell/Console commands - backport to 2.x branch-add OsgiSshCommandSecurityTest

Repository: karaf
Updated Branches:
  refs/heads/karaf-2.x b67977120 -> 0b62b8636


[KARAF-2934]Role-based security for Shell/Console commands - backport to 2.x branch-add OsgiSshCommandSecurityTest


Project: http://git-wip-us.apache.org/repos/asf/karaf/repo
Commit: http://git-wip-us.apache.org/repos/asf/karaf/commit/0b62b863
Tree: http://git-wip-us.apache.org/repos/asf/karaf/tree/0b62b863
Diff: http://git-wip-us.apache.org/repos/asf/karaf/diff/0b62b863

Branch: refs/heads/karaf-2.x
Commit: 0b62b863698081465d5ddf405c60765e186258a3
Parents: b679771
Author: Freeman Fang <fr...@gmail.com>
Authored: Tue May 6 16:47:19 2014 +0800
Committer: Freeman Fang <fr...@gmail.com>
Committed: Tue May 6 16:47:19 2014 +0800

----------------------------------------------------------------------
 .../karaf/itests/EnterpriseFeaturesTest.java    |   2 +-
 .../apache/karaf/itests/KarafTestSupport.java   |  54 +++++-
 .../itests/OsgiSshCommandSecurityTest.java      |  78 +++++++++
 .../apache/karaf/itests/SshCommandTestBase.java | 167 +++++++++++++++++++
 .../karaf/itests/StandardFeaturesTest.java      |   2 +-
 5 files changed, 295 insertions(+), 8 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/karaf/blob/0b62b863/itests/src/test/java/org/apache/karaf/itests/EnterpriseFeaturesTest.java
----------------------------------------------------------------------
diff --git a/itests/src/test/java/org/apache/karaf/itests/EnterpriseFeaturesTest.java b/itests/src/test/java/org/apache/karaf/itests/EnterpriseFeaturesTest.java
index ab6d699..70756e3 100644
--- a/itests/src/test/java/org/apache/karaf/itests/EnterpriseFeaturesTest.java
+++ b/itests/src/test/java/org/apache/karaf/itests/EnterpriseFeaturesTest.java
@@ -23,7 +23,7 @@ import org.ops4j.pax.exam.spi.reactors.PerMethod;
 @ExamReactorStrategy(PerMethod.class)
 public class EnterpriseFeaturesTest extends KarafTestSupport {
 
-    private void installAndAssertFeature(String feature) throws Exception {
+    protected void installAndAssertFeature(String feature) throws Exception {
         featuresService.installFeature(feature);
         assertFeatureInstalled(feature);
     }

http://git-wip-us.apache.org/repos/asf/karaf/blob/0b62b863/itests/src/test/java/org/apache/karaf/itests/KarafTestSupport.java
----------------------------------------------------------------------
diff --git a/itests/src/test/java/org/apache/karaf/itests/KarafTestSupport.java b/itests/src/test/java/org/apache/karaf/itests/KarafTestSupport.java
index 87d3cd5..cbba8b7 100644
--- a/itests/src/test/java/org/apache/karaf/itests/KarafTestSupport.java
+++ b/itests/src/test/java/org/apache/karaf/itests/KarafTestSupport.java
@@ -13,11 +13,6 @@
  */
 package org.apache.karaf.itests;
 
-import static org.ops4j.pax.exam.CoreOptions.maven;
-import static org.ops4j.pax.exam.karaf.options.KarafDistributionOption.karafDistributionConfiguration;
-import static org.ops4j.pax.exam.karaf.options.KarafDistributionOption.keepRuntimeFolder;
-import static org.ops4j.pax.exam.karaf.options.KarafDistributionOption.logLevel;
-
 import java.io.ByteArrayOutputStream;
 import java.io.File;
 import java.io.PrintStream;
@@ -28,7 +23,9 @@ import java.util.Collection;
 import java.util.Collections;
 import java.util.Dictionary;
 import java.util.Enumeration;
+import java.util.HashSet;
 import java.util.Hashtable;
+import java.util.Set;
 import java.util.concurrent.Callable;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
@@ -45,7 +42,6 @@ import org.apache.felix.service.command.CommandProcessor;
 import org.apache.felix.service.command.CommandSession;
 import org.apache.karaf.features.Feature;
 import org.apache.karaf.features.FeaturesService;
-import org.junit.Assert;
 import org.ops4j.pax.exam.Configuration;
 import org.ops4j.pax.exam.MavenUtils;
 import org.ops4j.pax.exam.Option;
@@ -60,6 +56,13 @@ import org.osgi.framework.InvalidSyntaxException;
 import org.osgi.framework.ServiceReference;
 import org.osgi.util.tracker.ServiceTracker;
 
+import org.junit.Assert;
+
+import static org.ops4j.pax.exam.CoreOptions.maven;
+import static org.ops4j.pax.exam.karaf.options.KarafDistributionOption.karafDistributionConfiguration;
+import static org.ops4j.pax.exam.karaf.options.KarafDistributionOption.keepRuntimeFolder;
+import static org.ops4j.pax.exam.karaf.options.KarafDistributionOption.logLevel;
+
 public class KarafTestSupport {
 
     static final Long COMMAND_TIMEOUT = 10000L;
@@ -304,5 +307,44 @@ public class KarafTestSupport {
         }
         Assert.fail("Feature " + featureName + " should be installed but is not");
     }
+    
+    protected void installAndAssertFeature(String feature) throws Exception {
+        featuresService.installFeature(feature);
+        assertFeatureInstalled(feature);
+    }
+
+    protected void installAssertAndUninstallFeature(String... feature) throws Exception {
+        Set<Feature> featuresBefore = new HashSet<Feature>(Arrays.asList(featuresService.listInstalledFeatures()));
+        try {
+                        for (String curFeature : feature) {
+                                featuresService.installFeature(curFeature);
+                            assertFeatureInstalled(curFeature);
+                        }
+                } finally {
+                        uninstallNewFeatures(featuresBefore);
+                }
+    }
+
+
+    /**
+     * The feature service does not uninstall feature dependencies when uninstalling a single feature.
+     * So we need to make sure we uninstall all features that were newly installed.
+     *
+     * @param featuresBefore
+     * @throws Exception
+     */
+    protected void uninstallNewFeatures(Set<Feature> featuresBefore) throws Exception {
+        Feature[] features = featuresService.listInstalledFeatures();
+        for (Feature curFeature : features) {
+            if (!featuresBefore.contains(curFeature)) {
+                try {
+                    System.out.println("Uninstalling " + curFeature.getName());
+                    featuresService.uninstallFeature(curFeature.getName(), curFeature.getVersion());
+                } catch (Exception e) {
+                    e.printStackTrace();
+                }
+            }
+        }
+    }
 
 }

http://git-wip-us.apache.org/repos/asf/karaf/blob/0b62b863/itests/src/test/java/org/apache/karaf/itests/OsgiSshCommandSecurityTest.java
----------------------------------------------------------------------
diff --git a/itests/src/test/java/org/apache/karaf/itests/OsgiSshCommandSecurityTest.java b/itests/src/test/java/org/apache/karaf/itests/OsgiSshCommandSecurityTest.java
new file mode 100644
index 0000000..0aabc82
--- /dev/null
+++ b/itests/src/test/java/org/apache/karaf/itests/OsgiSshCommandSecurityTest.java
@@ -0,0 +1,78 @@
+/*
+ * Licensed 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.karaf.itests;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.ops4j.pax.exam.junit.PaxExam;
+import org.ops4j.pax.exam.spi.reactors.ExamReactorStrategy;
+import org.ops4j.pax.exam.spi.reactors.PerClass;
+
+/**
+ * This test exercises the Shell Command ACL for the osgi scope commands as defined in
+ * apache-karaf/src/main/distribution/text/etc/org.apache.karaf.command.acl.osgi.cfg
+ */
+@RunWith(PaxExam.class)
+@ExamReactorStrategy(PerClass.class)
+public class OsgiSshCommandSecurityTest extends SshCommandTestBase {
+    private static int counter = 0;
+
+    @Test
+    public void testBundleCommandSecurityViaSsh() throws Exception {
+        String manageruser = "man" + System.nanoTime() + "_" + counter++;
+        String vieweruser = "view" + System.nanoTime() + "_" + counter++;
+
+        addUsers(manageruser, vieweruser);
+
+        assertCommand(vieweruser, "osgi:refresh 999", Result.NOT_FOUND);
+        assertCommand(manageruser, "osgi:refresh --force 999", Result.NO_CREDENTIALS);
+        assertCommand(manageruser, "osgi:refresh 999", Result.OK);
+        assertCommand("karaf", "osgi:refresh --force 999", Result.OK);
+        assertCommand("karaf", "osgi:refresh 999", Result.OK);
+
+        assertCommand(vieweruser, "osgi:restart 999", Result.NOT_FOUND);
+        assertCommand(manageruser, "osgi:restart --force 999", Result.NO_CREDENTIALS);
+        assertCommand(manageruser, "osgi:restart 999", Result.OK);
+        assertCommand("karaf", "osgi:restart --force 999", Result.OK);
+        assertCommand("karaf", "osgi:restart 999", Result.OK);
+
+        assertCommand(vieweruser, "osgi:start 999", Result.NOT_FOUND);
+        assertCommand(manageruser, "osgi:start --force 999", Result.NO_CREDENTIALS);
+        assertCommand(manageruser, "osgi:start 999", Result.OK);
+        assertCommand("karaf", "osgi:start --force 999", Result.OK);
+        assertCommand("karaf", "osgi:start 999", Result.OK);
+
+        assertCommand(vieweruser, "osgi:stop 999", Result.NOT_FOUND);
+        assertCommand(manageruser, "osgi:stop --force 999", Result.NO_CREDENTIALS);
+        assertCommand(manageruser, "osgi:stop 999", Result.OK);
+        assertCommand("karaf", "osgi:stop --force 999", Result.OK);
+        assertCommand("karaf", "osgi:stop 999", Result.OK);
+
+        assertCommand(vieweruser, "osgi:uninstall 999", Result.NOT_FOUND);
+        assertCommand(manageruser, "osgi:uninstall --force 999", Result.NO_CREDENTIALS);
+        assertCommand(manageruser, "osgi:uninstall 999", Result.OK);
+        assertCommand("karaf", "osgi:uninstall --force 999", Result.OK);
+        assertCommand("karaf", "osgi:uninstall 999", Result.OK);
+
+        assertCommand(vieweruser, "osgi:update 999", Result.NOT_FOUND);
+        assertCommand(manageruser, "osgi:update --force 999", Result.NO_CREDENTIALS);
+        assertCommand(manageruser, "osgi:update 999", Result.OK);
+        assertCommand("karaf", "osgi:update --force 999", Result.OK);
+        assertCommand("karaf", "osgi:update 999", Result.OK);
+
+        assertCommand(vieweruser, "osgi:install xyz", Result.NOT_FOUND);
+        assertCommand(manageruser, "osgi:install xyz", Result.NOT_FOUND);
+        assertCommand("karaf", "osgi:install xyz", Result.OK);
+    }
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0b62b863/itests/src/test/java/org/apache/karaf/itests/SshCommandTestBase.java
----------------------------------------------------------------------
diff --git a/itests/src/test/java/org/apache/karaf/itests/SshCommandTestBase.java b/itests/src/test/java/org/apache/karaf/itests/SshCommandTestBase.java
new file mode 100644
index 0000000..48085cb
--- /dev/null
+++ b/itests/src/test/java/org/apache/karaf/itests/SshCommandTestBase.java
@@ -0,0 +1,167 @@
+/*
+ * Licensed 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.karaf.itests;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.PipedInputStream;
+import java.io.PipedOutputStream;
+import java.util.Arrays;
+import java.util.HashSet;
+
+import junit.framework.Assert;
+
+import org.apache.karaf.features.Feature;
+import org.apache.sshd.ClientChannel;
+import org.apache.sshd.ClientSession;
+import org.apache.sshd.SshClient;
+import org.apache.sshd.client.future.ConnectFuture;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.runner.RunWith;
+import org.ops4j.pax.exam.junit.PaxExam;
+import org.ops4j.pax.exam.spi.reactors.ExamReactorStrategy;
+import org.ops4j.pax.exam.spi.reactors.PerClass;
+
+@RunWith(PaxExam.class)
+@ExamReactorStrategy(PerClass.class)
+public class SshCommandTestBase extends KarafTestSupport {
+    enum Result { OK, NOT_FOUND, NO_CREDENTIALS };
+
+    private SshClient client;
+    private ClientChannel channel;
+    private ClientSession session;
+    private HashSet<Feature> featuresBefore;
+
+    @Before
+    public void installSshFeature() throws Exception {
+        featuresBefore = new HashSet<Feature>(Arrays.asList(featuresService.listInstalledFeatures()));
+        installAndAssertFeature("ssh");
+    }
+
+    @After
+    public void uninstallSshFeature() throws Exception {
+        uninstallNewFeatures(featuresBefore);
+    }
+
+    void addUsers(String manageruser, String vieweruser) throws Exception {
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+        OutputStream pipe = openSshChannel("karaf", "karaf", out);
+        pipe.write(("jaas:manage --realm=karaf"
+                + ";jaas:useradd " + manageruser + " " + manageruser
+                + ";jaas:roleadd " + manageruser + " manager"
+                + ";jaas:roleadd " + manageruser + " viewer"
+                + ";jaas:useradd " + vieweruser + " " + vieweruser
+                + ";jaas:roleadd " + vieweruser + " viewer"
+                + ";jaas:update;jaas:manage --realm=karaf;jaas:users\n").getBytes());
+        pipe.flush();
+        closeSshChannel(pipe);
+        System.out.println(new String(out.toByteArray()));
+    }
+
+    void addViewer(String vieweruser) throws Exception {
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+        OutputStream pipe = openSshChannel("karaf", "karaf", out);
+        pipe.write(("jaas:manage --realm=karaf"
+                + ";jaas:useradd " + vieweruser + " " + vieweruser
+                + ";jaas:roleadd " + vieweruser + " viewer"
+                + ";jaas:update;jaas:manage --realm=karaf;jaas:users\n").getBytes());
+        pipe.flush();
+        closeSshChannel(pipe);
+        System.out.println(new String(out.toByteArray()));
+    }
+
+    String assertCommand(String user, String command, Result result) throws Exception, IOException {
+        if (!command.endsWith("\n"))
+            command += "\n";
+
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+        OutputStream pipe = openSshChannel(user, user, out, out);
+        pipe.write(command.getBytes());
+        pipe.flush();
+
+        closeSshChannel(pipe);
+        String output = new String(out.toByteArray());
+
+        switch(result) {
+        case OK:
+            Assert.assertFalse("Should not contain 'Insufficient credentials' or 'Command not found': " + output,
+                    output.contains("Insufficient credentials") || output.contains("Command not found"));
+            break;
+        case NOT_FOUND:
+            Assert.assertTrue("Should contain 'Command not found': " + output,
+                    output.contains("Command not found"));
+            break;
+        case NO_CREDENTIALS:
+            Assert.assertTrue("Should contain 'Insufficient credentials': " + output,
+                    output.contains("Insufficient credentials"));
+            break;
+        default:
+            Assert.fail("Unexpected enum value: " + result);
+        }
+        return output;
+    }
+
+    private OutputStream openSshChannel(String username, String password, OutputStream ... outputs) throws Exception {
+        client = SshClient.setUpDefaultClient();
+        client.start();
+        ConnectFuture future = client.connect("localhost", 8101).await();
+        session = future.getSession();
+
+        int ret = ClientSession.WAIT_AUTH;
+        while ((ret & ClientSession.WAIT_AUTH) != 0) {
+            session.authPassword(username, password);
+            ret = session.waitFor(ClientSession.WAIT_AUTH | ClientSession.CLOSED | ClientSession.AUTHED, 0);
+        }
+        if ((ret & ClientSession.CLOSED) != 0) {
+            throw new Exception("Could not open SSH channel");
+        }
+        channel = session.createChannel("shell");
+        PipedOutputStream pipe = new PipedOutputStream();
+        channel.setIn(new PipedInputStream(pipe));
+
+        OutputStream out;
+        if (outputs.length >= 1) {
+            out = outputs[0];
+        } else {
+            out = new ByteArrayOutputStream();
+        }
+        channel.setOut(out);
+
+        OutputStream err;
+        if (outputs.length >= 2) {
+            err = outputs[1];
+        } else {
+            err = new ByteArrayOutputStream();
+        }
+        channel.setErr(err);
+        channel.open();
+
+        return pipe;
+    }
+
+    private void closeSshChannel(OutputStream pipe) throws IOException {
+        pipe.write("logout\n".getBytes());
+        pipe.flush();
+
+        channel.waitFor(ClientChannel.CLOSED, 0);
+        session.close(true);
+        client.stop();
+
+        client = null;
+        channel = null;
+        session = null;
+    }
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0b62b863/itests/src/test/java/org/apache/karaf/itests/StandardFeaturesTest.java
----------------------------------------------------------------------
diff --git a/itests/src/test/java/org/apache/karaf/itests/StandardFeaturesTest.java b/itests/src/test/java/org/apache/karaf/itests/StandardFeaturesTest.java
index f626457..68d23e4 100644
--- a/itests/src/test/java/org/apache/karaf/itests/StandardFeaturesTest.java
+++ b/itests/src/test/java/org/apache/karaf/itests/StandardFeaturesTest.java
@@ -31,7 +31,7 @@ public class StandardFeaturesTest extends KarafTestSupport {
         assertFeatureInstalled("kar");
     }
 
-    private void installAndAssertFeature(String feature) throws Exception {
+    protected void installAndAssertFeature(String feature) throws Exception {
         featuresService.installFeature(feature);
         assertFeatureInstalled(feature);
     }