.. include:: ../vars.rst

.. _chapter-access-control:

**************
Access Control
**************

Access Control makes sure that |DPs| in your system have the right permissions
to join your *DDS* |SecDomains|, to publish data on sensitive |TOPICs|, to
subscribe to them, and to act as a proxy for |DWs| on different |DPs|.

Once a |DP| successfully authenticates, its permissions need to be validated and enforced. In this sense, the |SEC_SPEC| goes beyond many traditional security methods, where an application that is allowed to communicate within a secure system is trusted to access any information in it. Instead, the |AccessControlPlugin| provides fine-grained permissions that let you define whether a |DP| is allowed to join a particular |DOMAIN|, whether it is allowed to subscribe to a specific |TOPIC| within a particular partition, etc. These permissions lock down the specific access that trusted applications have, so if one application becomes compromised, the damage to the system is limited.

There is a strong relationship between the |AccessControlPlugin| and the Cryptography plugin because encryption keys need to be generated for |SecEntities| based on the |DP|'s permissions (see :ref:`p2_core/cryptography:Secure Entities`).

When a |DP| is created, the |AccessControlPlugin| will check whether the local
|PermissionsDoc| has a grant for the |DP| being created, based on its
|IdentityCert|. Then the plugin will check whether the |DP| has permission to
join the |DOMAIN| and permission to create the necessary entities. This is done
by examining the |PermissionsDoc|. |PermissionsDocs| are exchanged between
|DPs| during the Authentication process. This makes it possible to check
whether the remote participants have permission to join the |DOMAIN|, to
publish/proxy/subscribe to certain |TOPICs|, etc. Because the |PermissionsDocs| must be signed by the Permissions CA, it's possible to verify that the |PermissionsDocs| provided by remote participants are legitimate.

The Cryptography plugin has an important role in making sure the permissions apply by protecting the data. The |GovernanceDoc| specifies how |DOMAIN|-wide permissions are enforced, and how data and metadata is protected on those |DOMAINs|. |PermissionsDocs| provide granular access control at an individual participant level.

.. admonition:: Definition

  We will refer to "|GovernanceDoc|" and "|PermissionsDoc|" as the abstract
  concept that contains the Governance rules or Permission grants that will
  apply in the system. On the other hand, we will refer to |GovernanceDoc| and
  |PermissionsDoc| to refer to the XML representation of the Governance rules
  and Permission grants. XML representation is the only one that is supported in
  the latest version of the |SEC_SPEC| and also in the current version of the
  |RTI_SP_PRODUCT|, so we will use these terms interchangeably in this chapter.

.. note::

  In the case of |LIGHT_SP_BUILTIN|, which implements |SEC_SPEC_12|
  builtin PSK plugins, the |AccessControlPlugin| does not support granular
  access control. Instead, all access control is based on the access to the right
  |PSK|.
  Consequently, most of this chapter is only applicable to |SP_BUILTIN| or
  custom security plugins.


Access Control consists of two components: governance and permissions checking. Governance is the process of configuring locally created |DPs|, |TOPICs|, |DWs|, and |DRs| to perform the right amount of security for the right use case. Permissions checking is the process of making sure locally created and remotely discovered |Entities| are allowed to do what they want to do. Both governance and permissions checking are enforced by XML documents that are signed by a Permissions Certificate Authority that can be the same as the Identity Certificate Authority that signs |IdentityCerts|. The XSD definitions of these documents are in :ref:`p2_core/elements_dds_secure_system:XML Validation in the Governance Document` and :ref:`p2_core/elements_dds_secure_system:XML Validation in the Permissions Document`.

For examples of these documents, refer to :ref:`section-sp-properties`.
Use these examples just as a reference; you will need to modify their content
to match your system configuration (|DOMAINs|, |TOPICs|, and used
|IdentityCerts|) and sign the XML files. To specify that you want to use these
files, add the corresponding properties detailed in :numref:`DDS Security
Properties for Configuring Access Control` and :numref:`|RTI_SP_PRODUCT_HEADING|
Properties for Configuring Access Control` to the |DP|'s PROPERTY QosPolicy
(see :ref:`section-sp-properties`).


Governance Document
===================

The |GovernanceDoc| is an XML document that specifies how the |DOMAIN| should be secured. The Permissions CA (specified with the :property:`dds.sec.access.permissions_ca` property) must sign the |GovernanceDoc| using S/MIME version 3.2 format (which corresponds to the mime-type application/pkcs7-signature). The signed |GovernanceDoc| needs to be provided to the plugins using the :property:`dds.sec.access.governance` property as specified in :numref:`DDS Security Properties for Configuring Access Control`.

This document configures multiple aspects that apply to the whole |DOMAIN|, such as:

* whether the discovery/liveliness information should be protected and the kind of protection,
* whether the whole RTPS message should be protected and the kind of protection,
* whether a discovered |DP| that cannot authenticate or fail the authentication should be allowed to join the |DOMAIN|,
* whether any successfully authenticated |DP| should be allowed to join the |DOMAIN| and see the discovery data without checking the access control policies.

This document also specifies how the information on specific |TOPICs| within the |DOMAIN| should be treated. More specifically, it specifies:

* whether the discovery/liveliness information on specific |TOPICs| should be sent using the secure (protected) writers or using the regular (unprotected) ones,
* whether read/write access to the Topic should be open to all or restricted to the |DPs| that have the proper permissions,
* whether the metadata information sent on the Topic should be protected and the kind of protection,
* whether the payload data (serialized application level data) sent on the |TOPIC| should be protected and the kind of protection.

The local |DP| validates the locally loaded |GovernanceDoc| against the
Permissions CA specified in the :property:`dds.sec.access.permissions_ca`
property (see :numref:`DDS Security Properties for Configuring Access Control`).
If the Permissions CA cannot validate the |GovernanceDoc|, the validation will
be retried with the alternative certificates specified in the
:property:`access_control.alternative_permissions_cas` property (see
:numref:`|RTI_SP_PRODUCT_HEADING| Properties for Configuring Access Control`).
If none of the alternative CAs can validate the file (or if you did not set this
property), the creation of the local |DP| will fail.

The local |DP| checks the compatibility of the |GovernanceDoc| for remotely discovered |DPs| by checking the participant security attributes and the endpoint security attributes exchanged in the discovery, as explained in :ref:`p2_core/elements_dds_secure_system:Governance Compatibility Validation`.

Further details on the |GovernanceDoc|:
:ref:`p2_core/elements_dds_secure_system:Governance Document`.


Permissions Document
====================

The |PermissionsDoc| specifies what actions a |DP| is allowed to take in a
|SecDomain|. For example, it determines whether the |DP| can join the |DOMAIN|
(participant-level rules), whether it can publish, subscribe to, or proxy
particular |TOPICs|, partitions, etc. (endpoint-level rules).

The |PermissionsDoc| is stored as an XML file. The Permissions CA must sign the
|PermissionsDoc| using S/MIME version 3.2 format (which corresponds to the
mime-type application/pkcs7-signature). The signed |PermissionsDoc| is provided
to the |SP_BUILTIN| using the :property:`dds.sec.access.permissions` property,
as specified in :numref:`DDS Security Properties for Configuring Access Control`.

The |PermissionsDoc| is mutable and can be renewed at the |DP|'s runtime.
Renewals are made using the ``set_qos`` API or by changing the
|PermissionsDoc| file. The |PermissionsDoc| file can be tracked for changes to
set up automatic renewals. For details, see the :ref:`p2_core/access_control:Permissions Expiration`
section.

The local |DP| validates the |PermissionsDoc| against the Permissions CA
specified in the :property:`dds.sec.access.permissions_ca` property (see
:numref:`DDS Security Properties for Configuring Access Control`). If the
Permissions CA cannot validate the |PermissionsDoc|, the validation will be
retried with the alternative certificates specified in the
:property:`access_control.alternative_permissions_cas` property (see
:numref:`|RTI_SP_PRODUCT_HEADING| Properties for Configuring Access Control`).
If none of the alternative CAs can validate the |PermissionsDoc| (or if you did
not set this property), the validation process will fail.

