Skip to content

uSpace Gateway

Carsten Stocklöw edited this page Apr 28, 2018 · 8 revisions

Table of Contents

Description

Also known as the Multi-Tenant Gateway (MTGW), this software artifact provides the needed level of connectivity and exchange of functionality and data between multiple uSpaces. The The uSpace Gateway (henceforth uSG) functionality is extended with the multi-tenant feature supporting two modes of operation:

  • Client (Tenant) side: The client uSG deployed in a "tenant" (e.g. house, apartment) represents the local uSpace, and its role is to receive messages (context, service) from the uSG server side and to forward them to the local context and service bus. Moreover, the uSG client side forwards messages (context, service) from nodes in the local space to the uSG server side.
  • Server side: The server side uSG manages multiple uSG clients (Tenants). The server side receives messages from the uSG client side, and it can send messages to a specific uSG client side, a set of them, all or none.
Figure below reports an example of a possible configuration of the uSG with the multi-tenant feature

Bundles

Artefact: uSpace Gateway
Maven artefact org.universAAL.remote / ri.gateway.multitenant
Pax Composite bundle scan-composite:mvn:org.universAAL.remote/ri.gateway.multitenant/x.y.0/composite
Karaf Feature uAAL-RI.Gateway.Multitenant
Maven Site https://universaal.github.io/remote/ri.gateway.multitenant/index.html

Features

The uSG with multi-tenant feature provides the following features:

  • ServiceCallers from one uSpace are able to invoke ServiceCallees from another uSpace;
  • ContextSubscribers from one uSpace are able to receive ContextEvents from another uSpace;
  • Solution the least intrusive as possible, it means that almost no changes are made to existing code of application which want to use members of another uSpace;
  • It is possible to specify security constraints regarding which ServiceCallees/ContextPublisher are accessible from remote uSpaces, as well as the specific message interchanged.
  • Process of exporting and importing BusMembers from uSpaces is done automatically by the uSG wihtout any other developer activity.
  • the uSG server side manages the connections with multiple uSG clients deployed in different locations (also names tenants)
  • the uSG server assigns a session ID to every connected uSG client, the clients can resume an existing session or create a new session
  • the uSG server routes messages towards the specific uSG client
  • the uSG clients forwards the messages coming from all the nodes in the same uSpace towards the uSG server. Currently only the context and service bus messages and sent/received to/from the uSG server/uSG client
  • Tenant Manager for inspecting programmatically multiple uSG client sides
  • Each instance is capable of running multiple servers and clients, allowing for cloud to cloud connections, as well as different configuration (i.e., security constrains) connections.
  • Capability to cache messages before connecting, and after first connection, for connection robustness in unreliable networks.
  • Configurable security channels, including custom cypering as well as SSL encryption.

Installation

The uSpace Gateway does not require any additional installations other than the universAAL middleware and itself.

  • ...Middleware bundles...
  • org.universAAL.remote/ri.gateway.multitenant/x.y.z
Another way to include the uSG is to use the uSpace Gateway Karaf feature (uAAL-RI.Gateway.Multitenant) from the Remote Interoperability features.

Configuration

The component can load several gateway instances, one for each .properties file found inside the folder {config folder}\ri.gateway.multitenant (config folder is usually /etc in Karaf). The properties file must look as follows:onnection-mode={SERVER|CLIENT}

 remote-gateway-host={IP or HOSTNAME}
 socket-port={TCP port number}
 security-definition-file={absolute file path}
 cipher.class={Class name of cipher protocol to use}
 timeout={Time expressed in miliseconds, default 5000}
 pre-connection-cache={true,false, default:false}
 cache-max-size={number of messages to be cached, negative means infinite, default: -1}
 server-threads={number of server threads dealing with connections; default:1}
 export-attempts={number of export attempts, negative means infinite, default:3}

