From OpenHome
Contents |
ohRemote
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.
How do I get it?
Source code is available to selected partners from github. Contact info@openhome.org if you require access.
System Architecture
[diagram]
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 [link]
- 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.
Deployment
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.) 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
Server Web Services
See notes on deployment [link] for how to determine [server_url] & generate ssh keys. Note that [server_url] is set by the Node maintainer. By default it is https://login.remote.openhome.org. 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. 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> </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 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>TBD</error>
</result>
Node web service
(RemoteAccess service description)
Use cases
Register new Node
• User brings up their Node UI inside the home • User enters desired username & password • Provider for RemoteAccess server is called for SetUserName [link] action • Provider calls register[link] 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. Following steps assume 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 [link] 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, 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 forwarding. These 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
• 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 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
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 [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.