The |PermissionsDoc| contains a set of :xmltag:`grant` sections, each of which
contains a :xmltag:`subject_name` or :xmltag:`subject_name_expression` section,
a :xmltag:`validity` section, zero or more :xmltag:`allow_rule` sections, and
zero or more :xmltag:`deny_rule` sections. Each grant contains the permissions
of a particular subject name or subject name expression, and the rules in
:ref:`p2_core/access_control:Rules for matching a subject name in the |PermissionsDoc|`
determine which grant is bound to a particular |DP|. The :xmltag:`validity` tag
determines whether the |PermissionsDoc| is valid for the current date and time.
Please note that in the current version of |CONNEXT|, the signed
|PermissionsDoc| only supports validity dates between 1970-01-01T00:00:00Z and
2106-02-07T06:28:15Z. Any dates before 1970-01-01T00:00:00Z will result in an
error, and any dates after 2106-02-07T06:28:15Z will be treated as
2106-02-07T06:28:15Z. Currently, |CONNEXT| is undefined if the system time is
after 7 February 2106, 06:28:15 UTC.

|PermissionsDocs| are exchanged between |DPs| during the authentication process
to claim and verify permissions. Hence, to conserve bandwidth, it is best for
this document to have exactly one :xmltag:`grant` section, which contains the
subject name and rules for the |DP| presenting it.

For more information about the |PermissionsDoc|, its structure, and its role in
your secured system, see :ref:`p2_core/elements_dds_secure_system:Permissions Document`.

Using the :xmltag:`domains` tag you can control what |DOMAINs| your |DPs| are
allowed to join (participant-level permissions), as described in
:ref:`p2_core/elements_dds_secure_system:Specifying Domains`. The following
sections describe how to give your |DPs| permission to publish, subscribe to,
and proxy different |TOPICs| based on the topic name, partitions, and data
tags. These endpoint-level permissions are specified using the elements in the
:xmltag:`publish`, :xmltag:`subscribe`, and :xmltag:`proxy` sections, which are
inside the :xmltag:`allow_rule` and :xmltag:`deny_rule` sections.

Rules for matching a subject name in the |PermissionsDoc|
---------------------------------------------------------

The |PermissionsDoc| contains a set of :xmltag:`grant` sections, each of which
must contain either a :xmltag:`subject_name` or a
:xmltag:`subject_name_expression` XML element. If a valid match is found between
the subject name of the |DP| (as defined in its |IdentityCert|) and one of the
subject names in the |PermissionsDoc|'s grants, then the |DP| is bound to the
rules for that grant.

The |SP_BUILTIN| consider that a match is valid if one of the following occurs:

* The |PermissionsDoc| grant has a :xmltag:`subject_name` element with
  attributes that exactly match those from the |DP|'s |IdentityCert| subject
  name. Capitalization is ignored when comparing the attribute values. The
  ordering of the attributes may be different between the :xmltag:`subject_name`
  and the |DP|'s |IdentityCert| subject name.

  * There can only be one exact match because different grants with the same
    value of the :xmltag:`subject_name` element are not allowed. The
    |SP_BUILTIN| also detect a duplicate :xmltag:`subject_name` that has a
    different attribute order.

* The |PermissionsDoc| grant has a :xmltag:`subject_name_expression` element
  with attributes that match the ones from the |DP|'s |IdentityCert| subject
  name. This is a case-sensitive match that follows the syntax and rules of the
  POSIX ``fnmatch()`` function as specified in POSIX 1003.2-1992, Section B.6.
  The ordering of the attributes may be different between the
  :xmltag:`subject_name_expression` and the |DP|'s |IdentityCert| subject name.

  * A |DP|'s |IdentityCert| subject name can match multiple
    :xmltag:`subject_name_expression` grants. Only the first matching
    :xmltag:`subject_name_expression` will be considered (even if later patterns
    are more specific).

  * Different grants can have values of :xmltag:`subject_name_expression` that
    are functionally equivalent. The |SP_BUILTIN| will not detect these
    duplicates. The |SP_BUILTIN| detect only exactly duplicated attribute values
    of the :xmltag:`subject_name_expression` elements (ordering of the
    attributes in the expression may vary).

.. warning::

    An exact (case-insensitive, order of attributes may vary) match between the
    |DP|'s |IdentityCert| subject name and a :xmltag:`subject_name` will take
    precedence over a (case-sensitive, order of attributes may vary) pattern
    match with a :xmltag:`subject_name_expression`, regardless of the positions
    of their grants in the |PermissionsDoc|. To improve debuggability, the
    |SP_BUILTIN| will log a warning message if a :xmltag:`subject_name` match
    happens after a :xmltag:`subject_name_expression` match.

.. admonition:: Some examples

    This |IdentityCert| subject name:

    .. code-block:: xml

        C = US, ST = CA, O = Real-Time Innovations, CN = RTI ECDSA01 (p256) PEER01, emailAddress = ecdsa01Peer01@rti.com

    will match any of the following ``<subject_name>`` values:

    .. code-block:: xml

        <grant name="ExactMatch">
          <subject_name>
            C = US, ST = CA, O = Real-Time Innovations, CN = RTI ECDSA01 (p256) PEER01, emailAddress = ecdsa01Peer01@rti.com
          </subject_name>
          [...]
        </grant>

        <!--
            Match: we ignore capitalization, whitespace around attribute values,
            and the order of the attributes. The ',' ';' '/' characters can act
            as delimiters between attributes.
        -->
        <grant name="MatchRegardlessOrderCaseAndWhitespace">
          <subject_name>
            /C=US/ST=CA/O=Real-Time Innovations/emailAddress=ecdsa01Peer01@rti.com/CN=rti ecdsa01 (p256) PEER01
          </subject_name>
          [...]
        </grant>

    or the following ``<subject_name_expression>`` values:

    .. code-block:: xml

        <grant name="ExactMatchInExpression">
          <subject_name_expression>
            /C=US/ST=CA/O=Real-Time Innovations/CN=RTI ECDSA01 (p256) PEER01/emailAddress=ecdsa01Peer01@rti.com
          </subject_name_expression>
          [...]
        </grant>

        <!--
            Match: we ignore whitespace around attribute values, and the order
            of the attributes. We do not ignore capitalization.
            The ',' ';' '/' characters can act as delimiters between attributes.
        -->
        <grant name="MatchRegardlessOrderAndWhitespace">
          <subject_name_expression>
            /C=US/ST=CA/O=Real-Time Innovations/emailAddress=*@rti.com/CN=RTI ECDSA01*
          </subject_name_expression>
          [...]
        </grant>

    The following ``<subject_name_expression>`` elements are considered
    duplicates if they are found in the same Permissions Document.

    .. code-block:: xml

        <!--
            Same attribute names and values, but in different order. We still
            detect them as duplicates.
        -->
        <grant name="DuplicateRegardlessOrderEmailLater">
          <subject_name_expression>
            /C=US/ST=CA/O=Real-Time Innovations/CN=*/emailAddress=ecdsa01Peer01@rti.com
          </subject_name_expression>
          [...]
        </grant>

        <grant name="DuplicateRegardlessOrderEmailFirst">
          <subject_name_expression>
            /C=US/CN=*/ST=CA/emailAddress=ecdsa01Peer01@rti.com/O=Real-Time Innovations
          </subject_name_expression>
          [...]
        </grant>
    
    But we wouldn't consider them duplicates if they had different
    capitalization or attribute values. The |SP_BUILTIN| only detects duplicates
    if the attribute values are exactly the same, even if they are redundant or
    functionally equivalent patterns. For example, these
    ``<subject_name_expression>`` elements won't be detected as duplicates even
    though the second expression is a subset of the first one:

    .. code-block:: xml

        <!--
            Subject names matching the second expression will also match the
            first one. However, this redundancy will not cause the Builtin
            Security Plugins to reject this Permissions Document. Only the first
            grant will ever be used, and the second grant will always be
            silently ignored.
        -->
        <grant name="LessSpecificMatchFirst">
          <subject_name_expression>
            /C=US/CN=*/ST=CA/emailAddress=*@rti.com/O=Real-Time Innovations
          </subject_name_expression>
          [...]
        </grant>

        <grant name="MoreSpecificMatchIgnored">
          <subject_name_expression>
            /C=US/ST=CA/O=Real-Time Innovations/CN=*/emailAddress=*01@rti.com
          </subject_name_expression>
          [...]
        </grant>

    If the |IdentityCert| subject name matches both a ``<subject_name>`` and a
    ``<subject_name_expression>`` in the same Permissions Document, the
    ``<subject_name>`` will take precedence over the
    ``<subject_name_expression>``. This happens regardless of the position of
    the ``<subject_name_expression>`` (before or after the ``<subject_name>``)
    and its specificity:

    .. code-block:: xml

        <!-- The subject_name takes precedence over the expressions. -->
        <grant name="ExpressionBefore">
          <subject_name_expression>
            /C=US/ST=CA/O=Real-Time Innovations/CN=RTI ECDSA01 (p256) PEER01/emailAddress=ecdsa01Peer01@rti.com
          </subject_name_expression>
          [...]
        </grant>

        <grant name="ExactMatchPreferred">
          <subject_name>
            /C=US/ST=CA/O=Real-Time Innovations/CN=rti ecdsa01 (p256) PEER01/emailAddress=ecdsa01Peer01@rti.com
          </subject_name>
          [...]
        </grant>

        <grant name="ExpressionAfter">
          <subject_name_expression>
            /C=US/ST=CA/O=Real-Time Innovations/CN=*/emailAddress=ecdsa01Peer01@rti.com
          </subject_name_expression>
          [...]
        </grant>

