IoT Micro-Platform HTTP Demonstrator

This demonstration is based on an early implementation of the IoT Micro-Platform infrastructure, which supports HTTP and HTTPS protocol layers for implementing RESTful APIs. The demonstration version defines a simple server resource type that provides data logging capability for arbitrary JSON object data and makes use of a simple text based console for configuration purposes. The demonstration is provided as a set of pre-compiled OSGi bundles that are shipped with the Apache Felix OSGi framework for easy setup and execution. A recent (Java 7 or later) Java SE runtime environment is required, running on a platform which has a single unique IP address. IP port number 8080 must be available for HTTP operation and port number 8443 must be available for HTTPS operation. For the purposes of this demonstration our standard test platform is a Raspberry Pi single board computer running the Oracle JVM under Raspbian Linux.

Running The Demonstration Code

The demonstration code may be found via the following link. This is a gzipped tar file which contains the Apache Felix OSGi framework and the OSGi bundles for the IoT Micro-Platform:

iot_http_demo_1_osgi_071016.tgz

After unpacking the OSGi framework archive, the IoT Micro-Platform can be started by changing to the Apache Felix framework directory and starting the OSGi framework from the command line. The complete sequence of commands is shown below:

...
> tar -xvzf iot_http_demo_1_osgi_071016.tgz
> cd felix-framework-5.4.0
> java -jar bin/felix.jar
...

The original command line console should now function as the Apache Felix OSGi shell and a separate Java console window should be created for configuring the IoT Micro-Platform demonstration server. To shut down the server at any time, the Apache Felix shell should be used to halt the OSGi system bundle (by typing 'stop 0'). All configuration settings and stored time series data is held in the local stash directory ('iot-server-demo.stash') and the server state can be reset by simply deleting the directory contents.

Configuring The Server

The demonstration server makes use of a simple Java console window, where commands should be typed into the small text entry box at the bottom of the window and the upper text area acts as the console output. There are currently two classes of commands for modifying server resources ('resource') and the associated access permissions ('access'). These will be discussed in more detail later, but the following commands may be used to quickly set up a single resource handler and associated access permissions.

access add access-scope
access set access-scope /default r
access set access-scope Example-Write-Token- m
resource add /foo/bar
resource include /foo/bar access-scope

This sequence of commands creates a new resource access scope (called 'access-scope') and configures it to allow read (GET) accesses from all clients, as well as allowing modify (POST) operations from any client which passes a matching base64url token in the HTTP headers (in this case 'Example-Write-Token-'). A new resource handler is then created in the resource hierarchy (called '/foo/bar') and the resource handler is then included in the previously defined access scope. The new configuration can be checked by typing 'access report' to report all the defined access scopes and 'resource report' to report all the defined resource handlers.

Accessing Resource Handler Data

Once a resource handler has been configured it will be possible to access two locations in the server resource tree - these being '/foo/bar/current' and '/foo/bar/history'. The first location allows the current data value to be accessed and modified, while the second location may be used to retrieve an array of previously stored values. For example, the following command will access the current resource value and output it to the Linux console:

wget --quiet --output-document - \
  'http://X.X.X.X:8080/foo/bar/current'

In the case of a newly created resource, this will return the default value which is a JSON object containing a single member named 'time'. This is a timestamp that indicates the number of milliseconds after the UNIX epoch at which the JSON object was generated. In the case of the default value the timestamp is set to zero, but for subsequently stored values it will either be the value that was explicitly specified in the stored JSON object, or a value automatically inserted by the server when the JSON object is committed to persistent storage. To demonstrate this, the following command may be used to post a new value to the resource handler:

wget --quiet --output-document - \
  --header='Content-Type: application/json' \
  --header='Rest-Access-Token: Example-Write-Token-' \
  --post-data='{ "Hello" : "World" } \
  'http://X.X.X.X:8080/foo/bar/current'

When posting new data in this manner the data format must be explicitly specified as corresponding to valid JSON. In addition, a base64url access token must be specified that confers modification (ie, HTTP POST) rights for the resource handler. In this case the posted data does not specify a data timestamp, so this will be automatically inserted by the resource handler. After updating the current value in this manner, a subsequent read access will return the following JSON data:

{
  "Hello" : "World",
  "time" : 1234567890000
}

Accessing History Data

For the demonstration server API, historical data posted to each resource handler can also be retrieved via the 'history' resource tree node. This is distinct from the 'current' tree node since it is used to access an array of data points and thus uses a different JSON representation. By default, requests for historical data will return all data items where the associated timestamp lies within the most recent 1 hour period.

Two URL query parameters may be used to modify this behaviour and select arbitrary history periods. The first query parameter is 'start', which specifies the start time for the history window as an integer number of seconds since the UNIX epoch. The second query parameter is 'window' which specifies the size of the history window as a integer number of seconds. If the 'start' parameter is used on its own then the default window period of 1 hour will be used. Similarly, if the 'window' parameter is used on its own then the history window will correspond to the most recent number of seconds specified. Both ampersand '&' and semicolon ';' query separators are supported. The following example requests the set of data samples spanning 83 seconds from a given point in time:

wget --quiet --output-document - \
  'http://X.X.X.X:8080/foo/bar/history?start=1475758620;window=83'

The effect of issuing a valid request for the history data is to return a JSON array consisting of the various values that were posted to the server over the specified time period. For example, the values posted by a temperature sensor over the specified period may be reported as follows:

[
  {
    "temperature" : "A bit chilly",
    "time" : 1475758628572
  },
  {
    "temperature" : "Brass monkeys",
    "time" : 1475758659589
  },
  {
    "temperature" : "Nice day for it",
    "time" : 1475758690607
  }
]

Enabling Support For HTTPS

Although the introductory examples given here make use of HTTP, performing these types of transactions 'in the clear' negates any benefit of introducing the token based access controls - since the token values could easily be intercepted and exploited. Therefore the recommended approach will be to use HTTPS wherever possible. The HTTP demonstrator can easily be configured to support HTTPS based operation by editing the provided Felix framework configuration file, which is found in the Felix framework directory as 'conf/config.properties'.

To enable HTTPS operation, a suitable Java key store file is required which contains a valid certificate for the server. Assuming that the Java keytool command line tool is available, a self signed certificate for the server can easily be generated using the following command and then entering the server name or IP address at the 'first or last name' prompt:

keytool -genkey -keyalg RSA -alias selfsigned \
  -keystore keystore.jks -storepass password \
  -validity 360 -keysize 2048

If the generated keystore file is then placed in the Felix framework directory, the IoT Micro-Platform demonstration code can be configured to use it as the HTTPS server certificate by adding the appropriate parameters in the properties file as follows:

com.zynaptic.demo.https_keystore_filename=keystore.jks
com.zynaptic.demo.https_keystore_password=password
com.zynaptic.demo.https_certificate_password=password

When the IoT Micro-Platform demonstrator is configured in this way it will only expose the RESTful API over a secure TLS 1.2 protocol layer on port 8443. Conventional insecure HTTP access will be disabled. Modifying the client access commands to support HTTPS operation is simply a matter of modifying the URL scheme and port number to 'https' and '8443' respectively. If a self signed certificate is being used it will also be neccessary to include the '--no-check-certificate' command line option to instruct the wget command not to check for a valid certificate authority.