Where:

  • connection-mode: Specifies if the uSG instance can be either a client or server. Specifying if the instance is to connect to a server, or be the server respectively.
  • remote-gateway-host: in case the instance is running in SERVER mode, this property specifies the IP or the hostname* to use for binding the TCP server socket (if left blank server will bind to all interfaces by default). If the instance is running in CLIENT mode, this property will be used to address the server (provided a SERVER uSG instance is reachable through this address, and port; you may need to configure the network firewall).
  • socket-port: Specifies the TCP port that used for accepting connection (when running in server mode) or connecting to (when running in client mode)
  • security-definition-file: The absolute path (e.g. file:///C:/Users/.../ri.gateway.multitenant/AcceptALL.ttl) to a Turtle (ttl) file** defining the security permissions. See Security section below. Not setting this property (or if the file is not found) will block all communications.
  • cipher.class: This is used to select the cyphering protocols, each will have further configuration; see below for configuration of each of the available ciphers. We recommend using SSL.
There is also the possiblity to provide your own channel encryption by creating a bundle fragment with a class implementing the org.universAAL.ri.gateway.communication.cipher.SocketCipher interface, and providing that class name as the configuration value.
  • timeout: Time after which without connection, a timeout will be issued, specially useful for determining how long service calls should be buffered in unreliable networks.
  • pre-connection-cache: This switch will enable cache before connection to peer, meaning proxies will be created before the actual connection, and they will start caching messages, when the connection is stablished all cached messages will be bursted to the peer. This may be problematic with servers and it should be configured with care in conjunction with cache-max-size to optimize memory usage and network resources.
  • cache-max-size: Configure the message queue length, handle with care as this might be very memory consuming, specially in scenarios where connection is delayed for long period of time and or when there is a high throughput of messages (context events and or service requests).
  • server-threads: Set the number of server threads attending connections, this could improve performance in multi thread systems.
  • export-attempts: Number of attempts to try to export proxies to the remote peer, after this number of uncessful attempts exporting will be aborted. This might be useful for configuring unreliable networks with low profile hardware.
* If you want to test a GW server and a client in the same machine, you should set the server host as "localhost" and the client as the loopback address "127.0.0.1" or else it may not work. In addition, you should set the following configuration parameters in /etc/system.properties in order to disable universAAL peer discovery mechanism (overwrite any other existing values for these conf params):
 net.slp.port=5555             # any value, but different port numbers for server and client
 net.slp.interfaces=127.0.0.1  # only this value
 jgroups.bind_addr=127.0.0.1   # only this value

** After version 3.3.1-SNAPSHOT this property can be set to the keyword none to disable the security definition permissions, allowing any communication authorized by other methods.

Security restrictions

Defining security restrictions in a turtle file allows for more granularity in the security restrictions, while being able to recycle the file for different connections. It must point to an absolute path of a security configuration file. This file must be in Turtle format (.ttl extension). Its content is a RDF representation of the security restrictions. You can see it better with the following example:

 @prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
 @prefix : <http://ontology.universAAL.org/Gateway.owl#> .
 _:BN000000  :exportPolicy "Whitelist"^^xsd:string ;
   :exportMatches [
 a <http://ontology.universAAL.org/Context.owl#ContextEventPattern>
 ] ;
   :importPolicy "Whitelist"^^xsd:string ;
   :importMatches [
 a <http://ontology.universAAL.org/Context.owl#ContextEventPattern>
 ] ;
   :inboundPolicy "Whitelist"^^xsd:string ;
   :inboundMatches [
 a <http://ontology.universAAL.org/Context.owl#ContextEvent>
 ] ;
   :outboundPolicy "Whitelist"^^xsd:string ;
   :outboundMatches [
 a <http://ontology.universAAL.org/Context.owl#ContextEvent>
 ] .

It is basically a Blank Node with 4 (Policy) + 4 (Matches) properties:

  • exportPolicy, importPolicy, inboundPolicy and outboundPolicy: Must have a String value of either "Whitelist" or "Blacklist". They define whether to allow or deny, respectively, the elements described "Matches" properties. The "export" and "import" policies are for receiver elements (Context Patterns and Service Profiles) and the "inbound" and "outbound" policies are for sender elements (Context Events and Service Requests).
  • exportMatches, importMatches, inboundMatches and outboundMatches: Must contain an ontological description against which each interaction through the gateway will be matched. That is, if an element that has to be "imported/exported" or sent "inbound/outbound" matches the description in the respective property, it will be treated as described in the "Policy" property (blocked if "Blacklist", allowed if "Whitelist").
The example shown above would always allow to export local Context Subscribers and import external Context Subscribers, and allow incoming and outgoing ContextEvents. You can find other examples that allow or deny everything here (but take into account that there is currently a bug in version 3.3.0 that does not allow these last 2 examples).

org.universAAL.ri.gateway.communication.cipher.LegacyBlowfishCipher

A SocketCipher whihc is compatible with previous versions of the gateway.

  • hash-key: pre-shared key to encrypt the communication, it should be the same for client and server.

org.universAAL.ri.gateway.communication.cipher.SSLCipher

A SocketCipher which implements SSL encryption. see standard Java SSLSocket usage and configuration for details.

  • javax.net.ssl.keyStore:
  • javax.net.ssl.keyStorePassword:
  • javax.net.ssl.trustStore:
  • javax.net.ssl.trustStorePassword

org.universAAL.ri.gateway.communication.cipher.StreamCipher

A SocketCipher that uses a generic implementation of CipherOutputStream and CipherInputStream.

  • cipher.algorithm:
  • cipher.key:
  • cipher.key.algorithm:

org.universAAL.ri.gateway.communication.cipher.ClearTextCipher

This SocketCipher will NOT cipher your communications, thus it should only be used in controlled environments or for seting purposes.

It has no further configuration.

Tenant-aware applications

The multi-tenancy support is a feature of the middleware, however, it cannot come into play unless in conjunction with the uSpace Gateway (or the R-API, but that's another story). It has been remarked that the uSpace Gateway deployed in a server side can deliver communication to an arbitrary set of tenants. But it is actually the applications running in the server side uSpace the ones that decide which tenant they want to communicate with.

The API that enables this is provided by the middleware. Each tenant is identified with a "Scope" (i.e. Scope = Tenant ID). When sending messages (events or requests), applications can set the scopes they want to communicate to. By default, if no scope is set, it will be forwarded to all tenants. Setting one or more scopes will forward to those tenants. And setting a specific tenant (ScopedResource.ONLY_LOCAL_SCOPE) will keep the message within the server uSpace only. Take into account that applications running in the client side also have access to this API, but the scopes will be overwritten by the uSG, so they are useless there. The following code example is for ContextEvent but is applicable to ServiceRequest as well:

 ContextEvent event=new ContextEvent(...);
 // This sets the event to be only local, not sent to tenants
 event.addScope(ScopedResource.ONLY_LOCAL_SCOPE);
 // Remove all scopes set so far (this would send to all tenants)
 event.clearScopes();
 // Add one or more explicit destination scopes
 event.addScope(destinationScope1);
 event.addScope(destinationScope2);

The other half of the feature is receiving events or calls from tenant applications to a server application. In this case you can find out which tenant sent this message. Again, the following code is for a ContextEvent received in a Context subscriber, but is also available in a ServiceCall received by a Service callee.

 // Check if it contains scopes
 boolean scoped=event.isScoped();
 // Get the list of all the scopes of an event
 List<String> scopes = event.getScopes();
 // Check if it would be delivered to a tenant
 // (not the same as containing that scope)
 boolean willsend=event.isSerializableTo(destinationScope1)

Note that the presence of a scope in an event/request doesn't necessarily mean it will be transferred there. To find out, use the method isSerializableTo(), whose javadoc states:

Check whether if this ScopedResource may be sent to a destination scope

  • Deny if the origin is the destination candidate (this will cause message loops)
  • Deny if the destinations do contain ScopedResource.ONLY_LOCAL_SCOPE (tenant-aware application has decided this message is only local)
  • Allow if the destinations are empty (non-tenant-aware application has generated the message / no tenant restrictions)
  • Deny if the destinations are not empty and do not contain the candidate destination
  • Allow if the destinations are not empty and contain the candidate destination.