This is an automated email from the ASF dual-hosted git repository.
jbonofre pushed a commit to branch karaf-4.4.x
in repository https://gitbox.apache.org/repos/asf/karaf.git
The following commit(s) were added to refs/heads/karaf-4.4.x by this push:
new 8ee4009b49 fix(jdbc,jms): add command ACLs for the jdbc and jms scopes
(karaf-4.4.x) (#2863)
8ee4009b49 is described below
commit 8ee4009b49eb1e59c9565551b3004e8c5880762f
Author: JB Onofré <[email protected]>
AuthorDate: Sat Sep 12 07:55:47 2026 +0200
fix(jdbc,jms): add command ACLs for the jdbc and jms scopes (karaf-4.4.x)
(#2863)
* fix(jdbc,jms): add command ACLs for the jdbc and jms scopes
The jdbc and jms command scopes had no org.apache.karaf.command.acl.*
configuration. The command guard treats an unmatched command as allowed,
so any authenticated shell user (viewer role included) could run every
jdbc:* and jms:* command.
jdbc:ds-create and jms:create store a user-supplied URL into a
pax-jdbc-config / pax-jms-config factory configuration that is turned
into a live DataSource / ConnectionFactory. Several JDBC drivers run
code at connection time based on URL parameters (for instance H2
INIT=RUNSCRIPT), so creating a datasource is equivalent to arbitrary
code execution. jdbc:execute / jdbc:query run arbitrary SQL, and
jms:send / jms:consume / jms:move write to or destructively drain
broker destinations.
Add an ACL for each scope, provided by the jdbc / jms feature via a
<config> element under a shell conditional (same mechanism as the kar
and maven scopes):
jdbc: ds-create, ds-delete, execute, query = admin;
ds-list, ds-info, ds-factories, tables = viewer
jms: create, delete, send, consume, move = admin;
connectionfactories, info, queues, topics, count, browse = viewer
This is consistent with shell:exec and config:install, which are
already restricted to admin. Add SSH command security itests for both
scopes.
* fix(jdbc,jms): grant admin/viewer roles in itests using jdbc/jms shell
commands
KarafTestSupport.executeCommand() runs without a Subject when no Principal
is passed, so XATest, JmsTest and JmsExampleTest were being denied by the
new jdbc/jms command ACLs with a misleading CommandNotFoundException.
---
.../enterprise/src/main/feature/feature.xml | 94 ++++++++++++++++++++++
.../test/java/org/apache/karaf/itests/JmsTest.java | 28 ++++---
.../test/java/org/apache/karaf/itests/XATest.java | 24 +++---
.../karaf/itests/examples/JmsExampleTest.java | 6 +-
.../itests/ssh/JdbcSshCommandSecurityTest.java | 79 ++++++++++++++++++
.../itests/ssh/JmsSshCommandSecurityTest.java | 80 ++++++++++++++++++
manual/src/main/asciidoc/user-guide/security.adoc | 4 +
7 files changed, 292 insertions(+), 23 deletions(-)
diff --git a/assemblies/features/enterprise/src/main/feature/feature.xml
b/assemblies/features/enterprise/src/main/feature/feature.xml
index 3a90627234..e58a51c180 100644
--- a/assemblies/features/enterprise/src/main/feature/feature.xml
+++ b/assemblies/features/enterprise/src/main/feature/feature.xml
@@ -300,6 +300,52 @@ com.atomikos.icatch.log_base_dir=${karaf.data}/atomikos
<feature prerequisite="true">pax-jdbc-config</feature>
<bundle
dependency="true">mvn:org.osgi/org.osgi.service.jdbc/${org.osgi.service.jdbc.version}</bundle>
<bundle>mvn:org.apache.karaf.jdbc/org.apache.karaf.jdbc.core/${project.version}</bundle>
+ <conditional>
+ <condition>shell</condition>
+ <config name="org.apache.karaf.command.acl.jdbc">
+################################################################################
+#
+# 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.
+#
+################################################################################
+
+#
+# This configuration file defines the ACLs for commands in the jdbc subshell
+#
+# For an explanation of the syntax of this file, see the file:
+# org.apache.karaf.command.acl.system.cfg
+#
+# 'ds-create' stores a user-supplied JDBC URL into a pax-jdbc-config factory
+# configuration that is turned into a live DataSource. Several JDBC drivers run
+# code at connection time based on URL parameters (for instance H2
INIT=RUNSCRIPT),
+# so creating a datasource is equivalent to arbitrary code execution and is
+# restricted to 'admin', consistent with shell:exec and config:install.
+# 'execute' and 'query' run arbitrary SQL and are restricted to 'admin' as
well.
+# 'ds-delete' removes a datasource and is an admin operation.
+#
+ds-create = admin
+ds-delete = admin
+execute = admin
+query = admin
+ds-list = viewer
+ds-info = viewer
+ds-factories = viewer
+tables = viewer
+ </config>
+ </conditional>
</feature>
<feature name="jms" description="JMS service and commands"
version="${project.version}">
@@ -313,6 +359,54 @@ com.atomikos.icatch.log_base_dir=${karaf.data}/atomikos
<bundle
dependency="true">mvn:org.apache.geronimo.specs/geronimo-jms_1.1_spec/${geronimo.jms-spec.version}</bundle>
<bundle
dependency="true">mvn:org.apache.commons/commons-pool2/${commons-pool2.version}</bundle>
<bundle>mvn:org.apache.karaf.jms/org.apache.karaf.jms.core/${project.version}</bundle>
+ <conditional>
+ <condition>shell</condition>
+ <config name="org.apache.karaf.command.acl.jms">
+################################################################################
+#
+# 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.
+#
+################################################################################
+
+#
+# This configuration file defines the ACLs for commands in the jms subshell
+#
+# For an explanation of the syntax of this file, see the file:
+# org.apache.karaf.command.acl.system.cfg
+#
+# 'create' stores a user-supplied broker URL into a pax-jms-config factory
+# configuration that is turned into a live ConnectionFactory, so it is
restricted
+# to 'admin', consistent with jdbc:ds-create and config:install. 'delete'
removes a
+# connection factory. 'send', 'consume' and 'move' write to / destructively
read
+# from broker destinations. All of these are restricted to 'admin'. The
read-only
+# commands require the 'viewer' role.
+#
+create = admin
+delete = admin
+send = admin
+consume = admin
+move = admin
+connectionfactories = viewer
+info = viewer
+queues = viewer
+topics = viewer
+count = viewer
+browse = viewer
+ </config>
+ </conditional>
</feature>
<feature name="application-without-isolation" description="Provide EBA
archive support" version="${aries.application.version}">
diff --git a/itests/test/src/test/java/org/apache/karaf/itests/JmsTest.java
b/itests/test/src/test/java/org/apache/karaf/itests/JmsTest.java
index ec8865487a..14d6ee0ea0 100644
--- a/itests/test/src/test/java/org/apache/karaf/itests/JmsTest.java
+++ b/itests/test/src/test/java/org/apache/karaf/itests/JmsTest.java
@@ -14,10 +14,12 @@
package org.apache.karaf.itests;
import java.lang.management.ManagementFactory;
+import java.security.Principal;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
+import org.apache.karaf.jaas.boot.principal.RolePrincipal;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -52,6 +54,8 @@ public class JmsTest extends BaseTest {
@Test(timeout = 60000)
public void testCommands() throws Exception {
+ Principal[] roles = { new RolePrincipal("admin"), new
RolePrincipal("viewer") };
+
System.out.println("== Installing ActiveMQ");
featureService.installFeature("aries-blueprint");
featureService.installFeature("activemq-broker-noweb");
@@ -61,42 +65,42 @@ public class JmsTest extends BaseTest {
featureService.installFeature("pax-jms-activemq");
System.out.println("== Creating JMS ConnectionFactory");
- executeCommand("jms:create test");
+ executeCommand("jms:create test", roles);
Thread.sleep(2000);
- String output = executeCommand("jms:connectionfactories");
+ String output = executeCommand("jms:connectionfactories", roles);
System.out.println(output);
assertContains("jms/test", output);
- output = executeCommand("jms:info jms/test");
+ output = executeCommand("jms:info jms/test", roles);
System.out.println(output);
assertContains("ActiveMQ", output);
- executeCommand("jms:send jms/test queue message");
- output = executeCommand("jms:count jms/test queue");
+ executeCommand("jms:send jms/test queue message", roles);
+ output = executeCommand("jms:count jms/test queue", roles);
System.out.println(output);
assertContains("1", output);
- output = executeCommand("jms:consume jms/test queue");
+ output = executeCommand("jms:consume jms/test queue", roles);
System.out.println(output);
assertContains("1 message", output);
- executeCommand("jms:send test queue message");
- output = executeCommand("jms:move test queue other");
+ executeCommand("jms:send test queue message", roles);
+ output = executeCommand("jms:move test queue other", roles);
System.out.println(output);
assertContains("1 message", output);
- output = executeCommand("jms:queues test");
+ output = executeCommand("jms:queues test", roles);
System.out.println(output);
assertContains("queue", output);
assertContains("other", output);
- output = executeCommand("jms:browse test other");
+ output = executeCommand("jms:browse test other", roles);
System.out.println(output);
assertContains("queue", output);
assertContains("queue://other", output);
- System.out.println(executeCommand("jms:consume test other"));
- System.out.println(executeCommand("jms:delete test"));
+ System.out.println(executeCommand("jms:consume test other", roles));
+ System.out.println(executeCommand("jms:delete test", roles));
}
@Test
diff --git a/itests/test/src/test/java/org/apache/karaf/itests/XATest.java
b/itests/test/src/test/java/org/apache/karaf/itests/XATest.java
index bf9d37c5e4..4ebdb22476 100644
--- a/itests/test/src/test/java/org/apache/karaf/itests/XATest.java
+++ b/itests/test/src/test/java/org/apache/karaf/itests/XATest.java
@@ -18,6 +18,7 @@ package org.apache.karaf.itests;
import org.apache.karaf.features.FeaturesService;
import org.apache.karaf.itests.util.RunIfRule;
+import org.apache.karaf.jaas.boot.principal.RolePrincipal;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -30,6 +31,7 @@ import org.ops4j.pax.exam.spi.reactors.ExamReactorStrategy;
import org.ops4j.pax.exam.spi.reactors.PerClass;
import org.osgi.framework.Bundle;
+import java.security.Principal;
import java.util.Arrays;
import java.util.EnumSet;
import java.util.LinkedList;
@@ -70,6 +72,8 @@ public class XATest extends BaseTest {
@Test
public void test() throws Exception {
+ Principal[] roles = { new RolePrincipal("admin"), new
RolePrincipal("viewer") };
+
System.out.println("== Starting Artemis broker == ");
String logDisplay = executeCommand("log:display");
while (!logDisplay.contains("AMQ221007: Server is now live")) {
@@ -77,7 +81,7 @@ public class XATest extends BaseTest {
logDisplay = executeCommand("log:display");
}
System.out.println("AMQ221007: Server is now live");
- System.out.println(executeCommand("jms:info artemis"));
+ System.out.println(executeCommand("jms:info artemis", roles));
System.out.println("== Installing Derby database == ");
featureService.installFeature("jdbc", NO_AUTO_REFRESH);
@@ -85,20 +89,20 @@ public class XATest extends BaseTest {
featureService.installFeature("pax-jdbc-pool-transx", NO_AUTO_REFRESH);
System.out.println(" ");
- String dsList = executeCommand("jdbc:ds-list");
+ String dsList = executeCommand("jdbc:ds-list", roles);
while (!dsList.contains("OK")) {
Thread.sleep(500);
- dsList = executeCommand("jdbc:ds-list");
+ dsList = executeCommand("jdbc:ds-list", roles);
}
System.out.println(dsList);
-
+
System.out.println("== Creating table in Derby ==");
- System.out.println(executeCommand("jdbc:execute derby CREATE TABLE
messages (id INTEGER NOT NULL GENERATED ALWAYS AS IDENTITY, message
VARCHAR(1024) NOT NULL, CONSTRAINT primary_key PRIMARY KEY (id))"));
+ System.out.println(executeCommand("jdbc:execute derby CREATE TABLE
messages (id INTEGER NOT NULL GENERATED ALWAYS AS IDENTITY, message
VARCHAR(1024) NOT NULL, CONSTRAINT primary_key PRIMARY KEY (id))", roles));
- String tableOutput = executeCommand("jdbc:query derby select * from
messages");
+ String tableOutput = executeCommand("jdbc:query derby select * from
messages", roles);
while (!tableOutput.contains("MESSAGE")) {
Thread.sleep(500);
- tableOutput = executeCommand("jdbc:query derby select * from
messages");;
+ tableOutput = executeCommand("jdbc:query derby select * from
messages", roles);;
}
System.out.println("== Table created ==");
@@ -122,13 +126,13 @@ public class XATest extends BaseTest {
System.out.println(routeList);
System.out.println("== Sending a message in Artemis broker that should
be consumed by Camel route and inserted into the Derby database");
- System.out.println(executeCommand("jms:send artemis MyQueue
'the-message'"));
+ System.out.println(executeCommand("jms:send artemis MyQueue
'the-message'", roles));
- String output = executeCommand("jdbc:query derby select * from
messages");
+ String output = executeCommand("jdbc:query derby select * from
messages", roles);
while (!output.contains("the-message")) {
Thread.sleep(500);
- output = executeCommand("jdbc:query derby select * from messages");
+ output = executeCommand("jdbc:query derby select * from messages",
roles);
}
System.out.println(output);
diff --git
a/itests/test/src/test/java/org/apache/karaf/itests/examples/JmsExampleTest.java
b/itests/test/src/test/java/org/apache/karaf/itests/examples/JmsExampleTest.java
index 350ed89acd..d1c5fa2c36 100644
---
a/itests/test/src/test/java/org/apache/karaf/itests/examples/JmsExampleTest.java
+++
b/itests/test/src/test/java/org/apache/karaf/itests/examples/JmsExampleTest.java
@@ -15,6 +15,7 @@ package org.apache.karaf.itests.examples;
import org.apache.karaf.features.FeaturesService;
import org.apache.karaf.itests.BaseTest;
+import org.apache.karaf.jaas.boot.principal.RolePrincipal;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.ops4j.pax.exam.Configuration;
@@ -24,6 +25,7 @@ import org.ops4j.pax.exam.junit.PaxExam;
import org.ops4j.pax.exam.spi.reactors.ExamReactorStrategy;
import org.ops4j.pax.exam.spi.reactors.PerClass;
+import java.security.Principal;
import java.util.Arrays;
import java.util.EnumSet;
import java.util.LinkedList;
@@ -57,8 +59,10 @@ public class JmsExampleTest extends BaseTest {
@Test
public void test() throws Exception {
+ Principal[] roles = { new RolePrincipal("admin"), new
RolePrincipal("viewer") };
+
Thread.sleep(10000);//wait until artemis up
- String output = executeCommand("jms:info artemis");
+ String output = executeCommand("jms:info artemis", roles);
System.out.println(output);
assertContains("ActiveMQ", output);
diff --git
a/itests/test/src/test/java/org/apache/karaf/itests/ssh/JdbcSshCommandSecurityTest.java
b/itests/test/src/test/java/org/apache/karaf/itests/ssh/JdbcSshCommandSecurityTest.java
new file mode 100644
index 0000000000..b9cd23a58f
--- /dev/null
+++
b/itests/test/src/test/java/org/apache/karaf/itests/ssh/JdbcSshCommandSecurityTest.java
@@ -0,0 +1,79 @@
+/*
+ * 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.ssh;
+
+import java.util.EnumSet;
+
+import org.apache.karaf.features.FeaturesService;
+import org.junit.Assume;
+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 jdbc scope commands as
defined in the
+ * {@code org.apache.karaf.command.acl.jdbc} configuration provided by the
{@code jdbc} feature.
+ *
+ * <p>{@code jdbc:ds-create} stores an arbitrary JDBC URL that pax-jdbc-config
turns into a live
+ * datasource - several JDBC drivers run code at connection time based on URL
parameters (for
+ * instance H2 {@code INIT=RUNSCRIPT}) - so it, together with {@code
jdbc:ds-delete},
+ * {@code jdbc:execute} and {@code jdbc:query} (arbitrary SQL), is restricted
to the
+ * {@code admin} role. The read-only commands require the {@code viewer}
role.</p>
+ */
+@RunWith(PaxExam.class)
+@ExamReactorStrategy(PerClass.class)
+public class JdbcSshCommandSecurityTest extends SshCommandTestBase {
+
+ private static int counter = 0;
+
+ @Test
+ public void testJdbcCommandSecurityViaSsh() throws Exception {
+ // Skip on Windows where PTY output can be garbled,
+ // when upgrading to Junit5, this can be replaced with
@DisabledOnOs(OS.WINDOWS)
+ Assume.assumeFalse(System.getProperty("os.name",
"").toLowerCase().contains("win"));
+
+ featureService.installFeature("jdbc",
EnumSet.of(FeaturesService.Option.NoAutoRefreshBundles));
+
+ String manageruser = "man" + System.nanoTime() + "_" + counter++;
+ String vieweruser = "view" + System.nanoTime() + "_" + counter++;
+
+ addUsers(manageruser, vieweruser);
+
+ // read-only commands are available to a viewer
+ assertCommand(vieweruser, "jdbc:ds-list", Result.OK);
+ assertCommand(vieweruser, "jdbc:ds-factories", Result.OK);
+
+ // ds-create / ds-delete / execute / query are admin-only: a viewer
and a manager
+ // must not even see the commands
+ assertCommand(vieweruser, "jdbc:ds-create", Result.NOT_FOUND);
+ assertCommand(vieweruser, "jdbc:ds-delete", Result.NOT_FOUND);
+ assertCommand(vieweruser, "jdbc:execute", Result.NOT_FOUND);
+ assertCommand(vieweruser, "jdbc:query", Result.NOT_FOUND);
+
+ assertCommand(manageruser, "jdbc:ds-create", Result.NOT_FOUND);
+ assertCommand(manageruser, "jdbc:execute", Result.NOT_FOUND);
+ assertCommand(manageruser, "jdbc:query", Result.NOT_FOUND);
+
+ // the admin user can see and run the jdbc commands (a bare invocation
reports a
+ // missing-argument / missing-driver error, not "Command not found")
+ assertCommand("karaf", "jdbc:ds-list", Result.OK);
+ assertCommand("karaf", "jdbc:ds-factories", Result.OK);
+ assertCommand("karaf", "jdbc:ds-create", Result.OK);
+ assertCommand("karaf", "jdbc:execute", Result.OK);
+ assertCommand("karaf", "jdbc:query", Result.OK);
+ assertCommand("karaf", "jdbc:ds-delete", Result.OK);
+ }
+}
diff --git
a/itests/test/src/test/java/org/apache/karaf/itests/ssh/JmsSshCommandSecurityTest.java
b/itests/test/src/test/java/org/apache/karaf/itests/ssh/JmsSshCommandSecurityTest.java
new file mode 100644
index 0000000000..cb6fabf96a
--- /dev/null
+++
b/itests/test/src/test/java/org/apache/karaf/itests/ssh/JmsSshCommandSecurityTest.java
@@ -0,0 +1,80 @@
+/*
+ * 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.ssh;
+
+import java.util.EnumSet;
+
+import org.apache.karaf.features.FeaturesService;
+import org.junit.Assume;
+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 jms scope commands as
defined in the
+ * {@code org.apache.karaf.command.acl.jms} configuration provided by the
{@code jms} feature.
+ *
+ * <p>{@code jms:create} stores an arbitrary broker URL that pax-jms-config
turns into a live
+ * connection factory, and {@code jms:send}, {@code jms:consume} and {@code
jms:move} write to
+ * or destructively read from broker destinations, so these commands together
with
+ * {@code jms:delete} are restricted to the {@code admin} role. The read-only
commands require
+ * the {@code viewer} role.</p>
+ */
+@RunWith(PaxExam.class)
+@ExamReactorStrategy(PerClass.class)
+public class JmsSshCommandSecurityTest extends SshCommandTestBase {
+
+ private static int counter = 0;
+
+ @Test
+ public void testJmsCommandSecurityViaSsh() throws Exception {
+ // Skip on Windows where PTY output can be garbled,
+ // when upgrading to Junit5, this can be replaced with
@DisabledOnOs(OS.WINDOWS)
+ Assume.assumeFalse(System.getProperty("os.name",
"").toLowerCase().contains("win"));
+
+ featureService.installFeature("jms",
EnumSet.of(FeaturesService.Option.NoAutoRefreshBundles));
+
+ String manageruser = "man" + System.nanoTime() + "_" + counter++;
+ String vieweruser = "view" + System.nanoTime() + "_" + counter++;
+
+ addUsers(manageruser, vieweruser);
+
+ // read-only commands are available to a viewer
+ assertCommand(vieweruser, "jms:connectionfactories", Result.OK);
+
+ // create / delete / send / consume / move are admin-only: a viewer
and a manager
+ // must not even see the commands
+ assertCommand(vieweruser, "jms:create", Result.NOT_FOUND);
+ assertCommand(vieweruser, "jms:delete", Result.NOT_FOUND);
+ assertCommand(vieweruser, "jms:send", Result.NOT_FOUND);
+ assertCommand(vieweruser, "jms:consume", Result.NOT_FOUND);
+ assertCommand(vieweruser, "jms:move", Result.NOT_FOUND);
+
+ assertCommand(manageruser, "jms:create", Result.NOT_FOUND);
+ assertCommand(manageruser, "jms:send", Result.NOT_FOUND);
+ assertCommand(manageruser, "jms:consume", Result.NOT_FOUND);
+ assertCommand(manageruser, "jms:move", Result.NOT_FOUND);
+
+ // the admin user can see and run the jms commands (a bare invocation
reports a
+ // missing-argument error, not "Command not found")
+ assertCommand("karaf", "jms:connectionfactories", Result.OK);
+ assertCommand("karaf", "jms:create", Result.OK);
+ assertCommand("karaf", "jms:delete", Result.OK);
+ assertCommand("karaf", "jms:send", Result.OK);
+ assertCommand("karaf", "jms:consume", Result.OK);
+ assertCommand("karaf", "jms:move", Result.OK);
+ }
+}
diff --git a/manual/src/main/asciidoc/user-guide/security.adoc
b/manual/src/main/asciidoc/user-guide/security.adoc
index a542b88994..7a736b02a1 100644
--- a/manual/src/main/asciidoc/user-guide/security.adoc
+++ b/manual/src/main/asciidoc/user-guide/security.adoc
@@ -506,6 +506,10 @@ By default, Apache Karaf defines the following commands
ACLs:
* `etc/org.apache.karaf.command.acl.system.cfg` configuration file defines the
ACL for `system:*` commands.
Only the users with `admin` role can execute `system:property` and
`system:shutdown` commands. Users with `manager` role can call
`system:start-level` above 100, otherwise `admin` role is required. Also users
with `viewer` role can obtain the current start-level.
The other `system:*` commands can be executed by any user.
+* `etc/org.apache.karaf.command.acl.jdbc.cfg` configuration file (provided by
the `jdbc` feature) defines the ACL for `jdbc:*` commands.
+ As `jdbc:ds-create` stores an arbitrary JDBC URL that pax-jdbc-config turns
into a live datasource (several drivers run code at connection time, for
instance H2 `INIT=RUNSCRIPT`), and `jdbc:execute` and `jdbc:query` run
arbitrary SQL, these commands together with `jdbc:ds-delete` are restricted to
the users with the `admin` role. The read-only `jdbc:*` commands require the
`viewer` role.
+* `etc/org.apache.karaf.command.acl.jms.cfg` configuration file (provided by
the `jms` feature) defines the ACL for `jms:*` commands.
+ As `jms:create` stores an arbitrary broker URL that pax-jms-config turns into
a live connection factory, and `jms:send`, `jms:consume` and `jms:move` write
to or destructively read from broker destinations, these commands together with
`jms:delete` are restricted to the users with the `admin` role. The read-only
`jms:*` commands require the `viewer` role.
You can change these default ACLs, and add your own ACLs for additional
command scopes (for instance `etc/org.apache.karaf.command.acl.cluster.cfg` for
Apache Karaf Cellar, `etc/org.apache.karaf.command.acl.camel.cfg` from Apache
Camel, ...).