Topics
------

The :xmltag:`topics` element defines the DDS Topic names that must be matched for the rule to apply. Topic names may be given explicitly or by means of Topic name expressions. Each topic name or topic-name expression appears in a separate :xmltag:`topic` sub-element within the :xmltag:`topics` element. The Topic name expression syntax and matching shall use the syntax and rules of the POSIX ``fnmatch()`` function as specified in POSIX 1003.2-1992, Section B.6.

Example (appearing within an :xmltag:`allow_rule` and within a :xmltag:`publish` tag):

.. code-block:: xml

  <allow_rule>
    <publish>
      <topics>
        <topic>Square</topic>
        <topic>B*</topic>
      </topics>
    </publish>
  </allow_rule>


The above topic condition would match |TOPIC| “Square” and any |TOPIC| that starts with a “B”.


Partitions
----------

The :xmltag:`partitions` element defines the DDS Partition names that must be
matched for the rule to apply (see
:link_connext_dds_pro_um:`PARTITION QosPolicy in the RTI Connext DDS Core Libraries User's Manual <#users_manual/PARTITION_QosPolicy.htm>`).
Partition names may be given explicitly or by means of partition-name
expressions. Each partition name or partition-name expression appears in a
separate :xmltag:`partition` sub-element within the :xmltag:`partitions`
element. The partition-name expression syntax and matching shall use the syntax
and rules of the POSIX ``fnmatch()`` function as specified in POSIX 1003.2-1992,
Section B.6.

Example (appearing within an :xmltag:`allow_rule` and within a
:xmltag:`subscribe` tag):

.. code-block:: xml

  <allow_rule>
    <subscribe>
      <topics>
        <topic>Square</topic>
      </topics>
      <partitions>
        <partition>Partition1</partition>
        <partition>Partition2</partition>
        <partition>PartitionA*</partition>
      </partitions>
       ...
    </subscribe>
  </allow_rule>


Note the asterisk in the third partition. POSIX ``fnmatch()`` matching is
allowed for the :xmltag:`partition` element.

The :xmltag:`partitions` tag can appear within a :xmltag:`publish` or
:xmltag:`proxy` element and affect |DWs|, within a :xmltag:`subscribe` element
and affect |DRs|, or directly under the :xmltag:`allow_rule` or
:xmltag:`deny_rule` tags and affect |DPs|.

Behavior of the partitions tag within an allow_rule
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

If the :xmltag:`partitions` tag is under an :xmltag:`allow_rule`, it delimits
which partitions (specified within :xmltag:`partition` tags) are allowed. In
order for an action (e.g., a publish action) to meet the allowed partitions
condition, the set of partitions associated with the |DDS_ENTITY| performing
that action (e.g., a |DW| for a publish action) must be contained by the set of
partitions defined by the allowed partitions condition section.

As a limitation, if the |DDS_ENTITY| performing an action (e.g., a |DW| for a
publish action) uses patterns in its partitions, these patterns must appear
explicitly in the allowed partitions condition section. An exception to this
rule is adding the :xmlval:`*` pattern to the allowed partitions condition
section, which will allow the attempted action, regardless of the partitions
announced by the |DDS_ENTITY|.

If there is no :xmltag:`partitions` section, then the default "empty string"
partition is assumed. Hence, the allowed action (e.g., a publish action) would
only allow publishing on the "empty string" partition.

Example (appearing within a :xmltag:`allow_rule` and within a :xmltag:`publish` tag):

.. code-block:: xml

  <allow_rule>
    <publish>
      <topics>
        <topic>Square</topic>
      </topics>
      <partitions>
        <partition>A</partition>
        <partition>B</partition>
      </partitions>
    </publish>
    ...
  </allow_rule>


