From OpenHome

(Difference between revisions)
Jump to: navigation, search
 
(25 intermediate revisions not shown)
Line 2: Line 2:
ohRemote provides the set of server components used to access ohOs apps from outside the home.
ohRemote provides the set of server components used to access ohOs apps from outside the home.
-
Remote access is designed to be as simple as possible to enable and as cheap as possible to host.  It is intended that tens of thousands of clients (homes) can be accommodated by a single server.  When user numbers grow beyond this or the geographical spread of users makes a single server a bottleneck, minimal work will allow any number of additional servers to be deployed.
+
 
 +
==== Simple for an end user to set up and use ====
 +
It has been designed to be trivial for end users to setup and use.  All communications are routed through a central server, avoiding any requirement for users to learn about port forwarding, static external IP addresses, or setup firewall rules to allow incoming http connections etc.
 +
 
 +
==== Cheap to host ====
 +
Secondly, it has been designed so that the central server can be inexpensive for Node manufacturers to host.  It is intended that tens of thousands of clients (homes) can be accommodated by a single server.  When user numbers grow beyond this or the geographical spread of users makes a single server a bottleneck, minimal work will allow any number of additional servers to be deployed.
 +
 
 +
 
 +
In addition to the software in ohRemote, remote access requires some additional features in [[ohOs|ohOs]].  These are also described below.
== How do I get it? ==
== How do I get it? ==
-
Source code is available to selected partners from github [https://github.com/openhome/ohremote].  Contact info@openhome.org if you require access.
+
[https://github.com/openhome/ohremote Source code] is available to selected partners.  OpenHome also maintain a demo server.  Contact info@openhome.org if you require access to either.
== System Architecture ==
== System Architecture ==
-
[diagram]
+
[[File:RemoteAccessOverview.png|800px|center]]
 +
 
The server contains the following components:
The server contains the following components:
-
Stunnel [http://www.stunnel.org/] – a SSL tunnel which allows secure communications between user/node and the server without server components having to understand SSL.
+
* [http://www.stunnel.org/ Stunnel] – a SSL tunnel which allows secure communications between user/node and the server without server components having to understand SSL.
-
A reverse proxy server – HaProxy [http://haproxy.1wt.eu/].  This directs web requests to the correct server component.
+
* A reverse proxy server – [http://haproxy.1wt.eu/ HaProxy].  This directs web requests to the correct server component.
-
Web server, provided by Node.js [http://nodejs.org/]
+
* Web server, provided by [http://nodejs.org/ Node.js]
-
Web services, implemented using Node.js [http://nodejs.org/]
+
* Web services, implemented using [http://nodejs.org/ Node.js]
-
SSH server, provided by dropbear [http://matt.ucc.asn.au/dropbear/dropbear.html]
+
* SSH server, provided by [http://matt.ucc.asn.au/dropbear/dropbear.html dropbear]
-
Client authentication – a pluggable authentication module [http://en.wikipedia.org/wiki/Pluggable_authentication_module] used by the ssh server when deciding whether to accept a connection request from a Node.
+
* Client authentication – a [http://en.wikipedia.org/wiki/Pluggable_authentication_module pluggable authentication module] used by the ssh server when deciding whether to accept a connection request from a Node.
-
Databases, provided by MySQL [http://www.mysql.com]
+
* Databases, provided by [http://www.mysql.com MySQL]
 +
 
The Node contains the following components:
The Node contains the following components:
-
1. Standard node software
+
* Standard node software
-
2. Provider for RemoteAccess UPnP service [link]
+
* Provider for RemoteAccess UPnP service
-
3. Remote access settings registry (currently combined with provider).
+
* Remote access settings registry (currently combined with provider). This stores username, password, user-facing control url & node-facing web services url
-
This stores username, password, user-facing control url & node-facing web services url
+
* Proxy serverThis connects to the remote access server’s ssh server and listens for requests, forwarding them to the appropriate locations on the standard node web server.  The proxy server uses standard .NET classes – <tt>HttpListener</tt> for the server and <tt>HttpWebRequest</tt> to forward requests.
-
4. Proxy server
+
 
-
This connects to the remote access server’s ssh server and listens for requests, forwarding them to the appropriate locations on the standard node web server.  The proxy server uses standard .NET classes – HttpListener for the server and HttpWebRequest to forward requests.
+
The remote client contains the following components:
The remote client contains the following components:
-
Any web browser supported by the Node UI.
+
* Any web browser supported by the Node UI.
-
== Deployment ==
+
== Use cases ==  
-
Server instructions – config options all contains in ohremote/scripts/config.  Hosting the server on a box with 2 IP addresses is recommended.  This allows both the ssh server and web services to operate on port 443.  This port is used by https so is likely to be open for outbound requests on most firewalls.  (An argument could be made for port 80 – as used by http.  This is at least as likely to be open on firewalls but is more likely to be subject to packet inspection and blocked as our use here will appear different to traditional web access.)
+
To aid understanding of the architecture diagram, key use cases for the system are described below.
-
Node instructions – key generation, setting server
+
-
The location of the remote access server must be set in the remote-access-server tag of ohos.ohconfig.xml.  This file is generated from ohOs/src/Host/ Host.ohconfig.xml.template during a build or the generated file can be edited and ohOs restarted to apply changes.
+
-
The Node must be capable of generating a RSA format SSH key.  This is currently only supported on Linux; other platforms need to manually generate the keys and move them (named key.priv & key.pub) to the remote directory in ohWidget’s store.
+
-
== APIs ==
+
=== Register new Node ===
-
=== Server Web Services ===
+
* User brings up their Node UI inside the home
-
See notes on deployment [link] for how to determine [server_url] & generate ssh keys.
+
* User enters desired username & password
-
Note that [server_url] is set by the Node maintainer.  By default it is https://login.remote.openhome.org.
+
* Provider for RemoteAccess service is called for <tt>SetUserName</tt> action
-
The Node must be capable of generating a RSA format SSH key.  This is currently only supported on Linux; other platforms need to manually generate the keys and move them (named key.priv & key.pub) to the remote directory in ohWidget’s store.
+
* Provider calls <tt>register</tt> web service
-
1. To register for remote access, including selecting a username
+
* Registration web service on remote access server is called (via Stunnel then HaProxy)
-
URL:  [server_url]/register
+
* If requested username is available, registration service adds a record to the Login Database.  Otherwise, it generates a list of similar usernames which are still available and returns this as part of an error.
-
Body:
+
* Assuming registration succeeded, Username is added to remote access registry.  <tt>SetUserName</tt> action returns success.
-
<register>
+
* UI calls <tt>SetPassword</tt> action.  Password is added to remote access registry and action returns success.
-
    <username>[Proposed username]</username>
+
* UI calls <tt>SetEnable</tt> action.  Enabled state is set in remote access registry.  Enabling remote access is then covered by the next use case...
-
    <uidnode>[Node’s UDN]</uidnode>
+
-
    <sshkey>[Contents of public key]</sshkey>
+
-
</register>
+
-
Returns (success):
+
-
<result>
+
-
    <success>[Proposed username]</success>
+
-
</result>
+
-
Returns (failure):
+
-
<result>
+
-
    <error>Username exists</error>
+
-
    <suggestionlist>
+
-
        <suggestion>First suggested free name </suggestion>
+
-
        <suggestion>Second suggested free name </suggestion>
+
-
        <suggestion>etc.</suggestion>
+
-
        </suggestion>
+
-
    </suggestionlist>
+
-
</result>
+
-
2. To clear an account - (deregister interest in remote access, remove username)
 
-
URL:  [server_url]/remove
 
-
Body:
 
-
<remove>
 
-
    <uidnode>[Node’s UDN]</uidnode>
 
-
</remove>
 
-
Returns (success):
 
-
<result>
 
-
    <success>TBD</success>
 
-
</result>
 
-
Returns (failure):
 
-
<result>
 
-
    <error>TBD</error>
 
-
</result>
 
-
3. To get connection details for the ssh tunnel
+
=== Connect a registered Node ===
-
URL:  [server_url]/getaddress
+
* Happens either when <tt>SetEnable</tt> action is called or ohOs starts when remote access was previously enabled.
-
Body:
+
* Provider for RemoteAccess service calls <tt>getaddress</tt> on Node Login service (via Stunnel then HaProxy)
-
< getaddress >
+
* Node Login service checks that node has been previously registered (by checking for node’s udn in Login Database).  If the node is unregistered, an error is returned.
-
    <uidnode>[Node’s UDN]</uidnode>
+
* Node Login service calls Port Finder service to determine which port of the ssh server the node should connect to.
-
</ getaddress >
+
* Port Finder service determines a free port.  Node Login service writes node udn, ssh server address & port, plus status (pending) to the Session Database.
-
Returns (success):
+
* Node Login service checks config file to determine ssh server host name & port (used for connecting to the ssh server) plus the IP address to bind to for remote port forwarding.  These 3 details plus the port determined above are returned to the home node.
-
<result>
+
* Home node now has approx 1 minute to connect to the ssh server.  The Node Login service periodically checks the Session Database and removes records that have been pending for longer than 1 minute.
-
    <success>
+
* Home node starts its proxy server.  This is currently hard-coded to listen on port 55170.
-
        <sshserver>
+
* Home node connects to ssh server.  Server uses PAM SQL Lookup to validate ssh key used in connection request against key in Login Database.  Server then changes status of node’s record in Session Database to ‘connected’.
-
            <address>[Ssh server host (or address)]</address>
+
* Home node sets up remote port forwarding for the port its proxy server is listening on.
-
            <port>[Ssh server port to connect to]</port>
+
-
        </sshserver>
+
-
        <portforward>
+
-
            <address>[Address for remote port forwarding]</address>
+
-
            <port>[Port for remote port forwarding]</port>
+
-
        </portforward>
+
-
    </success>
+
-
</result>
+
-
Returns (failure):
+
-
<result>
+
-
    <error>TBD</error>
+
-
</result>
+
-
=== Node web service ===
 
-
(RemoteAccess service description)
 
-
== Use cases ==
+
=== User connects remotely ===
-
=== Register new Node ===
+
* User enters the url returned by the node registration process into their web browser.
-
• User brings up their Node UI inside the home
+
* This reaches the Login web service (via Stunnel and HaProxy).
-
User enters desired username & password
+
* The url path is the user name that was selected during registration.  Login service looks this up in Login Database and redirects the request to HaProxy with the path changed to the node udn which matches the username.
-
• Provider for RemoteAccess server is called for SetUserName [link] action
+
* HaProxy uses the node udn to look up ssh server address/port in the Session Database.
-
• Provider calls register[link] web service
+
* HaProxy forwards the request to the appropriate address/port on the ssh server.
-
• Registration web service on remote access server is called (via Stunnel then HaProxy)
+
* Ssh server forwards the request to the appropriate proxy server on a home node.
-
• If requested username is available, registration service adds a record to the Login Database. Otherwise, it generates a list of similar usernames which are still available and returns this as part of an error.
+
* Home node checks for the presence of a login cookie in the request.  If this is missing, the request is redirected to a login page hosted by the home node.
-
Following steps assume registration succeeded.
+
* When the first request completes, HaProxy sets a session cookie noting the udn for this user.
-
• Username is added to remote access registry. SetUserName action returns success.
+
* The user’s web browser displays the login page prompting for username and passwordThe results from this are sent to the home node’s proxy server which checks them against the data in its remote access registry.  If the login is valid, another session cookie is set and the user is redirected to the root of the home node’s proxy server.
-
• UI calls SetPassword actionPassword is added to remote access registry and action returns success.
+
* The user’s web browser issues a GET request for ‘/’HaProxy uses its cookie to find the correct ssh server address/port.  (This may come from either the session database or an in-memory cache.) The home node’s proxy server manually forwards the request to the web server home UIs are available from, applying minor rewrites (such as compression) to the response.
-
• UI calls SetEnable actionEnabled state is set in remote access registryEnabling remote access is then covered by the next use case…
+
-
=== Connect a registered Node ===
+
== Deployment ==
-
• Happens either when SetEnable action is called or ohOs starts when remote access was previously enabled.
+
=== Server ===
-
• Provider for RemoteAccess service calls getaddress [link] on Node Login service (via Stunnel then HaProxy)
+
All configuration options are contained in the file <tt>ohremote/scripts/config</tt>.
-
• Node Login service checks that node has been previously registered (by checking for node’s udn in Login Database).  If the node is unregistered, an error is returned.
+
<br>Hosting the server on a box with 2 IP addresses is recommendedThis allows both the ssh server and web services to operate on port 443.  This port is used by https so is likely to be open for outbound requests on most firewalls(An argument could be made for port 80 – as used by http.  This is at least as likely to be open on firewalls but is more likely to be subject to packet inspection and blocked as our use here will appear different to traditional web access.)
-
• Node Login service calls Port Finder service to determine which port of the ssh server the node should connect to.
+
-
• Port Finder service determines a free portNode Login service writes node udn, port and status (pending) to the Session Database.
+
-
• Home node now has approx 1 minute to connect to the ssh server.  The Node Login service periodically checks the Session Database and removes records that have been pending for longer than 1 minute.
+
-
• Node Login service checks config file to determine ssh server host name and IP address/port to bind to for remote port forwardingThese 3 details plus the port determined above are returned to the home node.
+
-
• Home node starts its proxy server.  This is currently hard-coded to listen on port 55170.
+
-
• Home node connects to ssh server.  Server uses PAM SQL Lookup to validate ssh key used in connection request against key in Login Database.  Server then changes status of node’s record in Session Database to ‘connected’.
+
-
• Home node sets up remote port forwarding for the port its proxy server is listening on.
+
-
=== User connects remotely ===
+
=== Node ===
-
• User enters the url returned by the node registration process into their web browser.
+
The location of the remote access server must be set in the <tt>remote-access-server</tt> tag of <tt>ohos.ohconfig.xml</tt>This file is generated from <tt>ohOs/src/Host/Host.ohconfig.xml.template</tt> during a build or the generated file can be edited and ohOs restarted to apply changes.
-
• This reaches the Login web service (via Stunnel and HaProxy).
+
<br>The Node must be capable of generating a RSA format SSH keyThis is currently only supported on Linux; other platforms need to manually generate the keys and move them (named key.priv & key.pub) to the remote directory in ohWidget’s store.
-
The url path is the user name that was selected during registration.  Login service looks this up in Login Database and redirects the request to HaProxy with the path changed to the node udn which matches the username.
+
-
• HaProxy uses the node udn to look up ssh server address/port in the Session Database.
+
-
• HaProxy forwards the request to the appropriate address/port on the ssh server.
+
-
• Ssh server forwards the request to the appropriate proxy server on a home node.
+
-
• Home node checks for the presence of a login cookie in the requestIf this is missing, the request is redirected to a login page hosted by the home node.
+
-
• When the first request completes, HaProxy sets a session cookie noting the Session Database row id for this user.
+
-
• The user’s web browser displays the login page prompting for username and password. The results from this are sent to the home node’s proxy server which checks them against the data in its remote access registry.  If the login is valid, another session cookie is set and the user is redirected to the root of the home node’s proxy server.
+
-
The user’s web browser issues a GET request for ‘/’HaProxy uses its cookie to find the correct ssh server address/port.  (This may come from either the session database or an in-memory cache.) The home node’s proxy server manually forwards the request to the web server home UIs are available from, applying minor rewrites (such as compression) to the response.
+
-
=== Monitoring ===
+
== Monitoring ==
-
server – Every 3 seconds, checks status of each component, restarting server if any component does not respond correctly.  See ohremote/scripts/ohmonitor for details.
+
=== Server ===
-
Node – Every 5 minutes, issues a HEAD request to the user-facing uri returned by register [link] web service (and then stored in registry).  If this fails, disconnects from ssh server, stops (local) proxy server then repeats “Connect a registered node” use case.  If connection fails, it is retried at randomised (but increasing) intervals thereafter.
+
Every 3 seconds, checks status of each component, restarting server if any component does not respond correctly.  See <tt>ohremote/scripts/ohmonitor</tt> for details.
 +
=== Node ===
 +
Every 5 minutes, issues a <tt>HEAD</tt> request to the user-facing uri returned by register web service (and then stored in registry).  If this fails, disconnects from ssh server, stops (local) proxy server then repeats “Connect a registered node” use case.  If connection fails, it is retried at randomised (but increasing) intervals thereafter.
 +
== APIs ==
 +
=== Server Web Services ===
 +
'''1. To register for remote access, including selecting a username'''
 +
URL:  [server_url]/register
 +
Body:
 +
    <register>
 +
        <username>[Proposed username]</username>
 +
        <uidnode>[Node’s UDN]</uidnode>
 +
        <sshkey>[Contents of public key]</sshkey>
 +
    </register>
 +
Returns (success):
 +
    <result>
 +
        <success>[Proposed username]</success>
 +
    </result>
 +
Returns (failure):
 +
    <result>
 +
        <error>Username exists</error>
 +
        <suggestionlist>
 +
            <suggestion>First suggested free name</suggestion>
 +
            <suggestion>Second suggested free name</suggestion>
 +
            <suggestion>etc.</suggestion>
 +
        </suggestionlist>
 +
    </result>
-
== What is it? ==
+
'''2. To clear an account - (deregister interest in remote access, remove username)'''
 +
URL:  [server_url]/remove
 +
Body:
 +
    <remove>
 +
        <uidnode>[Node’s UDN]</uidnode>
 +
    </remove>
 +
Returns (success):
 +
    <result>
 +
        <success>[Node’s UDN]</success>
 +
    </result>
 +
Returns (failure):
 +
    <result>
 +
        <error>[Error Message]</error>
 +
    </result>
 +
'''3. To get connection details for the ssh tunnel'''
 +
URL:  [server_url]/getaddress
 +
Body:
 +
    <getaddress>
 +
        <uidnode>[Node’s UDN]</uidnode>
 +
    </getaddress>
-
== How do I get it? ==
+
Returns (success):
 +
    <result>
 +
        <success>
 +
            <sshserver>
 +
                <address>[Ssh server host (or address)]</address>
 +
                <port>[Ssh server port to connect to]</port>
 +
            </sshserver>
 +
            <portforward>
 +
                <address>[Address for remote port forwarding]</address>
 +
                <port>[Port for remote port forwarding]</port>
 +
            </portforward>
 +
        </success>
 +
    </result>
 +
Returns (failure):
 +
    <result>
 +
        <error>[Error Message]</error>
 +
    </result>
 +
=== Node web service ===
 +
As with other Node features, this is available as a UPnP service - openhome-org:service:RemoteAccess:1.
 +
==== State variables ====
 +
* <tt>Enabled</tt><br><tt>true</tt> if remote access is currently enabled; <tt>false</tt> otherwise.
 +
* <tt>PasswordSet</tt><br><tt>true</tt> if a password is currently set; <tt>false</tt> otherwise.  (Note that the password itself cannot be queried.)
 +
* <tt>PublicUri</tt><br>The url used for remote access.  This is set once a Node has registered for remote access.  The value does not change when <tt>Enabled</tt> changes.
 +
* <tt>UserName</tt><br>The username selected during registration; or <tt>""</tt> if the Node is not registered for remote access.
-
== Docs ==
+
==== Actions ====
 +
* <tt>SetUserName(in uint Handle, in string UserName, out bool Succeeded, out string AlternativeNames)</tt><br>Register a Node for remote access, selecting its unique username.  Arguments are:
 +
** <tt>''Handle'': </tt>Reserved for future compatability.  Must be 0.
 +
** <tt>''UserName'': </tt>Proposed username.
 +
** <tt>''Succeeded'': </tt><tt>true</tt> if <tt>UserName</tt> was available; <tt>false</tt> otherwise.
 +
** <tt>''AlternativeNames'': </tt>XML block in the same form as <tt>suggestionlist</tt> block from <tt>register</tt> web service.
 +
* <tt>SetPassword(int uint Handle, in string Password)</tt><br>Set a password used to authenticate remote connection requests.  Arguments are:
 +
** <tt>''Handle'': </tt>Reserved for future compatability.  Must be 0.
 +
** <tt>''Password'': </tt>Password.  This is held locally on the Node so is guaranteed to be valid.
 +
* <tt>Enable(bool Enable)</tt><br>Enable remote access.  This can only be called when a valid username and password are set.  i.e. When the <tt>UserName</tt> state variable is non-empty and the <tt>PasswordSet</tt> state variable is <tt>true</tt>.  Arguments are:
 +
** <tt>''Enable'': </tt><tt>True</tt> if remote access should be enabled; <tt>false</tt> if it is currently enabled and should be disabled.
 +
* <tt>Reset(uint Handle)</tt><br>Disable remote access, remove registration with remote access server and clear local username and password.
 +
* <tt>ClearAuthenticatedClients()</tt><br>Force any active remote access sessions to re-authenticate.

Latest revision as of 13:35, 7 March 2012

Contents

ohRemote

ohRemote provides the set of server components used to access ohOs apps from outside the home.

Simple for an end user to set up and use

It has been designed to be trivial for end users to setup and use. All communications are routed through a central server, avoiding any requirement for users to learn about port forwarding, static external IP addresses, or setup firewall rules to allow incoming http connections etc.

Cheap to host

Secondly, it has been designed so that the central server can be inexpensive for Node manufacturers to host. It is intended that tens of thousands of clients (homes) can be accommodated by a single server. When user numbers grow beyond this or the geographical spread of users makes a single server a bottleneck, minimal work will allow any number of additional servers to be deployed.


In addition to the software in ohRemote, remote access requires some additional features in ohOs. These are also described below.

How do I get it?

Source code is available to selected partners. OpenHome also maintain a demo server. Contact info@openhome.org if you require access to either.

System Architecture

RemoteAccessOverview.png

The server contains the following components:

  • Stunnel – a SSL tunnel which allows secure communications between user/node and the server without server components having to understand SSL.
  • A reverse proxy server – HaProxy. This directs web requests to the correct server component.
  • Web server, provided by Node.js
  • Web services, implemented using Node.js
  • SSH server, provided by dropbear
  • Client authentication – a pluggable authentication module used by the ssh server when deciding whether to accept a connection request from a Node.
  • Databases, provided by MySQL


The Node contains the following components:

  • Standard node software
  • Provider for RemoteAccess UPnP service
  • Remote access settings registry (currently combined with provider). This stores username, password, user-facing control url & node-facing web services url
  • Proxy server. This connects to the remote access server’s ssh server and listens for requests, forwarding them to the appropriate locations on the standard node web server. The proxy server uses standard .NET classes – HttpListener for the server and HttpWebRequest to forward requests.


The remote client contains the following components:

  • Any web browser supported by the Node UI.

Use cases

To aid understanding of the architecture diagram, key use cases for the system are described below.

Register new Node

  • User brings up their Node UI inside the home
  • User enters desired username & password
  • Provider for RemoteAccess service is called for SetUserName action
  • Provider calls register web service
  • Registration web service on remote access server is called (via Stunnel then HaProxy)
  • If requested username is available, registration service adds a record to the Login Database. Otherwise, it generates a list of similar usernames which are still available and returns this as part of an error.
  • Assuming registration succeeded, Username is added to remote access registry. SetUserName action returns success.
  • UI calls SetPassword action. Password is added to remote access registry and action returns success.
  • UI calls SetEnable action. Enabled state is set in remote access registry. Enabling remote access is then covered by the next use case...


Connect a registered Node

  • Happens either when SetEnable action is called or ohOs starts when remote access was previously enabled.
  • Provider for RemoteAccess service calls getaddress on Node Login service (via Stunnel then HaProxy)
  • Node Login service checks that node has been previously registered (by checking for node’s udn in Login Database). If the node is unregistered, an error is returned.
  • Node Login service calls Port Finder service to determine which port of the ssh server the node should connect to.
  • Port Finder service determines a free port. Node Login service writes node udn, ssh server address & port, plus status (pending) to the Session Database.
  • Node Login service checks config file to determine ssh server host name & port (used for connecting to the ssh server) plus the IP address to bind to for remote port forwarding. These 3 details plus the port determined above are returned to the home node.
  • Home node now has approx 1 minute to connect to the ssh server. The Node Login service periodically checks the Session Database and removes records that have been pending for longer than 1 minute.
  • Home node starts its proxy server. This is currently hard-coded to listen on port 55170.
  • Home node connects to ssh server. Server uses PAM SQL Lookup to validate ssh key used in connection request against key in Login Database. Server then changes status of node’s record in Session Database to ‘connected’.
  • Home node sets up remote port forwarding for the port its proxy server is listening on.


User connects remotely

  • User enters the url returned by the node registration process into their web browser.
  • This reaches the Login web service (via Stunnel and HaProxy).
  • The url path is the user name that was selected during registration. Login service looks this up in Login Database and redirects the request to HaProxy with the path changed to the node udn which matches the username.
  • HaProxy uses the node udn to look up ssh server address/port in the Session Database.
  • HaProxy forwards the request to the appropriate address/port on the ssh server.
  • Ssh server forwards the request to the appropriate proxy server on a home node.
  • Home node checks for the presence of a login cookie in the request. If this is missing, the request is redirected to a login page hosted by the home node.
  • When the first request completes, HaProxy sets a session cookie noting the udn for this user.
  • The user’s web browser displays the login page prompting for username and password. The results from this are sent to the home node’s proxy server which checks them against the data in its remote access registry. If the login is valid, another session cookie is set and the user is redirected to the root of the home node’s proxy server.
  • The user’s web browser issues a GET request for ‘/’. HaProxy uses its cookie to find the correct ssh server address/port. (This may come from either the session database or an in-memory cache.) The home node’s proxy server manually forwards the request to the web server home UIs are available from, applying minor rewrites (such as compression) to the response.

Deployment

Server

All configuration options are contained in the file ohremote/scripts/config.
Hosting the server on a box with 2 IP addresses is recommended. This allows both the ssh server and web services to operate on port 443. This port is used by https so is likely to be open for outbound requests on most firewalls. (An argument could be made for port 80 – as used by http. This is at least as likely to be open on firewalls but is more likely to be subject to packet inspection and blocked as our use here will appear different to traditional web access.)

Node

The location of the remote access server must be set in the remote-access-server tag of ohos.ohconfig.xml. This file is generated from ohOs/src/Host/Host.ohconfig.xml.template during a build or the generated file can be edited and ohOs restarted to apply changes.
The Node must be capable of generating a RSA format SSH key. This is currently only supported on Linux; other platforms need to manually generate the keys and move them (named key.priv & key.pub) to the remote directory in ohWidget’s store.

Monitoring

Server

Every 3 seconds, checks status of each component, restarting server if any component does not respond correctly. See ohremote/scripts/ohmonitor for details.

Node

Every 5 minutes, issues a HEAD request to the user-facing uri returned by register web service (and then stored in registry). If this fails, disconnects from ssh server, stops (local) proxy server then repeats “Connect a registered node” use case. If connection fails, it is retried at randomised (but increasing) intervals thereafter.

APIs

Server Web Services

1. To register for remote access, including selecting a username

URL:  [server_url]/register
Body:
   <register>
       <username>[Proposed username]</username>
       <uidnode>[Node’s UDN]</uidnode>
       <sshkey>[Contents of public key]</sshkey>
   </register>

Returns (success):

   <result>
       <success>[Proposed username]</success>
   </result>

Returns (failure):

   <result>
       <error>Username exists</error>
       <suggestionlist>
           <suggestion>First suggested free name</suggestion>
           <suggestion>Second suggested free name</suggestion>
           <suggestion>etc.</suggestion>
       </suggestionlist>
   </result>

2. To clear an account - (deregister interest in remote access, remove username)

URL:  [server_url]/remove
Body:
   <remove>
       <uidnode>[Node’s UDN]</uidnode>
   </remove>

Returns (success):

   <result>
       <success>[Node’s UDN]</success>
   </result>

Returns (failure):

   <result>
       <error>[Error Message]</error>
   </result>

3. To get connection details for the ssh tunnel

URL:  [server_url]/getaddress
Body:
   <getaddress>
       <uidnode>[Node’s UDN]</uidnode>
   </getaddress>

Returns (success):

   <result>
       <success>
           <sshserver>
               <address>[Ssh server host (or address)]</address>
               <port>[Ssh server port to connect to]</port>
           </sshserver>
           <portforward>
               <address>[Address for remote port forwarding]</address>
               <port>[Port for remote port forwarding]</port>
           </portforward>
       </success>
   </result>

Returns (failure):

   <result>
       <error>[Error Message]</error>
   </result>


Node web service

As with other Node features, this is available as a UPnP service - openhome-org:service:RemoteAccess:1.

State variables

  • Enabled
    true if remote access is currently enabled; false otherwise.
  • PasswordSet
    true if a password is currently set; false otherwise. (Note that the password itself cannot be queried.)
  • PublicUri
    The url used for remote access. This is set once a Node has registered for remote access. The value does not change when Enabled changes.
  • UserName
    The username selected during registration; or "" if the Node is not registered for remote access.

Actions

  • SetUserName(in uint Handle, in string UserName, out bool Succeeded, out string AlternativeNames)
    Register a Node for remote access, selecting its unique username. Arguments are:
    • Handle: Reserved for future compatability. Must be 0.
    • UserName: Proposed username.
    • Succeeded: true if UserName was available; false otherwise.
    • AlternativeNames: XML block in the same form as suggestionlist block from register web service.
  • SetPassword(int uint Handle, in string Password)
    Set a password used to authenticate remote connection requests. Arguments are:
    • Handle: Reserved for future compatability. Must be 0.
    • Password: Password. This is held locally on the Node so is guaranteed to be valid.
  • Enable(bool Enable)
    Enable remote access. This can only be called when a valid username and password are set. i.e. When the UserName state variable is non-empty and the PasswordSet state variable is true. Arguments are:
    • Enable: True if remote access should be enabled; false if it is currently enabled and should be disabled.
  • Reset(uint Handle)
    Disable remote access, remove registration with remote access server and clear local username and password.
  • ClearAuthenticatedClients()
    Force any active remote access sessions to re-authenticate.