July 15, 2022 - By Justin Wilson, OCI Principal Software Engineer
Middleware News Brief (MNB) features news and technical information about Open Source middleware technologies.
- Authentication and Authorization
- RESTful Webservices Security Design
- JSON Web Tokens
- DDS Security: Authentication
- DDS Security: Authorization
- Applying Security to the Example Game
In a previous article, I compared and contrasted RESTful webservices and the data-centric publish subscribe model of DDS.
- RESTful webservices are great for ad hoc queries and RPC-styled operations.
- DDS shines in situations where data is inherently distributed and dynamic.
In this article, I continue the comparison through the lens of security by comparing the JSON Web Token (JWT) method of securing web applications to DDS Security.
Authentication and authorization are foundational concepts with respect to security.
Authentication refers to the idea that a principal or actor is who it claims to be.
With respect to authentication, there are the notions of identity and proof of that identity. Passphrases, certificates, and biometrics are examples of methods used to prove an identity. For this article, we are concerned with securing services as opposed to user applications. As such, we will limit the discussion to passphrases and certificates, as they are common methods for authentication.
Authorization refers to the idea of a principal or actor being able to perform an operation.
With respect to authorization, role-based access control (RBAC) has become very popular. A system using RBAC defines a set of roles. Associated with each role is a set of permissions that correspond to operations that are allowed in that role. A principal is assigned one or more roles. Given an authenticated principal and a requested operation, a system can look up the roles and permissions for the principal and check if the requested operation is allowed. Roles provide a convenient way of grouping permissions into reusable units. From an applications perspective, however, roles are mostly irrelevant, as the only concern is whether or not the principal has permission to execute the operation.
A RESTful webservice consists of a number of endpoints and methods (operations) on those endpoints. A privilege corresponds to the ability to perform a certain operation on a certain endpoint. At an extreme, there is one permission for each endpoint-operation combination. More typically, endpoints that are logically coupled can share permissions.
One aspect of security not addressed by RBAC is operations that are tied to the identity of the principal. For example, a user should be able to update his or her own information, but not another user's information. This type of logic must be baked into the application.
Token-based security is a popular way of securing web applications, and JWT are a popular way of implementing token-based security.
A token is simply a string used for authorization. In the context of JWT, the token is a signed JSON object. The content of the JSON object is arbitrary but typically contains information that identifies the principal, an expiration date, and a list of permissions for the principal.
Note that the roles assigned to the principal are used to create the list of permissions, but the roles themselves need not appear in the JWT.
The JWT is signed by an authority whose certificate is distributed to all applications accepting the JWT.
A JWT is returned to a principal upon successful authentication. The principal then provides the JWT when requesting an operation. An application receiving a JWT uses the certificate of the signing authority to validate the JWT. Assuming the JWT is valid and not expired, the application can check if the principal has privileges to perform the requested operation. In many cases, the design of JWTs allows a service processing a request to determine if the request is authorized without consulting another service.
There are other ways of securing web applications that make different assumptions and attempt to optimize different things. However, they are all equivalent in that they start with the identity of the principal and arrive at a list of permissions that can be used to authorize a requested operation.
In DDS Security, authentication is based on public key infrastructure (PKI). (For an introduction to DDS Security, see this article.) An application generates a key (private) and a certificate signing request (CSR). It sends the CSR to the identity certificate authority (CA). The identity CA signs the CSR to produce a certificate (public).
DDS participants using security mutually authenticate each other. Each DDS participant starts with its key, certificate, and the certificate of the identity CA. Each pair of secure participants goes through a mutual authentication process that involves exchanging certificates and validating the peer's certificate using the certificate of the identity CA.
With respect to web applications, this is directly comparable to systems that use client certificates. When a client connects with a certificate, it receives a certificate from the server and validates it using a stored list of certificate authorities. It then sends its own certificate to the server, which validates it using a stored list of certificate authorities.
In DDS Security, authorization is based on the governance file and permissions file.
The governance file is shared by all participants and describes the security policy for the DDS domain, including discovery and topics.
The permissions file identifies the principal and describes the access (writing and/or reading and for how long) the principal has to topics. The permissions file is signed by a permissions CA whose certificate is distributed to all of the DDS participant.
During discovery, DDS participants using security exchange permissions files. A received permissions file is validated using the certificate of the permissions CA. A local participant then uses the received permissions file to match its local writers and readers with authorized remote readers and writers.
A permissions file is directly comparable to a JWT. Both are signed in a way that can be validated by the receiving party. Both identify the principal and list the permissions available to the principal. Where a JWT contains permissions that allow the principal to perform modifying (write) or non-modifying (read) operations on an endpoint, the permissions file describes the topics that the principal can read or write. This follows naturally from the previous article, where endpoints in a RESTful webservice were compared to topics in a DDS domain.
Recall that web applications require security logic that uses the identity of the principal, e.g., users can change only their own passwords. The corresponding concept in DDS Security is that of instance-level security. Using the DDS Security plugin mechanism, an application can define a new Access Control plugin that checks instance-related operations, including a local or remote participant's ability to register and dispose instances. These pertain only to writing operations; there is no way to say that a reader cannot access a particular instance. (Applications where this is an issue are most likely performing ad hoc queries where a RESTful webservice would excel.)
Partitions are another way to restrict access to specific instances within a topic. A partition is a label associated with a reader/writer, and a reader/writer may have multiple partitions or a wildcard. A reader and a writer must have a pair of partitions that match to associate. The permissions file contains a list of partitions that a reader/writer may use. The corresponding concept in RESTful web services is multi-tenancy, where services are deployed for each tenant. Some services will have access only to records for a particular tenant, while other services will have access to all records.
In the previous article, I applied the REST-to-DCPS-translation to a hypothetical game server. In this section, we will translate from JWT-based security to DDS security.
In the REST version of the game, there is a service for recording player connections.
- A player connection is a JSON object consisting of a guid, player id, timestamp, and server id.
- The connection service has an endpoint that allows the game servers to GET, POST, PUT, PATCH, and DELETE these records. The connection service also allows GETs from authorized clients.
- At a high level, there is a
CONNECTION_EDITORrole, which is assigned to the game servers and a
CONNECTION_VIEWERrole that is assigned to other clients that need to use the connection service.
- In terms of permissions, the
CONNECTION_EDITORrole has two permissions,
CONNECTION.READ, while the
CONNECTION_VIEWERrole has only the
In the DDS/DCPS implementation of the game, the game servers are allowed to read and write the Player Connection topic. Other authorized participants may read the Player Connection topic.
To realize this design, the governance file must specify the policy for the Player Connection topic. Here is an example governance file that enables read-access control and write-access control for the Player Connection topic:
<?xml version="1.0" encoding="UTF-8"?> <dds xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../schema/omg_shared_ca_governance.xsd"> <domain_access_rules> <domain_rule> <domains> <id>0</id> </domains> <allow_unauthenticated_participants>FALSE</allow_unauthenticated_participants> <enable_join_access_control>TRUE</enable_join_access_control> <discovery_protection_kind>NONE</discovery_protection_kind> <liveliness_protection_kind>NONE</liveliness_protection_kind> <rtps_protection_kind>ENCRYPT</rtps_protection_kind> <topic_access_rules> <topic_rule> <topic_expression>Player Connection</topic_expression> <enable_discovery_protection>FALSE</enable_discovery_protection> <enable_liveliness_protection>FALSE</enable_liveliness_protection> <enable_read_access_control>TRUE</enable_read_access_control> <enable_write_access_control>TRUE</enable_write_access_control> <metadata_protection_kind>NONE</metadata_protection_kind> <data_protection_kind>NONE</data_protection_kind> </topic_rule> </topic_access_rules> </domain_rule> </domain_access_rules> </dds>
The permissions file for a game server must grant the game server the ability to read and write the Player Connection topic:
<?xml version="1.0" encoding="utf-8"?> <dds xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://www.omg.org/spec/DDS-SECURITY/20160303/omg_shared_ca_permissions.xsd"> <permissions> <grant name="GameServerPlayerConnection"> <subject_name>/CN=gameserver</subject_name> <validity> <not_before>2022-01-01T00:00:00.000Z</not_before> <not_after>2023-01-01T00:00:00.000Z</not_after> </validity> <allow_rule> <domains> <id>0</id> </domains> <publish> <topics> <topic>Player Connection</topic> </topics> </publish> <subscribe> <topics> <topic>Player Connection</topic> </topics> </subscribe> </allow_rule> <default>DENY</default> </grant> </permissions> </dds>
The example permission file limits the time period that the permissions are valid. It also has a default rule that denies access.
The permissions file for a participant that should only be able to read the Player Connection topic would look similar but not have the publish rule:
<?xml version="1.0" encoding="utf-8"?> <dds xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://www.omg.org/spec/DDS-SECURITY/20160303/omg_shared_ca_permissions.xsd"> <permissions> <grant name="PlayerConnectionReader"> <subject_name>/CN=reader</subject_name> <validity> <not_before>2022-01-01T00:00:00.000Z</not_before> <not_after>2023-01-01T00:00:00.000Z</not_after> </validity> <allow_rule> <domains> <id>0</id> </domains> <subscribe> <topics> <topic>Player Connection</topic> </topics> </subscribe> </allow_rule> <default>DENY</default> </grant> </permissions> </dds>
As explored in the previous article, RESTful web services and DDS applications are both similar to databases in their organization, as they allow applications to create, read, update, and delete records. This similarity extends to security.
Web applications and DDS applications are built on the fundamental security concepts of authentication and authorization. Web applications that use client certificates for authentication are directly comparable to DDS applications that use certificates for mutual authentication. Authorization in web applications is based on the idea that a principal has a set of privileges that allow them to request operations. In DDS, this translates to operations on a topic. Security is applied to topics using the shared governance file, and the read/write access of each participant is controlled by their permissions file.