The above allowed partitions condition would be matched if the partitions
associated with the |DDS_ENTITY| performing the action (e.g., |DW| for publish
action) are a subset of the set :value:`[A, B]`. So it would be OK to publish in
partition :value:`A`, in partition :value:`B`, or in partition :value:`[A, B]`
but not in partition :value:`[A, B, C]` [#]_ or in the "empty string" partition.

.. [#] Assuming the property :property:`access_control.use_530_partitions` is
   :value:`FALSE` (see :numref:`|RTI_SP_PRODUCT_HEADING| Properties for Configuring Access Control`).


Behavior of the partitions tag within a deny_rule
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

If the :xmltag:`partitions` tag is under a :xmltag:`deny_rule`, it delimits which partitions (specified within :xmltag:`partition` tags) are denied. For this condition to be met, the |DDS_ENTITY| associated with the action (e.g., |DW| for a publish action) must have a partition that matches one of the partitions explicitly listed in the denied partitions condition section.

In other words, the |AccessControlPlugin| will deny the attempted action if the set of partitions announced by the |DDS_ENTITY| attempting to perform that action (e.g., |DW| for a publish action) intersects the set of partitions defined in the denied partitions condition section. For computing the intersection, both concrete partitions and expressions containing patterns are considered. Note that if the |DDS_ENTITY| only announces partitions containing patterns, it will fall back to the "empty string" partition. Therefore, the action will be denied if the denied partitions condition section intersects with the "empty string" partition.

If there is no :xmltag:`partitions` section, then the :value:`*` partition expression is assumed. This means that the deny action (e.g., publish action) would apply regardless of the partitions associated with the |DDS_ENTITY| (e.g., |DW| for a publish action).

Example (appearing within a :xmltag:`deny_rule` and within a :xmltag:`publish` tag):

.. code-block:: xml

  <deny_rule>
    <subscribe>
      <topics>
        <topic>Square</topic>
      </topics>
      <partitions>
        <partition>A</partition>
        <partition>B</partition>
      </partitions>
    </subscribe>
    ...
  </deny_rule>

  <default>ALLOW</default>


The above denied partitions condition would be matched if the partitions associated with the |DDS_ENTITY| performing the action (e.g., |DW| for a publish action) intersect the partition set :value:`[A, B]`. So, it would be OK to publish in partition :value:`C` or in the "empty string" partition, but not in partition :value:`A`, in partition :value:`[A,B]`, or in partition :value:`[A, B, C]`.


Partition Mutability
^^^^^^^^^^^^^^^^^^^^

|DWs| need to avoid sending historical data to unauthorized |DRs| joining a new
partition. Therefore, there are scenarios where |PUBs| are not allowed to change
partitions. Note that these restrictions do not apply to |SUBs| or to |DPs|.

The |RTI_SP_PRODUCT| do not allow a |PUB| to change the PARTITION QosPolicy after the |PUB| has been enabled if the |PUB| contains any |DW| that meets the following two criteria:

* The TopicSecurityAttributes for that |DW| have :xmltag:`is_read_protected` (which corresponds to :xmltag:`enable_read_access_control` in the |GovernanceDoc|) set to :xmlval:`TRUE`.
* The |DW| has the DURABILITY QosPolicy kind set to something other than
  :xmlval:`VOLATILE`.

When these two criteria are met, a |DW| should send historical data only to |DRs| that were passing the :xmltag:`topic` access control rules at the time the historical data was generated. The rule about PartitionQoS immutability enforces this behavior by conservatively preventing a |DW| of a protected |TOPIC| from sending historical data to |DRs| that were not matched before a PartitionQoS change and that potentially could have failed to pass the :xmltag:`topic` access control rules.

.. figure:: ../static/datawriter-changing-partition.png
    :scale: 50%
    :name: Reliable DataWriter Changing Partition
    :align: center

    Reliable |DW| Changing Partitions


Data Tags
---------

The RTI Connext DDS Core Libraries User's Manual describes the DATATAG QosPolicy as a sequence of :value:`(name, value)` string pairs that belong to a |DW| or |DR| (see :link_connext_dds_pro_um:`DATATAG QosPolicy in the Core Libraries User's Manual <#users_manual/DATATAG_Qos.htm>`). The |AccessControlPlugin| uses these tags to determine whether or not a |DW| or |DR| is allowed to exist according to the |PermissionsDoc|. Inside the |PermissionsDoc|, the :xmltag:`data_tags` element may appear within a :xmltag:`publish` or :xmltag:`subscribe` element. :xmltag:`data_tags` may contain one or more :xmltag:`tag` elements, each containing a :xmltag:`name` and a :xmltag:`value` element. For example:

.. code-block:: xml

  <subscribe>
    <topics>
      <topic>Sq*</topic>
    </topics>
    <data_tags>
      <tag>
        <name>Department</name>
        <value>Engineering</value>
      </tag>
      <tag>
        <name>Seniority</name>
        <value>Senior</value>
      </tag>
      <tag>
        <name>Title</name>
        <value>*Software*</value>
      </tag>
    </data_tags>
  </subscribe>

Note the asterisk in the third tag's value. POSIX ``fnmatch()`` matching is allowed for the :xmltag:`value` element, but not for the :xmltag:`name` element.

For further information on data tags, refer to :ref:`p2_core/tagging:Data Tagging`.


Behavior of data_tags within an allow_rule
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

If the :xmltag:`data_tags` are under an :xmltag:`allow_rule`, then the :xmltag:`data_tags` delimit an allowed data tags condition section. In order for an action (e.g., a publish action) to meet the allowed data tags condition, the set of the data tags associated with the |DDS_EP| performing the action (e.g., a |DW| for a publish action) must be contained in the set of data tags defined by the allowed data tags condition section. If there is no :xmltag:`data_tags` section, then the default empty set is assumed. This means that the allow action (e.g., publish action) would only allow publishing if there are no data tags associated with the |DDS_EP| (e.g., |DW| for a publish action).

Example (appearing within an :xmltag:`allow_rule` and within a :xmltag:`publish` tag):

.. code-block:: xml

  <allow_rule>
    <publish>
      <topics>
        <topic>Square</topic>
      </topics>
      <data_tags>
         <tag>
             <name>aTagName1</name>
             <value>aTagValue1</value>
         </tag>
      </data_tags>
    </publish>
  </allow_rule>

The above allowed data tags condition would be matched if the data tags associated with the |DDS_ENTITY| performing the action (e.g., |DW| for publish action) are a subset of the set :value:`[(aTagName1, aTagValue)]`. So it would be OK to publish using a |DW| with no associated data tags, or a |DW| with a single tag with name :value:`aTagName1` and value :value:`aTagValue1`.

Behavior of data_tags within a deny_rule
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

If the :xmltag:`data_tags` are under a :xmltag:`deny_rule`, then the :xmltag:`data_tags` delimit a denied data tags condition section. For this condition to be met, the |DDS_ENTITY| associated with the action (e.g., |DW| for a publish action) must have a data tag name and value pair that matches one of the data tags explicitly listed in the denied data tags condition section. If there is no :xmltag:`data_tags` section, then the "set of all possible tags" set is assumed as default. This means that the deny action (e.g., deny publish action) would apply regardless of the data tags associated with the |DDS_EP| (e.g., |DW| for a publish action).

Example (appearing within a :xmltag:`deny_rule` and within a :xmltag:`publish` tag):

.. code-block:: xml

  <deny_rule>
    <publish>
      <data_tags>
        <tag>
           <name>aTagName1</name>
           <value>aTagValue1</value>
        </tag>
      </data_tags>
    </publish>
  </deny_rule>

The above denied data tags condition would be matched if the data tags associated with the |DDS_ENTITY| performing the action (e.g., |DW| for a publish action) intersect the set :value:`[(aTagName1, aTagValue1)]`. So it would not deny publishing using a |DW| with no associated data-tags, or a |DW| with a single tag with name :value:`aTagName2`, or a |DW| with a single tag with name :value:`aTagName1` and value :value:`aTagValue2`. But it would deny publishing using a |DW| with two associated data tags :value:`[(aTagName1, aTagValue1), (aTagName2, aTagValue2)]`. :numref:`Effect of the Example Deny Rule When Different Data Tags Are Present` analyzes other scenarios for this concrete example.

.. list-table:: Effect of the Example Deny Rule When Different Data Tags Are Present
  :name: Effect of the Example Deny Rule When Different Data Tags Are Present
  :width: 70%
  :widths: auto
  :align: center
  :header-rows: 1
  :class: longtable

  * - |DW| Tag(s)
    - Allow/Deny

  * - .. code-block:: xml

        <tag>
          <name>aTagName1</name>
          <value>aTagValue1</value>
        </tag>

    - Deny

  * - .. code-block:: xml

        <tag>
        </tag>

    - Allow

  * - .. code-block:: xml

        <tag>
          <name>aTagName1</name>
          <value>aTagValue2</value>
        </tag>

    - Allow

  * - .. code-block:: xml

        <tag>
          <name>aTagName2</name>
          <value>aTagValue1</value>
        </tag>

    - Allow

  * - .. code-block:: xml

        <tag>
          <name>aTagName1</name>
          <value>aTagValue1</value>
        </tag>
        <tag>
          <name>aTagName2</name>
          <value>aTagValue2</value>
        </tag>

    - Deny

Permissions Expiration
----------------------

The |SP_BUILTIN| enforce the times provided in the :xmltag:`validity` tag of the
|PermissionsDoc|. The :xmltag:`notBefore` attribute indicates when the permissions
become valid, and the :xmltag:`notAfter` attribute indicates when the permissions
expire. If the :xmltag:`notBefore` value is in the future or :xmltag:`notAfter`
is in the past, the |PermissionsDoc| will be rejected. If the |PermissionsDoc| is
rejected during the |DP| creation process, the |DP| creation will fail. If the
rejection occurs while renewing the |PermissionsDoc|, the previous permissions
will remain in effect.

The same principles apply to remote |DPs|. A remote |DP| using permissions
that are not currently valid will either cause the authentication to fail,
or cause the remote |DP| to be removed from the system upon permissions
expiration if it does not present a renewed |PermissionsDoc| before this time. See
the :ref:`p2_core/access_control:Permissions Renewal` section for details about
the |PermissionsDoc| renewal.

To use permissions expiration and renewal in |SP_BUILTIN|, Key Revisions must 
be enabled. To do so, set the :xmltag:`enable_key_revision` domain-level 
Governance Rule to ``true``. For more information about this rule, 
see :ref:`section-enable-key-revision`.

.. note::

  The |PermissionsDoc| validity times are compared against the local clock of each
  |DP|. Time synchronization within your system is an important topic, and it includes
  time-related settings in the Permissions CA. When designing your system, we recommend
  you account for possible clock differences in your system and incorporate measures
  (for example, an adequate leeway and early updates) to mitigate |PermissionsDoc|
  rejection caused by a minimal time difference.

Expiration Notification
^^^^^^^^^^^^^^^^^^^^^^^

To receive notifications about an upcoming local |DP| |PermissionsDoc| expiration,
configure the local |DP| with a *DomainParticipantListener* and a *StatusMask* that
includes :link_connext_dds_api_cpp2:`INVALID_LOCAL_ADVANCE_NOTICE_STATUS
<classrti_1_1core_1_1status_1_1InvalidLocalAdvanceNoticeStatus.html>`. The
|SP_BUILTIN| notification time is derived from the |PermissionsDoc| :xmltag:`notAfter`
attribute and the :property:`dds.participant.trust_plugins.expiration_advance_notice_duration.sec`
property (:value:`notification time = notAfter - expiration_advance_notice_duration.sec`).
The notification is issued by invoking the
:link_connext_dds_api_cpp2:`on_invalid_local_status_advance_notice<classdds_1_1domain_1_1DomainParticipantListener.html>`
callback function.

After the first notification is sent, the |SP_BUILTIN| will resend the same notification
at a specified interval until the |PermissionsDoc| expires. To configure the reminder
interval, use the :property:`dds.participant.trust_plugins.expiration_advance_notice_reminder_period.sec`
property.

Permissions Renewal
^^^^^^^^^^^^^^^^^^^

The |SP_BUILTIN| provide two mechanisms to renew the |PermissionsDoc| at runtime.

* Use the ``set_qos`` API. For details on how to use the ``set_qos`` operation, see
  :link_connext_dds_pro_um:`Configuring QoS Programatically <#users_manual/Getting__Setting__and_Comparing_QosPolic.htm>`
  in the *RTI Core Libraries User's Manual*.

* Update the content of (or replace) the |PermissionsDoc| file. If file tracking is enabled,
  the |SP_BUILTIN| will automatically pick up changes in the |PermissionsDoc| and renew the
  |DP|'s permissions. To enable |PermissionsDoc| tracking, ensure the
  :property:`files_poll_interval` property is set to a non-zero number
  (see :ref:`section-elements-global-props`).

.. attention::

  In this release, the |SP_BUILTIN| only allow renewing the |PermissionsDoc|; only
  changes in :xmltag:`notBefore` and :xmltag:`notAfter` values are permitted. This
  means you can extend the validity of your permissions, but you cannot change what is
  allowed or not. Any changes beyond |PermissionsDoc| validity will result in |PermissionsDoc|
  update rejection. To avoid rejection, make sure the renewed |PermissionsDoc| keeps exactly
  the same content (except validity dates and S/MIME prefix and postfix) and the same order
  as in the original |PermissionsDoc|.

  If you want to change the permissions to allow or deny a rule, you need to restart
  the |DP| with a new |PermissionsDoc|.

Related Governance Rules
========================

This section describes the Access Control attributes that appear in the
|GovernanceDoc|.


Domain-level rules
------------------

The following attributes can be configured inside a :xmltag:`domain_rule`:


enable_join_access_control (within a domain_rule)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

:xmltag:`enable_join_access_control` may be :xmlval:`TRUE` or :xmlval:`FALSE`. It controls whether or not |DP|-level permissions are checked when a |DP| is created or discovered.

When :xmltag:`enable_join_access_control` = :xmlval:`TRUE`, the local |DP| will check whether it has permission to join the |DOMAIN|. If it does, it will perform the same check for each of the remotely discovered |DPs|.

When :xmltag:`enable_join_access_control` = :xmlval:`FALSE`, the local |DP| is still required to have a valid |PermissionsDoc|, but this |PermissionsDoc| is not required to allow the local |DP| to join the |DOMAIN|. Remote |DPs| are not even required to have a valid |PermissionsDoc| unless :xmltag:`enable_read_access_control` = :xmlval:`TRUE` or :xmltag:`enable_write_access_control` = :xmlval:`TRUE` for a discovered |TOPIC|.

Note that :xmltag:`enable_join_access_control` does not affect endpoint-level permissions such as publishing or subscribing to specific |TOPICs|.

The |AccessControlPlugin| will not check participant-level permissions for |DPs| that cannot be authenticated because they either are unsecure participants or they fail to authenticate. Therefore, :xmltag:`enable_join_access_control` does not have any effect when :xmltag:`allow_unauthenticated_participants` = :xmlval:`TRUE`, and the remote participant is unauthenticated.

For more information, see :ref:`p2_core/access_control:Participant-level Permissions, Endpoint-level Permissions, and Unsecure DomainParticipants`.


enforce_proxy_permissions
^^^^^^^^^^^^^^^^^^^^^^^^^

You should not use this tag unless you are integrating with legacy systems
where domain insider integrity and availability threats are not a concern.

:xmltag:`enforce_proxy_permissions` may be :xmlval:`true` or :xmlval:`false`. It
controls what to do when the |PermissionsDoc| does not have
an explicit allow or deny rule for a |DW|'s proxy permission. For more
information on proxy permissions, see
:ref:`p2_core/access_control:DataWriters Acting as a Proxy for other DataWriters`.

When :xmltag:`enforce_proxy_permissions` = :xmlval:`true`, the |DW| will be
prohibited to act as a proxy. The only way to allow the |DW| from acting as a
proxy would be to have an explicit allow rule for it.

When :xmltag:`enforce_proxy_permissions` = :xmlval:`false`, the |DW| will be
allowed to act as a proxy. The only way to prohibit the |DW| from acting as a
proxy would be to have an explicit deny rule for it.

:xmltag:`enforce_proxy_permissions` is an optional tag. If it is absent, the
value of :xmltag:`enforce_proxy_permissions` is effectively :xmlval:`true`.
We recommend leaving :xmltag:`enforce_proxy_permissions` absent and explicitly
adding allow rules for proxy permissions as needed.


topic_access_rules (domain_rule)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

:xmltag:`topic_access_rules` contains one or more :xmltag:`topic_rule` attributes where you can define your system's security requirements on a per-topic basis (see :ref:`p2_core/access_control:Governance Document`).


Topic-level rules
------------------

The following attributes can be configured inside a :xmltag:`topic_rule`:


enable_read_access_control (topic_rule)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

This attribute may be :xmlval:`TRUE` or :xmlval:`FALSE`. It controls whether or not endpoint-level permissions are checked for |DRs|. If :xmltag:`enable_read_access_control` = :xmlval:`TRUE` for a given :xmltag:`topic`, the local permissions are enforced on locally created |DRs| of that :xmltag:`topic`, and the remote permissions are enforced on remotely discovered |DRs| of that :xmltag:`topic`.


enable_write_access_control (topic_rule)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

This attribute may be :xmlval:`TRUE` or :xmlval:`FALSE`. It controls whether or not |DW| permissions are checked. If :xmltag:`enable_writer_access_control` is :xmlval:`TRUE` for a given :xmltag:`topic`, the local permissions are enforced on locally created |DWs| of that :xmltag:`topic`, and the remote permissions are enforced on remotely discovered |DWs| of that :xmltag:`topic`.


No Matching Rule
^^^^^^^^^^^^^^^^

If no matching domain (in the case of |DPs|) or topic rule (in the case of |DWs|/|DRs|) is found in the |GovernanceDoc|, the |Entity| creation will fail when Access Control checks if this |Entity| can be created in this |DOMAIN|. This is done because if there is no rule, the |AccessControlPlugin| assumes no permissions, which is the more restrictive decision.


Advanced Access-Control Concepts
================================

Participant-Level Permissions, Endpoint-Level Permissions, and Unsecure DomainParticipants
------------------------------------------------------------------------------------------

As mentioned earlier, you can control whether the |AccessControlPlugin| will check participant-level permissions and endpoint-level permissions for remote participants with the enable_*_control Governance rules (see :ref:`p2_core/access_control:Related Governance Rules`). The |AccessControlPlugin| checks these permissions in different stages of the communication, so they are independent. (Note that successfully authenticated remote participants must present a grant matching the subject name in its |IdentityCert|, even though remote permissions checking is disabled. Authenticated participants failing to provide such a grant will be rejected.)

The :xmltag:`enable_join_access_control` Governance rule controls whether the |AccessControlPlugin| will check participant-level permissions for remotely discovered participants. Your local participant (|P1|) checks participant-level permissions when it discovers and authenticates a remote participant (|P2|). When :xmltag:`enable_join_access_control` = :xmlval:`TRUE`, |P1| will check whether |P2| has permission to join the |SecDomain|. In other words, |P1| will check whether |P2| has an :xmltag:`allow_rule` that includes this |DOMAIN| in its |PermissionsDoc| (as specified with the :xmltag:`domains` tag). When :xmltag:`enable_join_access_control` = :xmlval:`FALSE`, |P1| skips this check.

In turn, :xmltag:`enable_read_access_control`, and :xmltag:`enable_write_access_control` Governance rules control whether the |AccessControlPlugin| will check endpoint-level permissions for both locally created and remotely discovered |EPs|. When :xmltag:`enable_read_access_control` = :xmlval:`TRUE` for a given |TOPIC| (*T*), |P1| will enforce permissions on locally created |DRs| of |TOPIC| *T*. Also, |P1| will check whether |P2| |DRs| have permission to subscribe to |TOPIC| *T*. In other words, when :xmltag:`enable_read_access_control` = :xmlval:`TRUE` , |P1| will check:

#. Whether |P1| has an :xmltag:`allow_rule` that includes permissions to subscribe to |TOPIC| *T* (as specified with the subscribe tag). This check takes place upon the creation of a |DR| for |TOPIC| *T*.
#. Whether |P2| has an :xmltag:`allow_rule` that includes permissions to subscribe to |TOPIC| *T* (as specified with the subscribe tag). This check takes place upon the discovery of a |DR| for |TOPIC| *T* in |P2|.

The same logic applies to :xmltag:`enable_write_access_control` and |DWs|.

When :xmltag:`allow_unauthenticated_participants` = :xmlval:`TRUE`, unsecure |DPs| will be allowed to join the |DOMAIN|. Since unsecure |DPs| do not load the |RTI_SP_PRODUCT|, participant-level permissions and endpoint-level permissions for unsecure participants cannot be verified.

Continuing with our previous example, a remote unsecure participant (|P3|) will not load the |RTI_SP_PRODUCT|; therefore, it cannot be bound to a Permissions or |GovernanceDoc|. From |P1|'s perspective, this is similar to having a |PermissionsDoc| that denies permissions for publishing/subscribing to any secure |TOPIC| (but not for joining the |DOMAIN|). As a result, |P3| has permission to join any |SecDomain| that sets :xmltag:`allow_unauthenticated_participants` = :xmlval:`TRUE`. However, |P3| is only allowed to subscribe to |TOPICs| that do not enforce read access control (:xmltag:`enable_read_access_control` = :xmlval:`FALSE`) and is only allowed to publish |TOPICs| that do not enforce write access control (:xmltag:`enable_write_access_control` = :xmlval:`FALSE`). Please note that if :xmltag:`allow_unauthenticated_participants` = :xmlval:`FALSE` for this domain, communication ends when |P1| fails to authenticate |P3|; neither endpoint discovery nor Permissions checks happen in this case.

To summarize: 
  * When :xmltag:`enable_read_access_control` = :xmlval:`TRUE`, the |TOPIC| is protected from unauthorized |DRs| (only participants that have permissions to subscribe to that |TOPIC| can subscribe to it).
  * When :xmltag:`enable_read_access_control` = :xmlval:`FALSE`, any |DR| of this |TOPIC| can subscribe to it (provided that the |DP| this |DR| belongs to, succeeds in joining the |SecDomain|).

Therefore, enabling read access control (:xmltag:`enable_read_access_control` = :xmlval:`TRUE`) does not affect secure participants' ability to publish a particular |TOPIC|. However, it does affect the unsecure participants' ability to subscribe to that |TOPIC|, since only secure participants with permissions to subscribe to that |TOPIC| will be allowed to do so.

Also note that :xmltag:`enable_read_access_control` = :xmlval:`TRUE` will enforce checks on both locally created and remotely discovered |DRs|, regardless of the value of :xmltag:`enable_join_access_control`. The same logic applies to :xmltag:`enable_write_access_control` and |DWs|.

Access Control and Unauthenticated Participants
-----------------------------------------------

The following matrix shows the security implications of the combinations of :xmltag:`allow_unauthenticated_participants` and :xmltag:`enable_join_access_control`. As described in :ref:`p2_core/authentication:allow_unauthenticated_participants (domain_rule)`, :xmltag:`allow_unauthenticated_participants` determines whether participants failing to authenticate will be allowed to communicate in the system, whereas :xmltag:`enable_join_access_control` determines whether the participant-level permissions of successfully authenticated remote participants will be checked. In other words, :xmltag:`allow_unauthenticated_participants` deals with the result of the authentication process (performed right after the participant discovery phase); :xmltag:`enable_join_access_control` deals with the result of a participant-level permissions check (performed right after the remote participant is successfully authenticated). Also note that the participant-level permissions check does not apply to allowed unauthenticated remote participants (i.e., unauthenticated remote participants that are allowed in the |DOMAIN| because :xmltag:`allow_unauthenticated_participants` = :xmlval:`TRUE`).

.. list-table:: Security Implications of :xmltag:`allow_unauthenticated_participants` and :xmltag:`enable_join_access_control`
  :name: Security Implications of allow_unauthenticated_participants and enable_join_access_control
  :widths: 15 15 70
  :header-rows: 1
  :class: longtable

  * - :xmltag:`allow_unauthenticated_participants`
    - :xmltag:`enable_join_access_control`
    - Security Implications

  * - :xmlval:`FALSE`
    - :xmlval:`FALSE`
    - Participants failing to authenticate (including unsecure participants) cannot join the |SecDomain|. Once a remote secure participant successfully authenticates, the local participant trusts it to communicate in the |DOMAIN| and its permissions are not checked. 

      Note that the Authentication Plugin always checks whether the local secure participant has permissions to join the |DOMAIN|, regardless of :xmltag:`enable_join_access_control`.

  * - :xmlval:`FALSE`
    - :xmlval:`TRUE`
    - Participants failing to authenticate (including unsecure participants) cannot join the |SecDomain|. 

      When a remote secure participant successfully authenticates, its permissions to joining the |DOMAIN| are locally checked. The remote participant will only be allowed in the |DOMAIN| if it has the right permissions.

  * - :xmlval:`TRUE`
    - :xmlval:`FALSE`
    - Participants failing to authenticate (including unsecure participants) can join the |SecDomain|. However, they can only publish to |TOPICs| that are not protected against unauthorized |DWs| and can only subscribe to |TOPICs| that are not protected against unauthorized |DRs|.

  * - :xmlval:`TRUE`
    - :xmlval:`TRUE`
    - Participants failing to authenticate (including unsecure participants) can join the |SecDomain|. However, they can only publish to |TOPICs| that are not protected against unauthorized |DWs| and can only subscribe to |TOPICs| that are not protected against unauthorized |DRs|.

      When a remote secure participant successfully authenticates, its permissions to joining the |DOMAIN| are locally checked. The remote participant will only be allowed in the |DOMAIN| if it has the right participant-level permissions.

DataWriters Acting as a Proxy for other DataWriters
---------------------------------------------------

A |DW| acts as a proxy for other |DWs| when it sends samples whose
:link_connext_dds_api_cpp2:`SampleInfo::original_publication_virtual_guid<classdds_1_1sub_1_1SampleInfo.html>`
(which corresponds to
:link_connext_dds_api_cpp2:`WriteParams::identity.writer_guid<classrti_1_1pub_1_1WriteParams.html>`)
or
:link_connext_dds_api_cpp2:`SampleInfo::source_guid<classdds_1_1sub_1_1SampleInfo.html>`
(which corresponds to :link_connext_dds_api_cpp2:`WriteParams::source_guid<classrti_1_1pub_1_1WriteParams.html>`)
correspond to a different |DP| from the one in
:link_connext_dds_api_cpp2:`SampleInfo::publication_handle<classdds_1_1sub_1_1SampleInfo.html>`.
Many |CONNEXT| features rely on the ability to act as a proxy. Some examples:

* With
  :link_connext_dds_pro_um:`Collaborative DataWriters <#users_manual/CollaborativeDataWriters.htm>`,
  you can provide a virtual identity to the samples you write using the
  :link_connext_dds_pro_um:`write_w_params <#users_manual/Writing_Data.htm>` API.
* :link_connext_dds_pro_um:`Durable Writer History <#users_manual/Durable_Writer_History.htm>`
  (including :link_connext_dds_pro_um:`Persistence Service <#users_manual/PartPersistence.htm>`)
  uses the virtual identity to identify samples that are stored in the
  persistence database. This allows the service to provide these samples to
  |DRs| on behalf of |DWs| that may no longer be active.
* |ROUTINGSERVICE| can be configured to propagate the virtual identity of
  samples when routing data between different DDS domains using the
  :link_services_routing_service:`publish_with_original_timestamp <configuration.html#tableroutetag>`
  option in a route.

Outside of these features, it may not be desirable to allow a |DW| to act as a
proxy. Depending on how the destination |DR| interprets these alternative
GUIDs, a malicious |DW| can send a message that appears to come from a
different |DW|. If the |DR| has not set
:link_connext_dds_pro_um:`dds.data_reader.state.filter_redundant_samples <#users_manual/How_To_Configure_a_DataReader_for_Durabl.htm>`
to 0, then the malicious |DW| can prevent the |DR| from receiving future
samples from a legitimate |DW|.

This potential vulnerability is the reason for the |PermissionsDoc| tag
:xmltag:`proxy`. This tag may appear inside an allow or deny rule, at the same
level as :xmltag:`publish` or :xmltag:`subscribe`, and its contents are similar
to those of a :xmltag:`publish` or :xmltag:`subscribe` tag. See
:ref:`p2_core/elements_dds_secure_system:Example Permissions Document (XML)`
for an example.

The |SP_BUILTIN| applies the :xmltag:`proxy` as follows:

* Being allowed to publish is a prerequisite to being allowed to proxy. A |DW|
  that is not allowed to publish will not be allowed to join the system, even
  if it is allowed to proxy.
* The :xmltag:`proxy` rule is enforced both when receiving samples from remote
  |DWs| and when writing samples using a local |DW|. If the remote |DW| is not
  allowed to proxy, and the sample's ``original_publication_virtual_guid`` or
  ``source_guid`` is different from the ``publication_handle``, then the |DR|
  will drop the sample. If the local |DW| is in the same situation, then
  ``write_w_params`` will return DDS_RETCODE_NOT_ALLOWED_BY_SECURITY.
* If there are multiple applicable :xmltag:`proxy` rules in a grant, the first
  one that appears is the one that takes effect. So for a given |DW|, the first
  applicable :xmltag:`proxy` rule and the first applicable :xmltag:`publish`
  rule are the rules that take effect. For example, suppose the following grant
  applies to a |DW| of topic "Foo":

  .. code-block:: xml

        <deny_rule>
            <domains>
                <id_range>
                    <min>0</min>
                </id_range>
            </domains>
            <proxy>
                <topics>
                    <topic>*Foo*</topic>
                </topics>
            </proxy>
        </deny_rule>
        <allow_rule>
            <domains>
                <id_range>
                    <min>0</min>
                </id_range>
            </domains>
            <publish>
                <topics>
                    <topic>*Foo*</topic>
                </topics>
            </publish>
            <proxy>
                <topics>
                    <topic>*Fo*</topic>
                </topics>
            </proxy>
        </allow_rule>
        <default>DENY</default>

  Even though the :xmltag:`publish` criteria appears alongside an applicable
  :xmltag:`proxy` criteria under the same :xmltag:`allow_rule`, that
  :xmltag:`proxy` criteria does not take effect. The one that takes effect is
  the first one, which is under a :xmltag:`deny_rule`. So this |DW| is allowed
  to publish but not proxy.
* If there is no applicable :xmltag:`proxy` rule in a grant, then the
  :ref:`p2_core/access_control:enforce_proxy_permissions` |GovernanceDoc|
  setting determines the behavior.


Properties for Configuring Access Control
=========================================

:numref:`DDS Security Properties for Configuring Access Control` lists
the properties that you can set to configure Access Control. These properties
are configured through the |DP|'s PROPERTY QosPolicy (see
:ref:`section-sp-properties`).

.. list-table:: DDS Security Properties for Configuring Access Control
  :name: DDS Security Properties for Configuring Access Control
  :widths: 40 60
  :header-rows: 1
  :class: longtable

  * - Property Name
    - Property Value Description

  * - :property:`dds.sec.access.permissions_ca`
    - :required:`Required`

      This Permissions Certificate Authority is used for signing access control governance and permissions XML files and verifying the signatures of those files. The Permissions Certificate Authority file may or may not be the same as the Identity Certificate Authority file.

      Two participants that want to securely communicate with each other must use the same Permissions Certificate Authority.

      The document should be in PEM format. You may specify either the file name or the document contents. If specifying the file name, the property value must have the prefix :value:`file:` (no space after the colon), followed by the fully qualified path and name of the file. If specifying the contents of the document, the property value must have the prefix :value:`data:,` (no space after the comma), followed by the contents inside the document. For example:

      .. code-block:: none
        :class: break-lines-anywhere

        "data:,-----BEGIN CERTIFICATE-----\nabcdef\n-----END CERTIFICATE-----"

      Note that the two ``\n`` characters are required.

      :type:`String`.

      Default: :value:`NULL`

  * - :property:`dds.sec.access.governance`
    - :required:`Required`

      The signed document that specifies the level of security required per |DOMAIN| and per |TOPIC| (see :ref:`p2_core/access_control:Governance Document`). The Permissions CA (:property:`dds.sec.access.permissions_ca`) must sign the |GovernanceDoc| using S/MIME version 3.2 format (which corresponds to the mime-type application/pkcs7-signature).

      You may specify either the file name or the document contents. If specifying the file name, the property value must have the prefix :value:`file:` (no space after the colon), followed by the fully qualified path and name of the file. If specifying the contents of the document, the property value must have the prefix :value:`data:,` (no space after the comma), followed by the contents inside the document. For example:

      .. code-block:: none
        :class: break-lines-anywhere

        "data:,MIME-Version: 1.0\nContent-Type:...boundary=\"---7236--\"\n\n"

      Note that for signed XML files, all whitespace characters (' ', '\r', '\n') are significant, and all quotes must be escaped by a backslash. The safest way to get the correct property value is to call the ``fread()`` function on the file and use the resulting buffer as the property value.

      :type:`String`.

      Default: :value:`NULL`

  * - :property:`dds.sec.access.permissions`
    - :required:`Required`

      The signed document that specifies the access control permissions per |DOMAIN| and per |TOPIC| (see :ref:`p2_core/access_control:Permissions Document`) for individual |DPs| identified by subject names. The Permissions CA (:property:`dds.sec.access.permissions_ca`) must sign the |PermissionsDoc| using S/MIME version 3.2 format (which corresponds to the mime-type application/pkcs7-signature).

      The :xmltag:`subject_name` element identifies the |DP| to which the permissions apply. Each subject name can only appear in a single :xmltag:`permissions` section within the XML |PermissionsDoc|.
      The contents of the :xmltag:`subject_name` element should be the X.509 subject name for the |DP|.
      The format of the subject name should conform to `IETF RFC 4514 "Lightweight Directory Access Protocol (LDAP): String Representation of Distinguished Names <https://datatracker.ietf.org/doc/html/rfc4514>`_.
      Specifically, the `=` character should separate an attribute's name from its value, and the `,` character should separate attributes from each other.
      See :link_connext_dds_secure_gsg:`Hands-on 4 <cpp11/hands_on_4.html#updating-permissions-files-with-new-credentials>` in the |SP_GSG| for an example openssl command to extract a correctly-formatted subject name.
      A :xmltag:`permissions` section with a subject name that does not match the subject name given in the corresponding |IdentityCert| will be ignored.

      The signed |PermissionsDoc| only supports validity dates between
      1970-01-01T00:00:00Z and 2106-02-07T06:28:15Z. Any dates before
      1970-01-01T00:00:00Z will result in an error, and any dates after
      2106-02-07T06:28:15Z will be treated as 2106-02-07T06:28:15Z.
      Currently, |CONNEXT| behavior is undefined if the system time is after
      7 February 2106, 06:28:15 UTC.

      You may specify either the file name or the document contents. If specifying the file name, the property value must have the prefix "file:" (no space after the colon), followed by the fully qualified path and name of the file. If specifying the contents of the document, the property value must have the prefix "data:," (no space after the comma), followed by the contents inside the document. For example:

      .. code-block:: none
        :class: break-lines-anywhere

        "data:,MIME-Version: 1.0\nContent-Type:...boundary=\"---7236--\"\n\n"

      Note that for signed XML files, all whitespace characters (' ', '\r', '\n') are significant, and all quotes must be escaped by a backslash. The safest way to get the correct property value is to call the ``fread()`` function on the file and use the resulting buffer as the property value.

      :type:`String`.

      Default: :value:`NULL`

  * - :property:`dds.sec.access.rtps_psk_protection_kind`
    - :required:`Optional`

      It specifies how to protect messages when using
      :ref:`p3_advanced/pre-shared_key:|PSKProtection|`: don't protect them,
      protect only their integrity, or protect both their integrity and
      confidentiality.

      This property can only be used in
      :ref:`p3_advanced/lightweight_security:The |LIGHT_SP_BUILTIN_HEADING|`. The
      |SP_BUILTIN| do not support this property. Instead, use the
      :xmltag:`rtps_psk_protection_kind` domain rule from the |GovernanceDoc|.
      For more information, read
      :ref:`p2_core/cryptography:rtps_psk_protection_kind (domain_rule)`.

      :type:`Enum`: :value:`NONE` (do not protect),
      :value:`SIGN` (protect the integrity), :value:`ENCRYPT` (protect the
      integrity and confidentiality).

      Default: :value:`ENCRYPT`


.. list-table:: |RTI_SP_PRODUCT| Properties for Configuring Access Control
  :name: |RTI_SP_PRODUCT_HEADING| Properties for Configuring Access Control
  :widths: 40 60
  :header-rows: 1
  :class: longtable

  * - Property Name (prefix with :property:`com.rti.serv.secure.`) [#fPrefix]_
    - Property Value Description

  * - :property:`access_control.alternative_permissions_authority_files` (deprecated)
    - :required:`Optional`

      Note:
        This property is deprecated and has been replaced by
        :property:`access_control.alternative_permissions_cas`.

      :type:`String`.

      Default: :value:`NULL`

  * - :property:`access_control.alternative_permissions_cas`
    - :required:`Optional`

      List of concatenated alternative Permissions CA certificates in PEM
      format. You can prefix this list with :value:`data:,` and specify it
      directly in the property value, or you can prefix it with :value:`file:`
      and specify a file name from which to read the list of certificates.
      If no prefix is given, :value:`file:` is assumed. See the
      :ref:`"Note regarding document format"
      <note_regarding_document_format>` for details.

      If verification of either the |PermissionsDoc| or the |GovernanceDoc|
      fails with the main certificate (:property:`dds.sec.access.permissions_ca`),
      verification will be retried with all of the corresponding alternative
      certificates. If none of the alternative certificates can be used to
      verify the file, the verification process will fail. If any of the
      alternative certificate files fail to be loaded, the |DP| creation will
      fail.

      :type:`String`.

      Default: :value:`NULL`

  * - :property:`access_control.use_530_permissions_rules_precedence`
    - :required:`Optional`

      How to deal with conflicting allow/deny rules in a |PermissionsDoc| when checking for a |TOPIC|, |DW|, or |DR|'s permission to exist. 

      * If :value:`TRUE`: the last rule will take precedence, which is consistent with the behavior in |CONNEXT| 5.3.0 and earlier versions.
      * If :value:`FALSE`: the first rule will take precedence, which is consistent with the intended behavior of the |SEC_SPEC| (see :ref:`p2_core/elements_dds_secure_system:How the Permissions are Interpreted`).

      :type:`Boolean`.

      Default: :value:`FALSE`

  * - :property:`access_control.use_530_logging_protection`
    - :required:`Optional`

      How to set the value of :xmltag:`metadata_protection_kind` for the
      |LoggingT|.

      * If :value:`TRUE`: the value will be :xmlval:`NONE`, which is consistent with |CONNEXT| 5.3.0 behavior.
      * If :value:`FALSE`: the value will be SIGN, which is consistent with the behavior of the |SEC_SPEC|.

      :type:`Boolean`.

      Default: :value:`FALSE`

  * - :property:`access_control.use_530_partitions`
    - :required:`Optional`

      How to determine a match between a |DW| or |DR|'s partitions and an "allowed partitions" condition in a |PermissionsDoc|.

      * If :value:`TRUE`: an |Entity| is matched if it has at least one partition in the condition; this is consistent with the behavior in |CONNEXT| 5.3.0 and earlier versions.
      * If :value:`FALSE`: an |Entity| is matched only if all of its partitions are in the condition; this is consistent with the behavior of the |SEC_SPEC| (see :ref:`p2_core/access_control:Partitions`).

      For example, if a |DW| has partitions [A, B], and a |PermissionsDoc| allows partitions [B, C], then when :property:`use_530_partitions` = :value:`TRUE`, the |DW| is allowed because B is allowed. When :property:`use_530_partitions` = :value:`FALSE`, the |DW| is not allowed because A is not allowed.

      :type:`Boolean`.

      Default: :value:`FALSE`

  * - :property:`access_control.use_610_permissions_rules_precedence`
    - :required:`Optional`

      How to deal with conflicting allow/deny rules in a |PermissionsDoc| when checking for a |DP|'s permission to exist. 

      * If :value:`false`: the first rule will take precedence, which is consistent with the behavior of the |SEC_SPEC| (see :ref:`p2_core/elements_dds_secure_system:How the Permissions are Interpreted`).
      * If :value:`true`: the last rule will take precedence, which is consistent with the behavior in |CONNEXT| 6.1.0 and earlier versions.
      * If :value:`auto`: for the local |DP|, the first rule will take precedence. For discovered remote |DPs|, the last rule will take precedence only if the discovered |DP| is |CONNEXT| 6.1.0 or earlier.

      :type:`Enum`: :value:`false`, :value:`true` :value:`auto`

      Default: :value:`auto`


.. [#fPrefix] Assuming you used :value:`com.rti.serv.secure` as the alias to load the plugin. If not, change the prefix to match the string used with :property:`com.rti.serv.load_plugins`, followed by the :value:`.` character.
