blob: c4b388b342354cafa83a0808f4371eac902aeac9 [file] [log] [blame]
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"><html lang="en">
<HEAD>
<meta name="copyright" content="Copyright (c) IBM Corporation and others 2012, 2020. This page is made available under license. For full details see the LEGAL in the documentation book that contains this page." >
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=ISO-8859-1">
<META HTTP-EQUIV="Content-Style-Type" CONTENT="text/css">
<LINK REL="STYLESHEET" HREF="../book.css" CHARSET="ISO-8859-1" TYPE="text/css">
<TITLE>Console Shell</TITLE>
<link rel="stylesheet" type="text/css" HREF="../book.css">
</HEAD>
<BODY BGCOLOR="#ffffff">
<h1>Console Shell</h1>
<h2>General features</h2>
<p>The Equinox OSGi console is based on Apache Felix Gogo, which provides a Unix-like shell
for OSGi frameworks. The OSGi console is useful for runtime configuration and management of the
framework and bundles deployed within it. It can also be useful for debugging and troubleshooting
of OSGi-based applications.</p>
<p>The Equinox console provides:</p>
<ul>
<li>support for console sessions over Telnet and SSH protocols</li>
<li><a href="https://docs.oracle.com/javase/8/docs/technotes/guides/security/jaas/JAASRefGuide.html">JAAS</a> based user authentication</li>
<li>public key based authentication</li>
<li>tab completion and command history</li>
</ul>
<p>This guide shows how to configure and use the console in a minimal OSGi runtime.</p>
<h2>Starting a Command Line Session</h2>
<p>The minimal bundle set needed to start Equinox with the console on the command line is as follows:</p>
<ul>
<li>org.apache.felix.gogo.command_&lt;version&gt;.jar</li>
<li>org.apache.felix.gogo.runtime_&lt;version&gt;.jar</li>
<li>org.apache.felix.gogo.shell_&lt;version&gt;.jar</li>
<li>org.eclipse.equinox.console_&lt;version&gt;.jar</li>
<li>org.eclipse.osgi_&lt;version&gt;.jar</li>
</ul>
<p>All of these bundles are available in the <b>Equinox SDK</b> zip file available from the
<a href="https://download.eclipse.org/equinox/">Equinox Downloads</a> site.</p>
<p>Extract these bundles into a directory, then inside that directory create a
<b>configuration/config.ini</b> file with the following content:</p>
<pre>
osgi.bundles=\
org.apache.felix.gogo.runtime,\
org.apache.felix.gogo.command,\
org.apache.felix.gogo.shell,\
org.eclipse.equinox.console</pre>
<p>Now this minimal Equinox configuration can be started with a console available on the command
line, by passing the <code>-console</code> option, for example:</p>
<pre>
$ java -jar org.eclipse.osgi_*.jar -console
osgi> ss
"Framework is launched."
id State Bundle
0 ACTIVE org.eclipse.osgi_3.15.200.v20200214-1600
1 ACTIVE org.apache.felix.gogo.runtime_1.1.0.v20180713-1646
2 ACTIVE org.apache.felix.gogo.command_1.0.2.v20170914-1324
3 ACTIVE org.apache.felix.gogo.shell_1.1.0.v20180713-1646
4 ACTIVE org.eclipse.equinox.console_1.4.0.v20190819-1430
osgi> exit
Really want to stop Equinox? (y/n; default=y)</pre>
<h2>Starting a Telnet Session</h2>
<p>Starting the console in a Telnet session is enabled by passing a port number with the
<code>-console</code> option, for example:</p>
<pre>
$ java -jar org.eclipse.osgi_*.jar -console 1234</pre>
<p>Once Equinox is started, connect to the Telnet session from another terminal using the
port number that was specified above:</p>
<pre>
$ telnet localhost 1234
Trying ::1...
Connected to localhost.
Escape character is '^]'.
osgi> ss
"Framework is launched."
id State Bundle
0 ACTIVE org.eclipse.osgi_3.15.200.v20200214-1600
1 ACTIVE org.apache.felix.gogo.runtime_1.1.0.v20180713-1646
2 ACTIVE org.apache.felix.gogo.command_1.0.2.v20170914-1324
3 ACTIVE org.apache.felix.gogo.shell_1.1.0.v20180713-1646
4 ACTIVE org.eclipse.equinox.console_1.4.0.v20190819-1430
osgi> disconnect
Disconnect from console? (y/n; default=y)
Connection closed by foreign host.</pre>
<p>It is possible to set the port in the <b>configuration/config.ini</b> file with the
addition of this line:</p>
<pre>
osgi.console=1234
# ... or ...
osgi.console=localhost:1234</pre>
<p>The <code>osgi.console</code> property specifies the port (and optionally the hostname) on
which the console should listen for Telnet connections without needing to pass the <code>-console</code>
option at all, but if <code>-console</code> is passed it will override any setting present in the
<b>configuration/config.ini</b> file.</p>
<h2>Starting an SSH Session with JAAS Authentication</h2>
<p>To start a console session in an SSH session, a few more bundles are needed:</p>
<ul>
<li>org.apache.felix.gogo.command_&lt;version&gt;.jar</li>
<li>org.apache.felix.gogo.runtime_&lt;version&gt;.jar</li>
<li>org.apache.felix.gogo.shell_&lt;version&gt;.jar</li>
<li>org.apache.sshd.osgi_&lt;version&gt;.jar</li>
<li>org.eclipse.equinox.console_&lt;version&gt;.jar</li>
<li>org.eclipse.equinox.console.jaas.fragment_&lt;version&gt;.jar</li>
<li>org.eclipse.equinox.console.ssh_&lt;version&gt;.jar</li>
<li>org.eclipse.osgi_&lt;version&gt;.jar</li>
<li>org.slf4j.api_&lt;version&gt;.jar</li>
</ul>
<p>All of these bundles are available in the <b>Equinox SDK</b> zip file available from the
<a href="https://download.eclipse.org/equinox/">Equinox Downloads</a> site.</p>
<p>Extract these bundles into a directory, then inside that directory create a
<b>configuration/config.ini</b> file with the following content:</p>
<pre>
osgi.bundles=\
org.apache.felix.gogo.runtime,\
org.apache.felix.gogo.command,\
org.apache.felix.gogo.shell,\
org.apache.sshd.osgi,\
org.eclipse.equinox.console,\
org.eclipse.equinox.console.jaas.fragment,\
org.eclipse.equinox.console.ssh@start,\
org.slf4j.api
osgi.console.ssh=127.0.0.1:1234
osgi.console.ssh.useDefaultSecureStorage=true</pre>
<p>Equinox uses JAAS to authenticate SSH sessions, the default login provider of which must be
configured by creating a JAAS configuration file, for example by creating a file
<b>configuration/console.auth.config</b> with the following content:</p>
<pre>
equinox_console {
org.eclipse.equinox.console.jaas.SecureStorageLoginModule REQUIRED;
};</pre>
<p>Then when starting Equinox, it must be told where the JAAS configuration is by setting the
<code>java.security.auth.login.config</code> system property. The default JAAS login provider stores
its credentials in a one-way encrypted store file that must be specified with the
<code>org.eclipse.equinox.console.jaas.file</code> system property:</p>
<pre>
$ java -Dssh.server.keystore=configuration/hostkey.ser \
-Dorg.eclipse.equinox.console.jaas.file=configuration/store \
-Djava.security.auth.login.config=configuration/console.auth.config \
-jar org.eclipse.osgi_*.jar</pre>
<p>The default JAAS login provider dynamically creates one default user <b>equinox</b> with password
<b>equinox</b>. After logging in with these credentials for the first time, the user will be prompted
to create a new account and the default account will be removed.</p>
<p>Once Equinox is started, connect to the SSH session from another terminal using the hostname and
port specified in the <b>configuration/config.ini</b> file:</p>
<pre>
$ ssh -p 1234 equinox@127.0.0.1
The authenticity of host '[127.0.0.1]:1234 ([127.0.0.1]:1234)' can't be established.
RSA key fingerprint is SHA256:7x3eOsDRM5lyL5vRsVREy8hIawIfqRiZ7CBnk6GkfRA.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '[127.0.0.1]:1234' (RSA) to the list of known hosts.
Password authentication
Password:
Currently the default user is the only one; since it will be deleted after first login, create a new user:
username: mbooth
password:
Confirm password:
roles: admin
osgi> disconnect
Disconnect from console? (y/n; default=y)
Connection to 127.0.0.1 closed.</pre>
<p>The password must be at least 8 symbols long and the username may contain alphanumerical
characters, underscores and dots. On subsequent connections the user will be required to supply the
newly created credentials:</p>
<pre>
$ ssh -p 1234 mbooth@127.0.0.1
Password authentication
Password:
osgi> disconnect
Disconnect from console? (y/n; default=y)
Connection to 127.0.0.1 closed.</pre>
<p>Once logged in there are various commands for administering users. Type <b>help</b> at the OSGi
console prompt to explore commands to perform the following functions:</p>
<ul>
<li>adding, deleting, listing users</li>
<li>reseting and changing passwords</li>
<li>adding and removing user roles</li>
</ul>
<h3>Custom JAAS Authentication Login Providers</h3>
<p>Only authentication is implemented in the default JAAS login provider so by default all
authenticated users have similar rights. Roles exist to allow authorization to be added in
custom JAAS login providers.</p>
<p>A custom JAAS login provider can be used by creating a bundle fragment that extends the
<b>org.apache.sshd.osgi</b> bundle. This fragment is used to provide or import the package
of the custom login provider. This is necessary for the SSH system to be able to load the
provider class.</p>
<p>If a custom JAAS login provider is used, then the <code>osgi.console.ssh.useDefaultSecureStorage</code>
property must not be set in the <b>configuration/config.ini</b> at all and the custom login provider
must be specified in the <b>configuration/console.auth.config</b> file instead of the default
entry there.</p>
<h2>Starting an SSH Session with Public Key Authentication</h2>
<p>It's common to want to use public key authentication with SSH and it is possible to configure
Equinox to do that instead of using JAAS authentication. First an SSH key-pair should be created
as normal and then a file created that contains the list of authorized keys that Equinox should
consult when users attempt to connect:</p>
<pre>
$ ssh-keygen -f ~/.ssh/equinox
Generating public/private rsa key pair.
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/mbooth/.ssh/equinox
Your public key has been saved in /home/mbooth/.ssh/equinox.pub
The key fingerprint is:
SHA256:0k7MSbLLzhhzI7Gw6oSYEx8Fv5UpNHMPTdOUDj8rplQ mbooth@thinkpad-p50
The key's randomart image is:
+---[RSA 3072]----+
| . + oooo.. |
| + + =o.o |
| + = o+ |
| . + BE.+ |
|. o o o.S o |
|o+ + +.=o . |
|=.o =.=o.. |
|.o O.. |
|o. . o |
+----[SHA256]-----+
$ cat ~/.ssh/equinox.pub > configuration/equinox_authorized_keys</pre>
<p>Next the following line must be removed from the <b>configuration/config.ini</b> file:</p>
<pre>
# Remove this line to use public key authentication
# Must only be present when using the default JAAS login provider
osgi.console.ssh.useDefaultSecureStorage=true</pre>
<p>Now when starting Equinox, instead of telling it about the JAAS configuration, it must be
told about the authorized keys file by setting the <code>ssh.server.authorized_keys</code>
system property:</p>
<pre>
$ java -Dssh.server.keystore=configuration/hostkey.ser \
-Dssh.server.authorized_keys=configuration/equinox_authorized_keys \
-jar org.eclipse.osgi_*.jar</pre>
<p>And that allows users to use their SSH keys instead of a username/password pair when
connecting to the SSH console session:</p>
<pre>
$ ssh -i ~/.ssh/equinox -p 1234 localhost
The authenticity of host '[localhost]:1234 ([127.0.0.1]:1234)' can't be established.
RSA key fingerprint is SHA256:m2JKy2fRZA1aqvxHBBe+Awsgk98ryI29fH03Rg7jeHw.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '[localhost]:1234' (RSA) to the list of known hosts.
osgi> disconnect
Disconnect from console? (y/n; default=y)
Connection to localhost closed.</pre>
<p>The authorized keys file given to Equinox will be read every time a connection is made,
which allows adding and removing of keys dynamically at runtime.</p>
<h3>Custom Public Key Authentication</h3>
<p>Equinox also supports customizing the public key authentication mechanism. If no
specific authorized keys file is configured via system property then the OSGi service
registry will be searched for available authenticators. To enable this feature set the
<code>ssh.custom.publickeys.auth</code> system property to <code>true</code>.</p>
<h2>Starting Telnet and SSH Sessions Together</h2>
<p>It is possible to start Equinox console sessions over both Telnet and SSH simultaneously.
For this, both the <code>osgi.console</code> and <code>osgi.console.ssh</code> properties must
be specified in the <b>configuration/config.ini</b> file:</p>
<pre>
# Telnet session
osgi.console=&lt;hostname&gt;:&lt;port&gt;
# SSH session
osgi.console.ssh=&lt;hostname&gt;:&lt;port&gt;</pre>
<p>These properties specify the port on which to listen and the hostname (or IP address) to
which it binds for incoming connections.</p>
<p>For both properties, the hostname (or IP address) is optional and may be omitted. If the
hostname is omitted, then localhost is assumed. If the hostname is the same for both properties,
or both hostnames are omitted then the SSH session must have a different port number to the
Telnet session.</p>
<h2>Using the Configuration Admin Service</h2>
<p>It is possible to configure Telnet and SSH console sessions through the Configuration Admin
Service instead of using the <code>osgi.console</code> and <code>osgi.console.ssh</code>
properties. This is helpful in more complex scenarios, for example when you want to run different
instances of the console in different subsystems of the framework. In this case if the port is
configured through a system property, the same value is used for all console instances and only one
will be able to bind to the socket.</p>
<p>To enable this feature, the Configuration Admin bundle and it's dependencies must be added
to the Equinox instance:</p>
<ul>
<li>org.eclipse.equinox.cm_&lt;version&gt;.jar</li>
<li>org.eclipse.osgi.services_&lt;version&gt;.jar</li>
<li>org.eclipse.osgi.util_&lt;version&gt;.jar</li>
</ul>
<p>All of these bundles are available in the <b>Equinox SDK</b> zip file available from the
<a href="https://download.eclipse.org/equinox/">Equinox Downloads</a> site.</p>
<p>And then in the <b>configuration/config.ini</b> file, the <code>osgi.console.useConfigAdmin</code>
property must be used in place of the usual configuration properties:</p>
<pre>
# Remove these properties:
#osgi.console=&lt;hostname&gt;:&lt;port&gt;
#osgi.console.ssh=&lt;hostname&gt;:&lt;port&gt;
# Use the Config Admin Service instead:
osgi.console.useConfigAdmin=true</pre>
<p>Now a custom bundle must be written that uses the Configuration Admin Service to configure
Telnet and SSH console sessions. The Persistent Identity (PID) for the Telnet configuration is
<code>osgi.console.telnet</code> and for the SSH configuration is <code>osgi.console.ssh</code>.
Both configurations have the following properties, all expecting values of type String:</p>
<ul>
<li><code>host</code></li>
<li><code>port</code></li>
<li><code>enabled</code></li>
</ul>
<p>The <code>enabled</code> property determines if the Telnet or SSH session is to be started
at all. If the value is <code>true</code>, it is started. If the value is <code>false</code>,
or the property <code>enabled</code> is absent, the Telnet or SSH session is not started.</p>
<h2>Console Command Usage</h2>
<p>The Equinox console works similarly to Unix-style shells. Multiple commands can be sent when
separated by a semi-colon and the output of commands may be piped to the input of other commands.
For example:</p>
<pre>
osgi> ss | grep slf4j
8 ACTIVE org.slf4j.api_1.7.2.v20121108-1250
true
osgi> stop 8 ; start 8</pre>
<p>IO redirection can be simulated with the <b>cat</b> and <b>tac</b> commands. For example:</p>
<pre>
osgi> ss | tac out.txt
osgi> cat out.txt | grep slf4j
8 ACTIVE org.slf4j.api_1.7.2.v20121108-1250
true</pre>
<p>The console also has standard command line editing features such as:</p>
<ul>
<li>backspace - deletes the character to the left of the cursor</li>
<li>delete - deletes the character on the cursor position</li>
<li>home/end - moves the cursor to the beginning/end of the command line</li>
<li>left/right arrow - moves the cursor one character left/right</li>
<li>up/down arrow - moves backward/forward one entry in the command history</li>
<li>pageup/pagedown - moves to the first/last entry of the command history</li>
<li>tab - command completion (described in more detail below)</li>
</ul>
<p>However some of these editing features are only supported when using the console via a
Telnet or SSH session.</p>
<h3>Command Scopes</h3>
<p>Equinox console commands have the notion of command scope. The scope is a kind of namespace
that can be used, for example, to differentiate between commands with the same name, but provided
by different providers.</p>
<p>The scope is a prefix of the command name, separated from it by a colon. When writing the
command in the console, specifying the scope is optional: A command may be written as
<code>command_name</code> or <code>scope:command_name</code>. If the scope is not specified,
then the command with this name from the default scope is used. If there is no such command in
the default scope, all scopes are searched.</p>
<p>If there is more than one command with the specified name in different, non-default scopes,
it is not guaranteed which one will be actually executed. Therefore, if there are commands
with the same name but in different scopes, the scope prefix must be specified explicitly
with the command name to ensure that exactly the desired command is executed.</p>
<p>The Equinox console is now based on Apache Felix Gogo, which has a different way of
implementing console commands than the traditional Equinox way. Equinox adapts these legacy
commands for the Gogo-based shell and makes them available in the <b>equinox</b> scope.
For compatibility, the default scope is the <b>equinox</b> scope.</p>
<h3>Getting Help for Commands</h3>
<p>Typing <b>help</b> (or <b>man</b>) at the OSGi console prompt with no arguments, the help for
all available commands is displayed. To limit the output to commands from a specific scope, the
<code>-scope &lt;scope_name&gt;</code> parameter can be passed to the <b>help</b> command:</p>
<pre>
osgi> help -scope equinox
close - shutdown and exit
scope: equinox
diag - Displays unsatisfied constraints for the specified bundle(s)
scope: equinox
parameters:
Bundle[] IDs of bundle(s), for which to display unsatisfied constraints
...etc...</pre>
<p>The help text for a specific command can be shown by passing a
<code>command_name</code> or <code>scope:command_name</code> to the <b>help</b> command. If
the scope is not specified, then the help text is shown for the command from the default scope
if it exists:</p>
<pre>
osgi> help headers
headers - print bundle headers
scope: equinox
parameters:
Bundle[] bundles to print headers for
osgi> help felix:headers
headers - display bundle headers
scope: felix
parameters:
Bundle[] target bundles</pre>
<p>The default help command provided by the Apache Felix Gogo shell does not provide help
for the legacy Equinox commands, which are adapted by the Equinox console for the Gogo shell.
For this reason the Equinox console provides its own <b>help</b> command in the <b>equinox</b> scope
that delegates to the default help command whilst also providing help for legacy commands.</p>
<h3>Closing Console Sessions</h3>
<p>When using the Equinox console standalone on the command line, the <b>exit</b> command can be
used to terminate Equinox and return to the system command prompt.</p>
</p>For both Telnet and SSH sessions, the session can be closed without terminating Equinox with
the <b>disconnect</b> command.</p>
<h2>Implementing Custom Console Commands</h2>
<p>Traditionally in Equinox commands are provided by a class implementing the
<code>org.eclipse.osgi.framework.console.CommandProvider</code> interface. The Equinox console
provides an adapter from this legacy type of command to the new type of command used in Gogo but it is
preferred that new commands are implemented as Gogo commands directly.</p>
<p>Commands for Apache Felix Gogo are plain old Java object (POJO) classes with all the commands
implemented as public methods. The methods may have arbitrary arguments. These classes are
registered as services, with two special properties:</p>
<ul>
<li><code>osgi.command.scope</code> - specifies the scope of the command</li>
<li><code>osgi.command.function</code> - specifies the commands provided by this service;
this is a string array containing the names of public methods in the implementing class
that can be executed as commands</li>
</ul>
<p>Gogo commands also have the notion of converters and formatters.</p>
<p>A converter is a class which converts the arguments passed at the OSGi console prompt,
to the actual arguments that the command accepts. For example, the command may have one
argument of type <code>Bundle</code>. A converter might accept a long integer and finds the
bundle with this ID. Then the command may be called with the ID of the bundle as an argument,
the converter will convert it to the corresponding <code>Bundle</code> object and the command
method will be called with this object as an argument.</p>
<p>A formatter is a class which displays a result returned by a command method.</p>
<p>For more information on Gogo commands, see the <a href="http://felix.apache.org/documentation/subprojects/apache-felix-gogo.html">Gogo documentation</a>.</p>
<h2>Implementing Custom Tab Completion</h2>
<p>The Equinox console provides tab completion and allows implementors to provide their own
custom completion providers. This feature is available only when connecting through a Telnet
or SSH session. Completion is available for:</p>
<ul>
<li>command names</li>
<li>variable names passed as command arguments - these must be previously defined in the session</li>
<li>file names passed as command arguments</li>
</ul>
<p>When the <code>tab</code> key is typed, all possible candidates for completion for the current
word are searched. If there is only one possible completion, the current word is automatically
completed. If there is more than one option, all are displayed. The user can then cycle through the
possible completions by hitting <code>tab</code> multiple times, until the desired completion
candidate is selected.</p>
<p>If longest common prefix of all available completion candidates is longer than the current word,
then the current word is completed automatically to this prefix before choosing the final completion.
For example, if the following completions are available for the word <b>bun</b>:</p>
<ul>
<li>bundles</li>
<li>bundle</li>
<li>bundlelevel</li>
</ul>
<p>Then the current word is completed automatically to <b>bundle</b> and the user can continue
typing normally or, by hitting <code>tab</code> again, they can cycle through the possible
completions.</p>
<p>A custom completer should implement the <code>org.eclipse.equinox.console.common.Completer</code>
interface provided by the Equinox console bundle. It has the single method <code>getCandidates</code>,
which take as parameters the whole command line and the current cursor position within it, and returns
a map of completion candidates to positions in the command line at which the completion begins.</p>
</BODY>
</HTML>