[KARAF-5427] Add RBAC support for reflection invocation and redirections in the console
diff --git a/pom.xml b/pom.xml
index 2e7778b..d0cced3 100644
--- a/pom.xml
+++ b/pom.xml
@@ -192,8 +192,8 @@
<felix.fileinstall.version>3.6.2</felix.fileinstall.version>
<felix.framework.version>5.6.8</felix.framework.version>
<felix.framework.security.version>2.6.0</felix.framework.security.version>
- <felix.gogo.runtime.version>1.0.8</felix.gogo.runtime.version>
- <felix.gogo.jline.version>1.0.8</felix.gogo.jline.version>
+ <felix.gogo.runtime.version>1.0.9-SNAPSHOT</felix.gogo.runtime.version>
+ <felix.gogo.jline.version>1.0.9-SNAPSHOT</felix.gogo.jline.version>
<felix.httplite.version>0.1.6</felix.httplite.version>
<felix.inventory.version>1.0.4</felix.inventory.version>
<felix.plugin.version>3.3.0</felix.plugin.version>
diff --git a/shell/core/src/main/java/org/apache/karaf/shell/impl/console/SessionFactoryImpl.java b/shell/core/src/main/java/org/apache/karaf/shell/impl/console/SessionFactoryImpl.java
index d351753..13e27ac 100644
--- a/shell/core/src/main/java/org/apache/karaf/shell/impl/console/SessionFactoryImpl.java
+++ b/shell/core/src/main/java/org/apache/karaf/shell/impl/console/SessionFactoryImpl.java
@@ -20,6 +20,7 @@
import java.io.InputStream;
import java.io.PrintStream;
+import java.nio.file.Path;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -29,6 +30,7 @@
import org.apache.felix.gogo.jline.Posix;
import org.apache.felix.gogo.jline.Procedural;
import org.apache.felix.gogo.runtime.CommandProcessorImpl;
+import org.apache.felix.gogo.runtime.CommandSessionImpl;
import org.apache.felix.gogo.runtime.Reflective;
import org.apache.felix.service.command.CommandSession;
import org.apache.felix.service.command.Function;
@@ -54,7 +56,17 @@
public SessionFactoryImpl(ThreadIO threadIO) {
super(null);
this.threadIO = threadIO;
- commandProcessor = new CommandProcessorImpl(threadIO);
+ commandProcessor = new CommandProcessorImpl(threadIO) {
+ @Override
+ public Object invoke(CommandSessionImpl session, Object target, String name, List<Object> args) throws Exception {
+ return SessionFactoryImpl.this.invoke(session, target, name, args);
+ }
+
+ @Override
+ public Path redirect(CommandSessionImpl session, Path path, int mode) {
+ return SessionFactoryImpl.this.redirect(session, path, mode);
+ }
+ };
register(new ExitCommand());
new HelpCommand(this);
register(new ShellCommand("addCommand", "Add a command", commandProcessor, "addCommand"));
@@ -77,6 +89,14 @@
}
}
+ protected Object invoke(CommandSessionImpl session, Object target, String name, List<Object> args) throws Exception {
+ return Reflective.invoke(session, target, name, args);
+ }
+
+ protected Path redirect(CommandSessionImpl session, Path path, int mode) {
+ return session.currentDir().resolve(path);
+ }
+
public CommandProcessorImpl getCommandProcessor() {
return commandProcessor;
}
diff --git a/shell/core/src/main/java/org/apache/karaf/shell/impl/console/osgi/secured/SecuredCommand.java b/shell/core/src/main/java/org/apache/karaf/shell/impl/console/osgi/secured/SecuredCommand.java
index e6e8ef7..2df6e09 100644
--- a/shell/core/src/main/java/org/apache/karaf/shell/impl/console/osgi/secured/SecuredCommand.java
+++ b/shell/core/src/main/java/org/apache/karaf/shell/impl/console/osgi/secured/SecuredCommand.java
@@ -64,7 +64,7 @@
@Override
public Object execute(Session session, List<Object> arguments) throws Exception {
- factory.checkSecurity(this, session, arguments);
+ factory.checkSecurity(getScope(), getName(), arguments);
return command.execute(session, arguments);
}
diff --git a/shell/core/src/main/java/org/apache/karaf/shell/impl/console/osgi/secured/SecuredSessionFactoryImpl.java b/shell/core/src/main/java/org/apache/karaf/shell/impl/console/osgi/secured/SecuredSessionFactoryImpl.java
index cf12f18..7fe015c 100644
--- a/shell/core/src/main/java/org/apache/karaf/shell/impl/console/osgi/secured/SecuredSessionFactoryImpl.java
+++ b/shell/core/src/main/java/org/apache/karaf/shell/impl/console/osgi/secured/SecuredSessionFactoryImpl.java
@@ -18,10 +18,12 @@
*/
package org.apache.karaf.shell.impl.console.osgi.secured;
+import java.nio.file.Path;
import java.security.AccessControlContext;
import java.security.AccessController;
import java.security.Principal;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Dictionary;
import java.util.HashMap;
import java.util.List;
@@ -30,12 +32,12 @@
import javax.security.auth.Subject;
import org.apache.felix.gogo.runtime.CommandNotFoundException;
+import org.apache.felix.gogo.runtime.CommandSessionImpl;
import org.apache.felix.service.command.Function;
import org.apache.felix.service.threadio.ThreadIO;
import org.apache.karaf.jaas.boot.principal.RolePrincipal;
import org.apache.karaf.service.guard.tools.ACLConfigurationParser;
import org.apache.karaf.shell.api.console.Command;
-import org.apache.karaf.shell.api.console.Session;
import org.apache.karaf.shell.impl.console.SessionFactoryImpl;
import org.apache.karaf.util.tracker.SingleServiceTracker;
import org.osgi.framework.BundleContext;
@@ -52,8 +54,11 @@
public class SecuredSessionFactoryImpl extends SessionFactoryImpl implements ConfigurationListener {
private static final String PROXY_COMMAND_ACL_PID_PREFIX = "org.apache.karaf.command.acl.";
- private static final String CONFIGURATION_FILTER =
- "(" + Constants.SERVICE_PID + "=" + PROXY_COMMAND_ACL_PID_PREFIX + "*)";
+ private static final String CONFIGURATION_FILTER = "(" + Constants.SERVICE_PID + "=" + PROXY_COMMAND_ACL_PID_PREFIX + "*)";
+
+ private static final String SHELL_SCOPE = "shell";
+ private static final String SHELL_INVOKE = ".invoke";
+ private static final String SHELL_REDIRECT = ".redirect";
private static final Logger LOGGER = LoggerFactory.getLogger(SecuredSessionFactoryImpl.class);
@@ -77,6 +82,18 @@
}
@Override
+ protected Object invoke(CommandSessionImpl session, Object target, String name, List<Object> args) throws Exception {
+ checkSecurity(SHELL_SCOPE, SHELL_INVOKE, Arrays.asList(target, name, args));
+ return super.invoke(session, target, name, args);
+ }
+
+ @Override
+ protected Path redirect(CommandSessionImpl session, Path path, int mode) {
+ checkSecurity(SHELL_SCOPE, SHELL_REDIRECT, Arrays.asList(path, mode));
+ return super.redirect(session, path, mode);
+ }
+
+ @Override
protected Function wrap(Command command) {
return new SecuredCommand(this, command);
}
@@ -84,17 +101,18 @@
@Override
protected boolean isVisible(Object service) {
if (service instanceof Command) {
- return isVisible((Command) service);
+ Command cmd = (Command) service;
+ return isVisible(cmd.getScope(), cmd.getName());
} else {
return super.isVisible(service);
}
}
- protected boolean isVisible(Command command) {
- Dictionary<String, Object> config = getScopeConfig(command.getScope());
+ protected boolean isVisible(String scope, String name) {
+ Dictionary<String, Object> config = getScopeConfig(scope);
if (config != null) {
List<String> roles = new ArrayList<>();
- ACLConfigurationParser.getRolesForInvocation(command.getName(), null, null, config, roles);
+ ACLConfigurationParser.getRolesForInvocation(name, null, null, config, roles);
if (roles.isEmpty()) {
return true;
} else {
@@ -109,14 +127,14 @@
return true;
}
- void checkSecurity(SecuredCommand command, Session session, List<Object> arguments) {
- Dictionary<String, Object> config = getScopeConfig(command.getScope());
+ void checkSecurity(String scope, String name, List<Object> arguments) {
+ Dictionary<String, Object> config = getScopeConfig(scope);
if (config != null) {
- if (!isVisible(command)) {
- throw new CommandNotFoundException(command.getScope() + ":" + command.getName());
+ if (!isVisible(scope, name)) {
+ throw new CommandNotFoundException(scope + ":" + name);
}
List<String> roles = new ArrayList<>();
- ACLConfigurationParser.Specificity s = ACLConfigurationParser.getRolesForInvocation(command.getName(), new Object[] { arguments.toString() }, null, config, roles);
+ ACLConfigurationParser.Specificity s = ACLConfigurationParser.getRolesForInvocation(name, new Object[] { arguments.toString() }, null, config, roles);
if (s == ACLConfigurationParser.Specificity.NO_MATCH) {
return;
}