.. include:: vars.rst

.. _section-sec-HO3:

Hands-On 3: Defining the DomainParticipant Permissions
======================================================

In this Hands-On, we will specify what the |DPs| in your
project will be allowed to do within your secure system. We will achieve
this by writing a |PermissionsDoc| for each of your participants.

Going back to our example, Alice will only have permission to publish the
*PatientMonitoring* data, while Bob will be restricted to subscribe to
patient-related |TOPICs|. We will associate each |PermissionsDoc| with its
corresponding participant based on their identities, limiting the system
damage if one of your applications becomes compromised. To put the
|PermissionsDocs| into effect, we will sign them with the provided Permissions
CA. Finally, we will modify your secure participants' QoS profiles to point to
the new |PermissionsDocs| and see how the new permissions are applied.

.. note::

   We will use the **OpenSSL CLI** to perform the security operations in the
   generation of the security artifacts. Make sure to include in the path your
   OpenSSL binary directory [#openssl_lm_path]_. The installation process is
   described in the |SP_IG_LINK|.

   Note that the |RTI_SP_PRODUCT| do not depend on OpenSSL to generate these artifacts; you
   can use the security toolkit of your choice. With that said, we recommend
   using |OpenSSL| to make sure that the certificates are in the right format.

.. _section-sec-HO3-granting-permissions-your-secure-participants:

Granting Permissions to Your Secure Participants
------------------------------------------------

As the DDS Security expert at Patient Monitoring Innovations (PMI), you are
going to specify the permissions of every |DP| in your system.
You will define what |TOPICs| your publisher, Alice, can read/write by
associating rules with the subject in her |IdentityCert|.

Create a file called :file:`pmiPermissionsAlice.xml` in the :file:`xml`
directory (along with the rest of XML files) and add the following content:

.. literalinclude:: snippets/pmiPermissionsAlice.xml
   :language: xml
   :caption: Sample |PermissionsDoc| configuring a single grant for *ParticipantAlice*

This |PermissionsDoc| configures a grant for *ParticipantAlice*, identified
by its |IdentityCert| (1). We will define the grant's subject name to
make it apply to your publisher in
:ref:`section-sec-HO3-binding-permissions-file`. The validity of this grant
is restricted in time (2). This grant has a single allow rule (3), so
*ParticipantAlice* will only be allowed to:

* Join |DOMAIN| *1*
* Publish the |TOPIC| "Example PatientMonitoring" — only in |DOMAIN| *1*

*ParticipantAlice* will be denied attempts to perform any other action (4).

In addition to configuring *allow* rules, we can specify *deny* rules with
the opposite effect. For details, see the
:link_connext_dds_secure_um:`Permissions Document
<p2_core/access_control.html#permissions-document>` in the |SP_UM|.

.. note::
   |PermissionsDocs| are always exchanged during authentication.
   The larger a |PermissionsDoc| is, the more network overhead it will
   cause. As such, we recommend that you keep separate |PermissionsDocs| per
   identity (i.e., per |DP|). For further details, see :link_connext_dds_secure_um:`Choosing
   the Granularity of Your Permissions Documents for DomainParticipants
   <p3_advanced/best_practices.html#choosing-the-granularity-of-your-permissions-files-for-domainparticipants>`
   in the |SP_UM|.

.. _section-sec-HO3-binding-permissions-file:

Binding the Permissions Document to Your DomainParticipants
-----------------------------------------------------------

When a |DP| loads a |PermissionsDoc|, it looks for a grant
with a :xmltag:`subject_name` matching its identity. In other words, the
:xmltag:`subject_name` identifies the |DP| to which the grant's
permissions apply. The contents of the :xmltag:`subject_name` tag should be
the X.509 subject name for the |DP|, as given in the
**Subject** field of its |IdentityCert|.

If you followed the steps in :ref:`section-sec-HO1`, Alice's |IdentityCert|
should be :file:`cert/ecdsa01/identities/ecdsa01Peer01Cert.pem`. The subject
of Alice's certificate does not match the :xmltag:`subject_name` section in
grant *ParticipantAlice*. We will modify :file:`pmiPermissionsAlice.xml` to make
this grant apply to Alice.

#. Check the information from Alice's |IdentityCert|
   (:file:`ecdsa01Peer01Cert.pem`) with the following command:

   .. tabs::

      .. group-tab:: Linux

         .. code-block:: console
            :emphasize-lines: 12

            $ openssl x509 -in cert/ecdsa01/identities/ecdsa01Peer01Cert.pem -text -noout
            Certificate:
                Data:
                    Version: 3 (0x2)
                    Serial Number:
                        7b:ba:b9:c9:2c:be:ee:b9:71:d0:62:4e:59:6b:de:89:3a:33:5c:ad
                Signature Algorithm: ecdsa-with-SHA256
                    Issuer: C=US, ST=CA, L=Santa Clara, O=Real Time Innovations, CN=RTI ECDSA01 (p256) ROOT CA, emailAddress=ecdsa01RootCa@rti.com
                    Validity
                        Not Before: Jan 28 21:26:58 2021 GMT
                        Not After : Jan 27 21:26:58 2026 GMT
                    Subject: C=US, ST=CA, O=Real Time Innovations, emailAddress=ecdsa01Peer01@rti.com, CN=RTI ECDSA01 (p256) PEER01
                    Subject Public Key Info:
                    ...

      .. group-tab:: macOS

         .. code-block:: console
            :emphasize-lines: 12

            $ openssl x509 -in cert/ecdsa01/identities/ecdsa01Peer01Cert.pem -text -noout
            Certificate:
                Data:
                    Version: 3 (0x2)
                    Serial Number:
                        7b:ba:b9:c9:2c:be:ee:b9:71:d0:62:4e:59:6b:de:89:3a:33:5c:ad
                Signature Algorithm: ecdsa-with-SHA256
                    Issuer: C=US, ST=CA, L=Santa Clara, O=Real Time Innovations, CN=RTI ECDSA01 (p256) ROOT CA, emailAddress=ecdsa01RootCa@rti.com
                    Validity
                        Not Before: Jan 28 21:26:58 2021 GMT
                        Not After : Jan 27 21:26:58 2026 GMT
                    Subject: C=US, ST=CA, O=Real Time Innovations, emailAddress=ecdsa01Peer01@rti.com, CN=RTI ECDSA01 (p256) PEER01
                    Subject Public Key Info:
                    ...

      .. group-tab:: Windows

         .. code-block:: doscon
            :emphasize-lines: 12

            > openssl x509 -in cert\ecdsa01\identities\ecdsa01Peer01Cert.pem -text -noout
            Certificate:
                Data:
                    Version: 3 (0x2)
                    Serial Number:
                        7b:ba:b9:c9:2c:be:ee:b9:71:d0:62:4e:59:6b:de:89:3a:33:5c:ad
                Signature Algorithm: ecdsa-with-SHA256
                    Issuer: C=US, ST=CA, L=Santa Clara, O=Real Time Innovations, CN=RTI ECDSA01 (p256) ROOT CA, emailAddress=ecdsa01RootCa@rti.com
                    Validity
                        Not Before: Jan 28 21:26:58 2021 GMT
                        Not After : Jan 27 21:26:58 2026 GMT
                    Subject: C=US, ST=CA, O=Real Time Innovations, emailAddress=ecdsa01Peer01@rti.com, CN=RTI ECDSA01 (p256) PEER01
                    Subject Public Key Info:
                    ...

#. Replace the :xmltag:`subject_name` in the |PermissionsDoc|
   (:file:`pmiPermissionsAlice.xml`) with the **Subject** field of the
   |IdentityCert| (:file:`ecdsa01Peer01Cert.pem`). |br| |br|

#. You may also want to update the :xmltag:`validity` tag with the information
   from the |IdentityCert|. Note that you are not required to have the
   same validity dates in the |PermissionsDoc| and the |IdentityCert|
   (upon creation, your |DP| will independently verify that the
   |IdentityCert| and the grant in your |PermissionsDoc| are valid for the
   current date). If you decide to update the :xmltag:`validity` tag, pay
   attention to the date/time format.

This is the result of updating Alice's grant in :file:`pmiPermissionsAlice.xml`:

   .. code-block:: xml
      :emphasize-lines: 6

      ...
      <!-- Grants for a specific DomainParticipant will be grouped under this tag -->
      <grant name="ParticipantAlice">
          <!-- 1. The rules below will apply to the DomainParticipant
           whose identity certificate contains this subject name -->
          <subject_name>C=US, ST=CA, O=Real Time Innovations, emailAddress=ecdsa01Peer01@rti.com, CN=RTI ECDSA01 (p256) PEER01</subject_name>
          <!-- 2. Validity dates for this grant -->
          <validity>
          <!-- Format is CCYY-MM-DDThh:mm:ss[Z|(+|-)hh:mm] in GMT -->
              <not_before>2019-11-15T20:24:34</not_before>
              <not_after>2024-11-13T20:24:34</not_after>
          </validity>
          ...


.. _section-sec-HO3-signing-permissions-files:

Signing the Permissions Documents
---------------------------------

We will use the provided Permissions CA's certificate and key to sign
the |PermissionsDocs| that we composed. [#]_

Run the command below to create the signed |PermissionsDoc|
(with PKCS#7 format) named :file:`xml/signed/signed_pmiPermissionsAlice.p7s`:

.. tabs::

   .. group-tab:: Linux

      .. code-block:: console

         $ openssl cms -sign -in xml/pmiPermissionsAlice.xml -text -out xml/signed/signed_pmiPermissionsAlice.p7s -signer cert/ecdsa01/ca/ecdsa01RootCaCert.pem -inkey cert/ecdsa01/ca/private/ecdsa01RootCaKey.pem

   .. group-tab:: macOS

      .. code-block:: console

         $ openssl cms -sign -in xml/pmiPermissionsAlice.xml -text -out xml/signed/signed_pmiPermissionsAlice.p7s -signer cert/ecdsa01/ca/ecdsa01RootCaCert.pem -inkey cert/ecdsa01/ca/private/ecdsa01RootCaKey.pem

   .. group-tab:: Windows

      .. code-block:: doscon

         > openssl cms -sign -in xml\pmiPermissionsAlice.xml -text -out xml\signed\signed_pmiPermissionsAlice.p7s -signer cert\ecdsa01\ca\ecdsa01RootCaCert.pem -inkey cert\ecdsa01\ca\private\ecdsa01RootCaKey.pem

.. [#] In this example, we have control of the Permissions CA.
   This is not always the case, and we may be required to send
   the |PermissionsDoc| to an external entity to get it signed.

.. _section-sec-HO3-updating-qos-profiles-your-project: 

Updating the QoS Profiles in Your Project
-----------------------------------------

Update :file:`USER_QOS_PROFILES.xml` so that your
|DPs| will load the new |PermissionsDoc|:

.. code-block:: xml

   <qos_profile name="Alice" base_name="BuiltinQosLib::Generic.Security" is_default_qos="true">
       <domain_participant_qos>
           <property>
               <value>
                   ...
                   <element>
                       <name>dds.sec.access.permissions</name>
                       <value>file:./xml/signed/signed_pmiPermissionsAlice.p7s</value>
                   </element>
                   ...

Here again, the ``file:`` prefix means that the signed |PermissionsDoc|
will be loaded from the specified path in the file system. Note that the
path is relative to the working directory from which you run your
application (unless you specify an absolute path). For more details, see
:link_connext_dds_secure_um:`DDS Security Properties for Configuring Access Control
<p2_core/access_control.html#properties-for-configuring-access-control>` in the |SP_UM|.

.. _section-sec-HO3-checking-that-new-permissions-applied:

Checking that the New Permissions Are Applied
---------------------------------------------

To verify that Alice is correctly loading her new permissions, we will
do two tests. First, we will check that communication only works in
|DOMAIN| *1*, as specified in the |PermissionsDoc|. Then we will make sure
that Alice is only allowed to publish data.

Communication Only Works in Domain 1
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

#. Run your publisher and subscriber as explained in
   :ref:`section-sec-HO1-running-applications`.

   Do not provide any arguments to the applications, so that they will
   try to communicate in |DOMAIN| *0*.

   If the publisher has loaded the new permissions, communication should
   not occur.

   .. only:: cpp98

      .. tabs::

         .. group-tab:: Linux

            Publisher:

            .. literalinclude:: snippets/snippets.py
               :language: console
               :start-after: snippet_console_publisher_cpp98_no_rule_found
               :end-before: """

            Subscriber:

            .. literalinclude:: snippets/snippets.py
               :language: console
               :start-after: snippet_console_subscriber_cpp98_waiting
               :end-before: """

         .. group-tab:: macOS

            Publisher:

            .. literalinclude:: snippets/snippets.py
               :language: console
               :start-after: snippet_console_publisher_cpp98_no_rule_found
               :end-before: """

            Subscriber:

            .. literalinclude:: snippets/snippets.py
               :language: console
               :start-after: snippet_console_subscriber_cpp98_waiting
               :end-before: """

         .. group-tab:: Windows

            Publisher:

            .. literalinclude:: snippets/snippets.py
               :language: doscon
               :start-after: snippet_doscon_publisher_cpp98_no_rule_found
               :end-before: """

            Subscriber:

            .. literalinclude:: snippets/snippets.py
               :language: doscon
               :start-after: snippet_doscon_subscriber_cpp98_waiting
               :end-before: """

   .. only:: cpp11

      .. tabs::

         .. group-tab:: Linux

            Publisher:

            .. literalinclude:: snippets/snippets.py
               :language: console
               :start-after: snippet_console_publisher_cpp11_no_rule_found
               :end-before: """

            Subscriber:

            .. literalinclude:: snippets/snippets.py
               :language: console
               :start-after: snippet_console_subscriber_cpp11_waiting
               :end-before: """

         .. group-tab:: macOS

            Publisher:

            .. literalinclude:: snippets/snippets.py
               :language: console
               :start-after: snippet_console_publisher_cpp11_no_rule_found
               :end-before: """

            Subscriber:

            .. literalinclude:: snippets/snippets.py
               :language: console
               :start-after: snippet_console_subscriber_cpp11_waiting
               :end-before: """

         .. group-tab:: Windows

            Publisher:

            .. literalinclude:: snippets/snippets.py
               :language: doscon
               :start-after: snippet_doscon_publisher_cpp11_no_rule_found
               :end-before: """

            Subscriber:

            .. literalinclude:: snippets/snippets.py
               :language: doscon
               :start-after: snippet_doscon_subscriber_cpp11_waiting
               :end-before: """


#. Run your publisher and subscriber using |DOMAIN| *1* (specified with the
   :command:`-d` option in the command line).

   Now communication should succeed.

   .. only:: cpp98

      .. tabs::

         .. group-tab:: Linux

            Publisher:

            .. literalinclude:: snippets/snippets.py
               :language: console
               :start-after: snippet_console_publisher_cpp98_d1_ok
               :end-before: """

            Subscriber:

            .. literalinclude:: snippets/snippets.py
               :language: console
               :start-after: snippet_console_subscriber_cpp98_d1_ok
               :end-before: """

         .. group-tab:: macOS

            Publisher:

            .. literalinclude:: snippets/snippets.py
               :language: console
               :start-after: snippet_console_publisher_cpp98_d1_ok
               :end-before: """

            Subscriber:

            .. literalinclude:: snippets/snippets.py
               :language: console
               :start-after: snippet_console_subscriber_cpp98_d1_ok
               :end-before: """

         .. group-tab:: Windows

            Publisher:

            .. literalinclude:: snippets/snippets.py
               :language: doscon
               :start-after: snippet_doscon_publisher_cpp98_d1_ok
               :end-before: """

            Subscriber:

            .. literalinclude:: snippets/snippets.py
               :language: doscon
               :start-after: snippet_doscon_subscriber_cpp98_d1_ok
               :end-before: """

   .. only:: cpp11

      .. tabs::

         .. group-tab:: Linux

            Publisher:

            .. literalinclude:: snippets/snippets.py
               :language: console
               :start-after: snippet_console_publisher_cpp11_d1_ok
               :end-before: """

            Subscriber:

            .. literalinclude:: snippets/snippets.py
               :language: console
               :start-after: snippet_console_subscriber_cpp11_d1_ok
               :end-before: """

         .. group-tab:: macOS

            Publisher:

            .. literalinclude:: snippets/snippets.py
               :language: console
               :start-after: snippet_console_publisher_cpp11_d1_ok
               :end-before: """

            Subscriber:

            .. literalinclude:: snippets/snippets.py
               :language: console
               :start-after: snippet_console_subscriber_cpp11_d1_ok
               :end-before: """

         .. group-tab:: Windows

            Publisher:

            .. literalinclude:: snippets/snippets.py
               :language: doscon
               :start-after: snippet_doscon_publisher_cpp11_d1_ok
               :end-before: """

            Subscriber:

            .. literalinclude:: snippets/snippets.py
               :language: doscon
               :start-after: snippet_doscon_subscriber_cpp11_d1_ok
               :end-before: """


Alice Is Only Allowed to Publish Data
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

We will now verify that a subscriber application with Alice's
permissions is not able to receive data. This means that even if
Alice becomes compromised, she can't listen for data she is not
authorized to access.

#. Temporarily change your subscriber's QoS profile to load the same
   security artifacts as Alice, including her identity and permissions:

   .. code-block:: xml
 
      <qos_profile name="Bob" base_name="Alice">
      </qos_profile>

   This means we are now configuring Bob with Alice's permissions. |br| |br|

#. Run your publisher and subscriber using |DOMAIN| *1*.

   Communication should not occur:

   .. only:: cpp98

      .. tabs::

         .. group-tab:: Linux

            Publisher:

            .. literalinclude:: snippets/snippets.py
               :language: console
               :start-after: snippet_console_publisher_cpp98_d1_ok
               :end-before: """

            Subscriber:

            .. literalinclude:: snippets/snippets.py
               :language: console
               :start-after: snippet_console_subscriber_cpp98_d1_no_rule_found
               :end-before: """

         .. group-tab:: macOS

            Publisher:

            .. literalinclude:: snippets/snippets.py
               :language: console
               :start-after: snippet_console_publisher_cpp98_d1_ok
               :end-before: """

            Subscriber:

            .. literalinclude:: snippets/snippets.py
               :language: console
               :start-after: snippet_console_subscriber_cpp98_d1_no_rule_found
               :end-before: """

         .. group-tab:: Windows

            Publisher:

            .. literalinclude:: snippets/snippets.py
               :language: doscon
               :start-after: snippet_doscon_publisher_cpp98_d1_ok
               :end-before: """

            Subscriber:

            .. literalinclude:: snippets/snippets.py
               :language: doscon
               :start-after: snippet_doscon_subscriber_cpp98_d1_no_rule_found
               :end-before: """

   .. only:: cpp11

      .. tabs::

         .. group-tab:: Linux

            Publisher:

            .. literalinclude:: snippets/snippets.py
               :language: console
               :start-after: snippet_console_publisher_cpp11_d1_ok
               :end-before: """

            Subscriber:

            .. literalinclude:: snippets/snippets.py
               :language: console
               :start-after: snippet_console_subscriber_cpp11_d1_no_rule_found
               :end-before: """

         .. group-tab:: macOS

            Publisher:

            .. literalinclude:: snippets/snippets.py
               :language: console
               :start-after: snippet_console_publisher_cpp11_d1_ok
               :end-before: """

            Subscriber:

            .. literalinclude:: snippets/snippets.py
               :language: console
               :start-after: snippet_console_subscriber_cpp11_d1_no_rule_found
               :end-before: """

         .. group-tab:: Windows

            Publisher:

            .. literalinclude:: snippets/snippets.py
               :language: doscon
               :start-after: snippet_console_publisher_cpp11_d1_ok
               :end-before: """

            Subscriber:

            .. literalinclude:: snippets/snippets.py
               :language: doscon
               :start-after: snippet_doscon_subscriber_cpp11_d1_no_rule_found
               :end-before: """


This test requires your |GovernanceDoc| to set
:xmltag:`enable_read_access_control` to :xmlval:`TRUE`
(see :ref:`section-sec-HO2-further-exercises` in Hands-On 2);
otherwise, endpoint-level permissions related to |DRs| will not be checked and
Bob will be able to receive the data.
When adding new rules to your |GovernanceDoc|, keep in mind (as we mentioned
in :ref:`section-adding-topic-rule-PatientMonitoring`) that the |GovernanceDoc|
is processed from top to bottom, and that only the first matching rule is
applied.
Also, make sure the Permissions CA signs the modified |GovernanceDoc| (see
:ref:`section-sec-HO2-signing-governance-file`); otherwise the changes will not
be applied.

This exercise illustrates what happens if an application tries to do
something it does not have permissions to do, by temporarily giving Bob
(the subscriber) the wrong permissions.

.. tip::

   Make sure you revert the changes to your subscriber's QoS
   profile before continuing the exercises.

.. _section-sec-HO3-further-exercises:

Further Exercises
-----------------

At this point, you have defined the permissions that will be applied
to your publisher application, restricting it to publish
*PatientMonitoring* data. However, we have not modified your subscriber's
permissions.

Define Different Permissions for Each Application in Your System
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

To minimize the damage in case one of your secure applications is compromised,
a |DP| should only have permissions to perform the actions
that are necessary for its legitimate purpose. [#]_

#. Define the permissions for Bob in a file called :file:`pmiPermissionsBob.xml`.
   This |PermissionsDoc| should contain a single grant named *ParticipantBob*,
   defining permissions to subscribe to any |TOPIC| containing the string
   ``Patient`` — only in |DOMAIN| *1*.

   You may want to use the following :xmltag:`allow_rule` as a reference:

   .. code-block:: xml

       <allow_rule>
           <domains>
               <id>1</id>
           </domains>
           <subscribe>
               <topics>
                   <topic>*Patient*</topic>
               </topics>
           </subscribe>
       </allow_rule>

   *ParticipantBob* should be denied any other actions. |br| |br|

#. Bind Bob's permissions to your subscriber application (see
   :ref:`section-sec-HO3-binding-permissions-file`).

   If you completed the exercises in :ref:`section-sec-HO1`),
   Bob's identity certificate should be
   :file:`cert/ecdsa01/identities/ecdsa01Peer02Cert.pem`.
   You will have to bind Bob's permissions to the subject of this certificate. |br| |br|

#. Make sure the Permissions CA signs the new |PermissionsDoc| and modify
   Bob's QoS profile to load it.

   After applying this configuration, your subscriber application, Bob, will
   only be allowed to subscribe to any |TOPIC| containing the string ``Patient``
   in |DOMAIN| *1*, while your publisher application, Alice, will only be allowed
   to publish |TOPIC| "Example PatientMonitoring" in |DOMAIN| *1*.

.. [#] This is known as the Principle of Least Privilege. For further
  information, see :link_connext_dds_secure_um:`Applying DDS Protection in the Security
  Plugins User's Manual <p1_welcome/overview.html#applying-dds-protection>`.

.. [#openssl_lm_path] In the :link_connext_dds_secure_ig:`free <#security_plugins/installation_guide/install_evaluation.html>`
   version (with ``lm`` in the bundle name), OpenSSL is installed automatically 
   when you install the |CONNEXT| host bundle. After installation, OpenSSL will 
   be in ``<installdir>/third_party/openssl-<version>``.

.. _section-sec-HO3-troubleshooting:

Troubleshooting
---------------

* When I run the publisher/subscriber, I get this error:

  .. code-block:: text

     RTI_Security_PermissionsCfgFileParser_getGrantForSubjectName:XML file doesn't contain a grant for subject name

  Make sure your |DPs| load the correct |IdentityCert| and |PermissionsDoc|.

  Make sure the subject in your |PermissionsDoc|'s grant matches the
  information in your participant's identity certificate (see
  :ref:`section-sec-HO3-binding-permissions-file`). Pay attention to the
  format. |br| |br|

* When I run the publisher/subscriber, I get this error:

  .. code-block:: text

     RTI_Security_AccessControl_create_participant:participant not allowed: no rule found for the participant's domain id or domain tag; default DENY

  Make sure you run your applications in the right |DOMAIN|, by specifying
  the Domain ID with the :command:`-d` option in the command line. In this
  example, we are using |DOMAIN| *1*. |br| |br|

* The subscriber is able to receive data, even if it does not have
  permissions to subscribe.

  Make sure your |GovernanceDoc| sets :xmltag:`enable_read_access_control`
  :xmlval:`TRUE`. Otherwise, permissions will not be enforced on locally created
  or remotely discovered |DRs|.

  You may be using the |GovernanceDoc| from
  :ref:`section-composing-governance-security-requirements`, with a specific
  topic rule appearing after the wildcard rule that applies to all topics. If
  your topic rule is more restrictive than the wildcard rule, it must be
  located first. The |GovernanceDoc| is processed from top to bottom, and the
  first matching rule is applied. |br| |br|

* When I run the publisher/subscriber, I get an error I do not understand.

  See :link_connext_dds_secure_um:`Logging Messages
  <p2_core/logging.html#logging-messages>` in the |SP_UM|.
