Repository: karaf Updated Branches: refs/heads/karaf-2.x fda3393cf -> bf0311611
Fix packaging problems with gogo as Gogo is deployed in its own bundle, but also partially embedded in shell/core. * Embed gogo in shell/core * Export the secured CommandProcessor directly Project: http://git-wip-us.apache.org/repos/asf/karaf/repo Commit: http://git-wip-us.apache.org/repos/asf/karaf/commit/94ffa5e5 Tree: http://git-wip-us.apache.org/repos/asf/karaf/tree/94ffa5e5 Diff: http://git-wip-us.apache.org/repos/asf/karaf/diff/94ffa5e5 Branch: refs/heads/karaf-2.x Commit: 94ffa5e5bedff9bb779ddf48888aea351459e006 Parents: fda3393 Author: Guillaume Nodet <gno...@gmail.com> Authored: Thu Sep 11 23:04:19 2014 +0200 Committer: Guillaume Nodet <gno...@gmail.com> Committed: Thu Sep 11 23:19:09 2014 +0200 ---------------------------------------------------------------------- .../standard/src/main/resources/features.xml | 1 - .../apache/karaf/itests/KarafTestSupport.java | 4 +- shell/console/pom.xml | 10 +- .../karaf/shell/console/jline/Console.java | 107 +--------- .../shell/console/jline/ConsoleFactory.java | 8 +- .../security/impl/SecCommandProcessorImpl.java | 42 ++++ .../impl/SecuredCommandProcessorImpl.java | 99 +++++----- .../OSGI-INF/blueprint/karaf-console.xml | 25 +-- .../org/apache/felix/gogo/commands/Context.java | 2 +- .../karaf/shell/console/jline/ConsoleTest.java | 195 ------------------- .../impl/SecuredCommandProcessorImplTest.java | 2 +- .../karaf/shell/ssh/ShellFactoryImpl.java | 112 ++++++----- 12 files changed, 185 insertions(+), 422 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/karaf/blob/94ffa5e5/assemblies/features/standard/src/main/resources/features.xml ---------------------------------------------------------------------- diff --git a/assemblies/features/standard/src/main/resources/features.xml b/assemblies/features/standard/src/main/resources/features.xml index 587bd1d..99008d4 100644 --- a/assemblies/features/standard/src/main/resources/features.xml +++ b/assemblies/features/standard/src/main/resources/features.xml @@ -99,7 +99,6 @@ <feature name="shell" description="Karaf Shell" version="${project.version}"> <feature>aries-blueprint</feature> <feature>jaas</feature> - <bundle start-level="30">mvn:org.apache.felix/org.apache.felix.gogo.runtime/${felix.gogo.version}</bundle> <bundle start-level="30">mvn:org.apache.karaf.shell/org.apache.karaf.shell.console/${project.version}</bundle> <bundle start-level="30">mvn:org.apache.karaf.shell/org.apache.karaf.shell.commands/${project.version}</bundle> <bundle start-level="30">mvn:org.apache.karaf.shell/org.apache.karaf.shell.osgi/${project.version}</bundle> http://git-wip-us.apache.org/repos/asf/karaf/blob/94ffa5e5/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 cbba8b7..c9321a5 100644 --- a/itests/src/test/java/org/apache/karaf/itests/KarafTestSupport.java +++ b/itests/src/test/java/org/apache/karaf/itests/KarafTestSupport.java @@ -120,8 +120,6 @@ public class KarafTestSupport { String response; final ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); final PrintStream printStream = new PrintStream(byteArrayOutputStream); - final CommandProcessor commandProcessor = getOsgiService(CommandProcessor.class); - final CommandSession commandSession = commandProcessor.createSession(System.in, printStream, System.err); final Callable<String> commandCallable = new Callable<String>() { @Override public String call() throws Exception { @@ -129,6 +127,8 @@ public class KarafTestSupport { if (!silent) { System.err.println(command); } + final CommandProcessor commandProcessor = getOsgiService(CommandProcessor.class); + final CommandSession commandSession = commandProcessor.createSession(System.in, printStream, System.err); commandSession.execute(command); } catch (Exception e) { throw new RuntimeException(e.getMessage(), e); http://git-wip-us.apache.org/repos/asf/karaf/blob/94ffa5e5/shell/console/pom.xml ---------------------------------------------------------------------- diff --git a/shell/console/pom.xml b/shell/console/pom.xml index a2ebe1f..4a8d98f 100644 --- a/shell/console/pom.xml +++ b/shell/console/pom.xml @@ -119,15 +119,16 @@ <configuration> <instructions> <Import-Package> - !org.apache.felix.gogo.runtime.*, org.osgi.service.event;resolution:=optional, org.apache.karaf.branding;resolution:=optional, org.apache.sshd.agent*;resolution:=optional, * </Import-Package> <Export-Package> - org.apache.felix.gogo.runtime.*;version=${felix.gogo.version};-split-package:=merge-first, - org.apache.felix.gogo.commands.*;version=${felix.gogo.version};-split-package:=merge-first, + org.apache.felix.service.command;version=${felix.gogo.version};-split-package:=merge-first;-noimport:=true, + org.apache.felix.service.threadio;version=${felix.gogo.version};-split-package:=merge-first;-noimport:=true, + org.apache.felix.gogo.api;version=${felix.gogo.version};-split-package:=merge-first;-noimport:=true, + org.apache.felix.gogo.commands.*;version=${felix.gogo.version};-split-package:=merge-first;-noimport:=true, org.apache.karaf.shell.console*;version=${project.version}, org.fusesource.jansi;version=${jansi.version};-split-package:=merge-first, jline*;version=${jline.version}, @@ -135,6 +136,7 @@ org.fusesource.hawtjni*;version=1.0;-split-package:=merge-first </Export-Package> <Private-Package> + org.apache.felix.gogo.runtime.*, org.apache.karaf.shell.security.impl, org.fusesource.jansi.internal;-split-package:=merge-first, !org.apache.karaf.util.properties, @@ -155,13 +157,11 @@ <Main-Class> org.apache.karaf.shell.console.Main </Main-Class> - <!-- <Export-Service> org.apache.felix.service.threadio.ThreadIO, org.apache.felix.service.command.CommandProcessor, org.apache.felix.service.command.Converter </Export-Service> - --> </instructions> <unpackBundle>true</unpackBundle> </configuration> http://git-wip-us.apache.org/repos/asf/karaf/blob/94ffa5e5/shell/console/src/main/java/org/apache/karaf/shell/console/jline/Console.java ---------------------------------------------------------------------- diff --git a/shell/console/src/main/java/org/apache/karaf/shell/console/jline/Console.java b/shell/console/src/main/java/org/apache/karaf/shell/console/jline/Console.java index ac48e0c..4ab38c6 100644 --- a/shell/console/src/main/java/org/apache/karaf/shell/console/jline/Console.java +++ b/shell/console/src/main/java/org/apache/karaf/shell/console/jline/Console.java @@ -102,7 +102,8 @@ public class Console implements Runnable this.queue = new ArrayBlockingQueue<Integer>(1024); this.terminal = term == null ? new UnsupportedTerminal() : term; this.consoleInput = new ConsoleInputStream(); - this.session = new DelegateSession(); + + this.session = processor.createSession(consoleInput, out, err); this.session.put("SCOPE", "shell:osgi:*"); this.closeCallback = closeCallback; this.bundleContext = bc; @@ -178,7 +179,6 @@ public class Console implements Runnable { try { threadIO.setStreams(consoleInput, out, err); - SecuredCommandProcessorImpl secCP = createSecuredCommandProcessor(); thread = Thread.currentThread(); CommandSessionHolder.setSession(session); running = true; @@ -212,11 +212,6 @@ public class Console implements Runnable logException(t); } } - try { - secCP.close(); - } catch (Throwable t) { - // Ignore - } close(true); } finally { try { @@ -227,22 +222,6 @@ public class Console implements Runnable } } - SecuredCommandProcessorImpl createSecuredCommandProcessor() { - if (!(session instanceof DelegateSession)) { - throw new IllegalStateException("Should be an Delegate Session here, about to set the delegate"); - } - DelegateSession is = (DelegateSession)session; - - // make it active - SecuredCommandProcessorImpl secCP = new SecuredCommandProcessorImpl(bundleContext); - CommandSession s = secCP.createSession(consoleInput, out, err); - - // before the session is activated attributes may have been set on it. Pass these on to the real - // session now - is.setDelegate(s); - return secCP; - } - private void logException(Throwable t) { try { boolean isCommandNotFound = "org.apache.felix.gogo.runtime.CommandNotFoundException".equals(t.getClass().getName()); @@ -443,88 +422,6 @@ public class Console implements Runnable thread.interrupt(); } - static class DelegateSession implements CommandSession { - final Map<String, Object> attrs = new HashMap<String, Object>(); - volatile CommandSession delegate; - - @Override - public Object execute(CharSequence commandline) throws Exception { - if (delegate != null) - return delegate.execute(commandline); - - throw new UnsupportedOperationException(); - } - - void setDelegate(CommandSession s) { - synchronized (this) { - for (Map.Entry<String, Object> entry : attrs.entrySet()) { - s.put(entry.getKey(), entry.getValue()); - } - } - delegate = s; - } - - @Override - public void close() { - if (delegate != null) - delegate.close(); - } - - @Override - public InputStream getKeyboard() { - if (delegate != null) - return delegate.getKeyboard(); - - throw new UnsupportedOperationException(); - } - - @Override - public PrintStream getConsole() { - if (delegate != null) - return delegate.getConsole(); - - throw new UnsupportedOperationException(); - } - - @Override - public Object get(String name) { - if (delegate != null) - return delegate.get(name); - - return attrs.get(name); - } - - // you can put attributes on this session before it's delegate is set... - @Override - public void put(String name, Object value) { - if (delegate != null) { - delegate.put(name, value); - return; - } - - // there is no delegate yet, so we'll keep the attributes locally - synchronized (this) { - attrs.put(name, value); - } - } - - @Override - public CharSequence format(Object target, int level) { - if (delegate != null) - return delegate.format(target, level); - - throw new UnsupportedOperationException(); - } - - @Override - public Object convert(Class<?> type, Object instance) { - if (delegate != null) - return delegate.convert(type, instance); - - throw new UnsupportedOperationException(); - } - } - private class ConsoleInputStream extends InputStream { private int read(boolean wait) throws IOException http://git-wip-us.apache.org/repos/asf/karaf/blob/94ffa5e5/shell/console/src/main/java/org/apache/karaf/shell/console/jline/ConsoleFactory.java ---------------------------------------------------------------------- diff --git a/shell/console/src/main/java/org/apache/karaf/shell/console/jline/ConsoleFactory.java b/shell/console/src/main/java/org/apache/karaf/shell/console/jline/ConsoleFactory.java index 68cf181..fcae59f 100644 --- a/shell/console/src/main/java/org/apache/karaf/shell/console/jline/ConsoleFactory.java +++ b/shell/console/src/main/java/org/apache/karaf/shell/console/jline/ConsoleFactory.java @@ -73,6 +73,10 @@ public class ConsoleFactory { this.bundleContext = bundleContext; } + public void setCommandProcessor(CommandProcessor commandProcessor) { + this.commandProcessor = commandProcessor; + } + public void setThreadIO(ThreadIO threadIO) { this.threadIO = threadIO; } @@ -95,7 +99,7 @@ public class ConsoleFactory { this.start = start; } - protected void start() throws Exception { + public void start() throws Exception { if (start) { Subject subject = new Subject(); String userName = System.getProperty("karaf.local.user"); @@ -211,7 +215,7 @@ public class ConsoleFactory { return parts[0]; } - protected void stop() throws Exception { + public void stop() throws Exception { if (registration != null) { registration.unregister(); } http://git-wip-us.apache.org/repos/asf/karaf/blob/94ffa5e5/shell/console/src/main/java/org/apache/karaf/shell/security/impl/SecCommandProcessorImpl.java ---------------------------------------------------------------------- diff --git a/shell/console/src/main/java/org/apache/karaf/shell/security/impl/SecCommandProcessorImpl.java b/shell/console/src/main/java/org/apache/karaf/shell/security/impl/SecCommandProcessorImpl.java new file mode 100644 index 0000000..29b02a2 --- /dev/null +++ b/shell/console/src/main/java/org/apache/karaf/shell/security/impl/SecCommandProcessorImpl.java @@ -0,0 +1,42 @@ +/* + * 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.karaf.shell.security.impl; + +import java.io.InputStream; +import java.io.PrintStream; + +import org.apache.felix.service.command.CommandProcessor; +import org.apache.felix.service.command.CommandSession; +import org.apache.felix.service.threadio.ThreadIO; +import org.osgi.framework.BundleContext; + +public class SecCommandProcessorImpl implements CommandProcessor { + + private final BundleContext bundleContext; + private final ThreadIO threadIO; + + public SecCommandProcessorImpl(BundleContext bundleContext, ThreadIO threadIO) { + this.bundleContext = bundleContext; + this.threadIO = threadIO; + } + + public CommandSession createSession(InputStream in, PrintStream out, PrintStream err) { + SecuredCommandProcessorImpl scp = new SecuredCommandProcessorImpl(bundleContext, threadIO); + return scp.createSession(in, out, err); + } + +} http://git-wip-us.apache.org/repos/asf/karaf/blob/94ffa5e5/shell/console/src/main/java/org/apache/karaf/shell/security/impl/SecuredCommandProcessorImpl.java ---------------------------------------------------------------------- diff --git a/shell/console/src/main/java/org/apache/karaf/shell/security/impl/SecuredCommandProcessorImpl.java b/shell/console/src/main/java/org/apache/karaf/shell/security/impl/SecuredCommandProcessorImpl.java index 84224c4..3a83958 100644 --- a/shell/console/src/main/java/org/apache/karaf/shell/security/impl/SecuredCommandProcessorImpl.java +++ b/shell/console/src/main/java/org/apache/karaf/shell/security/impl/SecuredCommandProcessorImpl.java @@ -22,7 +22,6 @@ import org.apache.felix.gogo.runtime.CommandProxy; import org.apache.felix.gogo.runtime.activator.Activator; import org.apache.felix.service.command.CommandProcessor; import org.apache.felix.service.command.Converter; -import org.apache.felix.service.command.Function; import org.apache.felix.service.threadio.ThreadIO; import org.apache.karaf.jaas.boot.principal.RolePrincipal; import org.osgi.framework.BundleContext; @@ -35,48 +34,47 @@ import javax.security.auth.Subject; import java.security.AccessControlContext; import java.security.AccessController; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; public class SecuredCommandProcessorImpl extends CommandProcessorImpl { private final BundleContext bundleContext; - private final ServiceReference<ThreadIO> threadIOServiceReference; private final ServiceTracker<Object, Object> commandTracker; private final ServiceTracker<Converter, Converter> converterTracker; private final ServiceTracker<CommandSessionListener, CommandSessionListener> listenerTracker; - public SecuredCommandProcessorImpl(BundleContext bc) { - this(bc, bc.getServiceReference(ThreadIO.class)); - } - - private SecuredCommandProcessorImpl(BundleContext bc, ServiceReference<ThreadIO> sr) { - super(bc.getService(sr)); + public SecuredCommandProcessorImpl(BundleContext bc, ThreadIO io) { + super(io); bundleContext = bc; - threadIOServiceReference = sr; + + String roleClause = ""; AccessControlContext acc = AccessController.getContext(); Subject sub = Subject.getSubject(acc); - if (sub == null) - throw new SecurityException("No current Subject in the Access Control Context"); - - Set<RolePrincipal> rolePrincipals = sub.getPrincipals(RolePrincipal.class); - if (rolePrincipals.size() == 0) - throw new SecurityException("Current user has no associated roles."); - - // TODO cater for custom roles - StringBuilder sb = new StringBuilder(); - sb.append("(|"); - for (RolePrincipal rp : rolePrincipals) { - sb.append('('); - sb.append("org.apache.karaf.service.guard.roles"); - sb.append('='); - sb.append(rp.getName()); + if (sub != null) { + Set<RolePrincipal> rolePrincipals = sub.getPrincipals(RolePrincipal.class); + if (rolePrincipals.size() == 0) + throw new SecurityException("Current user has no associated roles."); + + // TODO cater for custom roles + StringBuilder sb = new StringBuilder(); + sb.append("(|"); + for (RolePrincipal rp : rolePrincipals) { + sb.append('('); + sb.append("org.apache.karaf.service.guard.roles"); + sb.append('='); + sb.append(rp.getName()); + sb.append(')'); + } + sb.append("(!(org.apache.karaf.service.guard.roles=*))"); // Or no roles specified at all sb.append(')'); + roleClause = sb.toString(); } - sb.append("(!(org.apache.karaf.service.guard.roles=*))"); // Or no roles specified at all - sb.append(')'); - String roleClause = sb.toString(); addConstant(Activator.CONTEXT, bc); addCommand("osgi", this, "addCommand"); @@ -101,7 +99,6 @@ public class SecuredCommandProcessorImpl extends CommandProcessorImpl { commandTracker.close(); converterTracker.close(); listenerTracker.close(); - bundleContext.ungetService(threadIOServiceReference); } private ServiceTracker<Object, Object> trackCommands(final BundleContext context, String roleClause) throws InvalidSyntaxException { @@ -109,45 +106,57 @@ public class SecuredCommandProcessorImpl extends CommandProcessorImpl { CommandProcessor.COMMAND_SCOPE, CommandProcessor.COMMAND_FUNCTION, roleClause)); return new ServiceTracker<Object, Object>(context, filter, null) { + private final ConcurrentMap<ServiceReference, Map<String, CommandProxy>> proxies + = new ConcurrentHashMap<ServiceReference, Map<String, CommandProxy>>(); + @Override - public Object addingService(ServiceReference<Object> reference) { + public Object addingService(ServiceReference reference) + { Object scope = reference.getProperty(CommandProcessor.COMMAND_SCOPE); Object function = reference.getProperty(CommandProcessor.COMMAND_FUNCTION); List<Object> commands = new ArrayList<Object>(); - if (scope != null && function != null) { - if (function.getClass().isArray()) { - for (Object f : ((Object[]) function)) { - Function target = new CommandProxy(context, reference, - f.toString()); + if (scope != null && function != null) + { + Map<String, CommandProxy> proxyMap = new HashMap<String, CommandProxy>(); + if (function.getClass().isArray()) + { + for (Object f : ((Object[]) function)) + { + CommandProxy target = new CommandProxy(context, reference, f.toString()); + proxyMap.put(f.toString(), target); addCommand(scope.toString(), target, f.toString()); commands.add(target); } - } else { - Function target = new CommandProxy(context, reference, - function.toString()); + } + else + { + CommandProxy target = new CommandProxy(context, reference, function.toString()); + proxyMap.put(function.toString(), target); addCommand(scope.toString(), target, function.toString()); commands.add(target); } + proxies.put(reference, proxyMap); return commands; } return null; } @Override - public void removedService(ServiceReference<Object> reference, Object service) { + public void removedService(ServiceReference reference, Object service) + { Object scope = reference.getProperty(CommandProcessor.COMMAND_SCOPE); Object function = reference.getProperty(CommandProcessor.COMMAND_FUNCTION); - if (scope != null && function != null) { - if (!function.getClass().isArray()) { - removeCommand(scope.toString(), function.toString()); - } else { - for (Object func : (Object[]) function) { - removeCommand(scope.toString(), func.toString()); - } + if (scope != null && function != null) + { + Map<String, CommandProxy> proxyMap = proxies.remove(reference); + for (Map.Entry<String, CommandProxy> entry : proxyMap.entrySet()) + { + removeCommand(scope.toString(), entry.getKey()); } } + super.removedService(reference, service); } }; http://git-wip-us.apache.org/repos/asf/karaf/blob/94ffa5e5/shell/console/src/main/resources/OSGI-INF/blueprint/karaf-console.xml ---------------------------------------------------------------------- diff --git a/shell/console/src/main/resources/OSGI-INF/blueprint/karaf-console.xml b/shell/console/src/main/resources/OSGI-INF/blueprint/karaf-console.xml index 65c1991..cf544bc 100644 --- a/shell/console/src/main/resources/OSGI-INF/blueprint/karaf-console.xml +++ b/shell/console/src/main/resources/OSGI-INF/blueprint/karaf-console.xml @@ -26,18 +26,23 @@ </ext:default-properties> </ext:property-placeholder> - <reference id="commandProcessor" interface="org.apache.felix.service.command.CommandProcessor"> - <reference-listener ref="consoleFactory" - bind-method="registerCommandProcessor" - unbind-method="unregisterCommandProcessor"/> - </reference> - <reference id="threadIO" interface="org.apache.felix.service.threadio.ThreadIO" /> - - <bean id="consoleFactory" class="org.apache.karaf.shell.console.jline.ConsoleFactory"> + <bean id="threadIO" class="org.apache.felix.gogo.runtime.threadio.ThreadIOImpl" + init-method="start" destroy-method="stop"/> + <service ref="threadIO" auto-export="interfaces"/> + + <bean id="commandProcessor" class="org.apache.karaf.shell.security.impl.SecCommandProcessorImpl"> + <argument ref="blueprintBundleContext"/> + <argument ref="threadIO"/> + </bean> + <service ref="commandProcessor" auto-export="interfaces"/> + + <bean id="consoleFactory" class="org.apache.karaf.shell.console.jline.ConsoleFactory" + init-method="start" destroy-method="stop"> <property name="start" value="$[karaf.startLocalConsole]"/> <property name="bundleContext" ref="blueprintBundleContext"/> <property name="terminalFactory" ref="terminalFactory"/> <property name="threadIO" ref="threadIO"/> + <property name="commandProcessor" ref="commandProcessor"/> </bean> <bean id="converters" class="org.apache.karaf.shell.console.Converters"> @@ -83,9 +88,7 @@ </service> <service auto-export="interfaces" ranking="-10"> <bean class="org.apache.karaf.shell.console.help.SingleCommandHelpProvider"> - <property name="io"> - <reference interface="org.apache.felix.service.threadio.ThreadIO"/> - </property> + <property name="io" ref="threadIO"/> </bean> </service> <service auto-export="interfaces" ref="subShellHelpProvider" ranking="-10"/> http://git-wip-us.apache.org/repos/asf/karaf/blob/94ffa5e5/shell/console/src/test/java/org/apache/felix/gogo/commands/Context.java ---------------------------------------------------------------------- diff --git a/shell/console/src/test/java/org/apache/felix/gogo/commands/Context.java b/shell/console/src/test/java/org/apache/felix/gogo/commands/Context.java index 80f5309..4ef17e0 100644 --- a/shell/console/src/test/java/org/apache/felix/gogo/commands/Context.java +++ b/shell/console/src/test/java/org/apache/felix/gogo/commands/Context.java @@ -51,7 +51,7 @@ public class Context extends CommandProcessorImpl public void addCommand(String name, Object target) { - put("test:" + name, target); + addCommand("test", target, name); } public void set(String name, Object value) http://git-wip-us.apache.org/repos/asf/karaf/blob/94ffa5e5/shell/console/src/test/java/org/apache/karaf/shell/console/jline/ConsoleTest.java ---------------------------------------------------------------------- diff --git a/shell/console/src/test/java/org/apache/karaf/shell/console/jline/ConsoleTest.java b/shell/console/src/test/java/org/apache/karaf/shell/console/jline/ConsoleTest.java deleted file mode 100644 index 34546c3..0000000 --- a/shell/console/src/test/java/org/apache/karaf/shell/console/jline/ConsoleTest.java +++ /dev/null @@ -1,195 +0,0 @@ -/* - * 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.karaf.shell.console.jline; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertSame; -import static org.junit.Assert.assertTrue; - -import java.io.InputStream; -import java.io.PrintStream; -import java.security.PrivilegedAction; - -import javax.security.auth.Subject; - -import org.apache.felix.gogo.api.CommandSessionListener; -import org.apache.felix.gogo.runtime.threadio.ThreadIOImpl; -import org.apache.felix.service.command.CommandProcessor; -import org.apache.felix.service.command.CommandSession; -import org.apache.felix.service.command.Converter; -import org.apache.karaf.jaas.boot.principal.RolePrincipal; -import org.apache.karaf.shell.console.jline.Console.DelegateSession; -import org.apache.karaf.shell.security.impl.SecuredCommandProcessorImpl; -import org.easymock.EasyMock; -import org.easymock.IAnswer; -import org.junit.Test; -import org.osgi.framework.BundleContext; -import org.osgi.framework.Filter; -import org.osgi.framework.FrameworkUtil; -import org.osgi.framework.ServiceListener; -import org.osgi.framework.ServiceReference; - -public class ConsoleTest { - @Test - public void testConsoleImpl() throws Exception { - ServiceReference<?> cmRef = EasyMock.createMock(ServiceReference.class); - EasyMock.expect(cmRef.getProperty(CommandProcessor.COMMAND_SCOPE)).andReturn("myscope").anyTimes(); - EasyMock.expect(cmRef.getProperty(CommandProcessor.COMMAND_FUNCTION)).andReturn("myfunction").anyTimes(); - EasyMock.replay(cmRef); - ServiceReference<?>[] cmRefs = new ServiceReference[] {cmRef}; - - BundleContext bc = EasyMock.createMock(BundleContext.class); - EasyMock.expect(bc.getServiceReference((Class<?>) EasyMock.anyObject())).andReturn(null).anyTimes(); - EasyMock.expect(bc.getService((ServiceReference<?>) EasyMock.anyObject())).andReturn(null).anyTimes(); - bc.addServiceListener(EasyMock.isA(ServiceListener.class), EasyMock.isA(String.class)); - EasyMock.expectLastCall().anyTimes(); - EasyMock.expect(bc.getServiceReferences((String) null, - "(&(osgi.command.scope=*)(osgi.command.function=*)" + - "(|(org.apache.karaf.service.guard.roles=myrole)(!(org.apache.karaf.service.guard.roles=*))))")).andReturn(cmRefs).anyTimes(); - EasyMock.expect(bc.getServiceReferences(Converter.class.getName(), null)).andReturn(null).anyTimes(); - EasyMock.expect(bc.getServiceReferences(CommandSessionListener.class.getName(), null)).andReturn(null).anyTimes(); - EasyMock.expect(bc.createFilter(EasyMock.isA(String.class))).andAnswer(new IAnswer<Filter>() { - @Override - public Filter answer() throws Throwable { - return FrameworkUtil.createFilter((String) EasyMock.getCurrentArguments()[0]); - } - }).anyTimes(); - EasyMock.replay(bc); - - final Console console = new Console(null, new ThreadIOImpl(), System.in, System.out, System.err, null, "UTF-8", null, bc); - assertTrue(console.session instanceof DelegateSession); - - console.session.put("foo", "bar"); - - final DelegateSession ds = (DelegateSession) console.session; - assertNull("Precondition", ds.delegate); - - Subject subject = new Subject(); - subject.getPrincipals().add(new RolePrincipal("myrole")); - - Subject.doAs(subject, new PrivilegedAction<Object>() { - @Override - public Object run() { - SecuredCommandProcessorImpl secCP = console.createSecuredCommandProcessor(); - assertNotNull(ds.delegate); - assertEquals("Attributes set before the delegate was set should have been transferred", - "bar", ds.get("foo")); - assertEquals("Attributes set before the delegate was set should have been transferred", - "bar", ds.delegate.get("foo")); - assertSame(System.out, ds.delegate.getConsole()); - assertSame(System.out, ds.getConsole()); - - assertTrue(secCP.getCommands().contains("myscope:myfunction")); - - return null; - } - }); - } - - @Test - public void testDelegateSession() throws Exception { - DelegateSession ds = new DelegateSession(); - - ds.put("a", "b"); - assertEquals("b", ds.get("a")); - - TestSession ts = new TestSession(); - - assertNull("Precondition", ts.lastInvoked); - - ds.setDelegate(ts); - assertEquals("put(a,b)", ts.lastInvoked); - - ds.put("c", "d"); - assertEquals("put(c,d)", ts.lastInvoked); - - ds.execute("hello 1234"); - assertEquals("execute(hello 1234)", ts.lastInvoked); - - ds.close(); - assertEquals("close", ts.lastInvoked); - - ds.getKeyboard(); - assertEquals("getKeyboard", ts.lastInvoked); - - ds.getConsole(); - assertEquals("getConsole", ts.lastInvoked); - - ds.get("xyz"); - assertEquals("get(xyz)", ts.lastInvoked); - - ds.format("foo", 12); - assertEquals("format(foo,12)", ts.lastInvoked); - - ds.convert(TestSession.class, "a string"); - assertEquals("convert(TestSession,a string)", ts.lastInvoked); - } - - static class TestSession implements CommandSession { - String lastInvoked; - - @Override - public Object execute(CharSequence commandline) throws Exception { - lastInvoked = "execute(" + commandline + ")"; - return null; - } - - @Override - public void close() { - lastInvoked = "close"; - } - - @Override - public InputStream getKeyboard() { - lastInvoked = "getKeyboard"; - return null; - } - - @Override - public PrintStream getConsole() { - lastInvoked = "getConsole"; - return null; - } - - @Override - public Object get(String name) { - lastInvoked = "get(" + name + ")"; - return null; - } - - @Override - public void put(String name, Object value) { - lastInvoked = "put(" + name + "," + value + ")"; - } - - @Override - public CharSequence format(Object target, int level) { - lastInvoked = "format(" + target + "," + level + ")"; - return null; - } - - @Override - public Object convert(Class<?> type, Object instance) { - lastInvoked = "convert(" + type.getSimpleName() + "," + instance + ")"; - return null; - } - } -} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/karaf/blob/94ffa5e5/shell/console/src/test/java/org/apache/karaf/shell/security/impl/SecuredCommandProcessorImplTest.java ---------------------------------------------------------------------- diff --git a/shell/console/src/test/java/org/apache/karaf/shell/security/impl/SecuredCommandProcessorImplTest.java b/shell/console/src/test/java/org/apache/karaf/shell/security/impl/SecuredCommandProcessorImplTest.java index 351a89f..0c66eb6 100644 --- a/shell/console/src/test/java/org/apache/karaf/shell/security/impl/SecuredCommandProcessorImplTest.java +++ b/shell/console/src/test/java/org/apache/karaf/shell/security/impl/SecuredCommandProcessorImplTest.java @@ -132,7 +132,7 @@ public class SecuredCommandProcessorImplTest { // Subclass to provide access to some protected members static class MySecuredCommandProcessorImpl extends SecuredCommandProcessorImpl { public MySecuredCommandProcessorImpl(BundleContext bc) { - super(bc); + super(bc, null); } Map<String, Object> getConstants() { http://git-wip-us.apache.org/repos/asf/karaf/blob/94ffa5e5/shell/ssh/src/main/java/org/apache/karaf/shell/ssh/ShellFactoryImpl.java ---------------------------------------------------------------------- diff --git a/shell/ssh/src/main/java/org/apache/karaf/shell/ssh/ShellFactoryImpl.java b/shell/ssh/src/main/java/org/apache/karaf/shell/ssh/ShellFactoryImpl.java index 37fb37c..8668b3c 100644 --- a/shell/ssh/src/main/java/org/apache/karaf/shell/ssh/ShellFactoryImpl.java +++ b/shell/ssh/src/main/java/org/apache/karaf/shell/ssh/ShellFactoryImpl.java @@ -44,6 +44,8 @@ import org.apache.sshd.server.SessionAware; import org.apache.sshd.server.session.ServerSession; import org.osgi.framework.BundleContext; import org.osgi.service.blueprint.container.ReifiedType; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * SSHD {@link org.apache.sshd.server.Command} factory which provides access to Shell. @@ -56,6 +58,8 @@ public class ShellFactoryImpl implements Factory<Command> { JaasHelper.DelegatingProtectionDomain.class, }; + private static final Logger LOGGER = LoggerFactory.getLogger(ShellFactoryImpl.class); + private CommandProcessor commandProcessor; private ThreadIO threadIO; private BundleContext bundleContext; @@ -111,63 +115,63 @@ public class ShellFactoryImpl implements Factory<Command> { } public void start(final Environment env) throws IOException { - try { - final Terminal terminal = new SshTerminal(env); - String encoding = env.getEnv().get("LC_CTYPE"); - if (encoding != null && encoding.indexOf('.') > 0) { - encoding = encoding.substring(encoding.indexOf('.') + 1); - } - Console console = new Console(commandProcessor, - threadIO, - in, - new PrintStream(new LfToCrLfFilterOutputStream(out), true), - new PrintStream(new LfToCrLfFilterOutputStream(err), true), - terminal, - encoding, - new Runnable() { - public void run() { - destroy(); - } - }, - bundleContext); - final CommandSession session = console.getSession(); - session.put("APPLICATION", System.getProperty("karaf.name", "root")); - for (Map.Entry<String,String> e : env.getEnv().entrySet()) { - session.put(e.getKey(), e.getValue()); - } - session.put("#LINES", new Function() { - public Object execute(CommandSession session, List<Object> arguments) throws Exception { - return Integer.toString(terminal.getHeight()); - } - }); - session.put("#COLUMNS", new Function() { - public Object execute(CommandSession session, List<Object> arguments) throws Exception { - return Integer.toString(terminal.getWidth()); + new Thread() { + @Override + public void run() { + Subject subject = ShellImpl.this.session != null ? ShellImpl.this.session.getAttribute(KarafJaasAuthenticator.SUBJECT_ATTRIBUTE_KEY) : null; + if (subject != null) { + JaasHelper.doAs(subject, new PrivilegedAction<Object>() { + public Object run() { + runConsole(); + return null; + } + }); + } else { + runConsole(); } - }); - session.put(".jline.terminal", terminal); - new Thread(console) { - @Override - public void run() { - Subject subject = ShellImpl.this.session != null ? ShellImpl.this.session.getAttribute(KarafJaasAuthenticator.SUBJECT_ATTRIBUTE_KEY) : null; - if (subject != null) { - JaasHelper.doAs(subject, new PrivilegedAction<Object>() { - public Object run() { - doRun(); - return null; - } - }); - } else { - doRun(); + } + protected void runConsole() { + try { + final Terminal terminal = new SshTerminal(env); + String encoding = env.getEnv().get("LC_CTYPE"); + if (encoding != null && encoding.indexOf('.') > 0) { + encoding = encoding.substring(encoding.indexOf('.') + 1); } + final Console console = new Console(commandProcessor, + threadIO, + in, + new PrintStream(new LfToCrLfFilterOutputStream(out), true), + new PrintStream(new LfToCrLfFilterOutputStream(err), true), + terminal, + encoding, + new Runnable() { + public void run() { + ShellImpl.this.destroy(); + } + }, + bundleContext); + final CommandSession session = console.getSession(); + session.put("APPLICATION", System.getProperty("karaf.name", "root")); + for (Map.Entry<String,String> e : env.getEnv().entrySet()) { + session.put(e.getKey(), e.getValue()); + } + session.put("#LINES", new Function() { + public Object execute(CommandSession session, List<Object> arguments) throws Exception { + return Integer.toString(terminal.getHeight()); + } + }); + session.put("#COLUMNS", new Function() { + public Object execute(CommandSession session, List<Object> arguments) throws Exception { + return Integer.toString(terminal.getWidth()); + } + }); + session.put(".jline.terminal", terminal); + console.run(); + } catch (Exception e) { + LOGGER.warn("Unable to start shell", e); } - protected void doRun() { - super.run(); - } - }.start(); - } catch (Exception e) { - throw (IOException) new IOException("Unable to start shell").initCause(e); - } + } + }.start(); } public void destroy() {